Port Subject38's unformat_profile as well as fix a small thing in clan/festo.
This commit is contained in:
parent
3a724c24d4
commit
488216c343
@ -1651,7 +1651,7 @@ class JubeatClan(
|
|||||||
newprofile.replace_int_array('title_list', 160, item.child_value('title_list'))
|
newprofile.replace_int_array('title_list', 160, item.child_value('title_list'))
|
||||||
newprofile.replace_int_array('parts_list', 160, item.child_value('parts_list'))
|
newprofile.replace_int_array('parts_list', 160, item.child_value('parts_list'))
|
||||||
newprofile.replace_int_array('emblem_list', 96, item.child_value('emblem_list'))
|
newprofile.replace_int_array('emblem_list', 96, item.child_value('emblem_list'))
|
||||||
newprofile.replace_int_array('commu_list', 96, item.child_value('commu_list'))
|
newprofile.replace_int_array('commu_list', 16, item.child_value('commu_list'))
|
||||||
|
|
||||||
newitem = item.child('new')
|
newitem = item.child('new')
|
||||||
if newitem is not None:
|
if newitem is not None:
|
||||||
|
@ -1404,7 +1404,7 @@ class JubeatFesto(
|
|||||||
self.game, self.music_version, userid, entry.get_int('whim', -1), timelimit=start_time
|
self.game, self.music_version, userid, entry.get_int('whim', -1), timelimit=start_time
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: Are these still the right state constants?
|
# Full combo challenge and whim challenge
|
||||||
fc_challenge = Node.void('fc_challenge')
|
fc_challenge = Node.void('fc_challenge')
|
||||||
player.add_child(fc_challenge)
|
player.add_child(fc_challenge)
|
||||||
today = Node.void('today')
|
today = Node.void('today')
|
||||||
@ -1641,3 +1641,391 @@ class JubeatFesto(
|
|||||||
# TODO: travel
|
# TODO: travel
|
||||||
|
|
||||||
return root
|
return root
|
||||||
|
|
||||||
|
def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile:
|
||||||
|
newprofile = oldprofile.clone()
|
||||||
|
newprofile.replace_bool('saved', True)
|
||||||
|
data = request.child('data')
|
||||||
|
|
||||||
|
# Grab system information
|
||||||
|
sysinfo = data.child('info')
|
||||||
|
|
||||||
|
# Grab player information
|
||||||
|
player = data.child('player')
|
||||||
|
|
||||||
|
# Grab result information
|
||||||
|
result = data.child('result')
|
||||||
|
|
||||||
|
# Grab last information. Lots of this will be filled in while grabbing scores
|
||||||
|
last = newprofile.get_dict('last')
|
||||||
|
if sysinfo is not None:
|
||||||
|
last.replace_int('play_time', sysinfo.child_value('time_gameend'))
|
||||||
|
last.replace_str('shopname', sysinfo.child_value('shopname'))
|
||||||
|
last.replace_str('areaname', sysinfo.child_value('areaname'))
|
||||||
|
|
||||||
|
# Grab player info for echoing back
|
||||||
|
info = player.child('info')
|
||||||
|
if info is not None:
|
||||||
|
newprofile.replace_int('tune_cnt', info.child_value('tune_cnt'))
|
||||||
|
newprofile.replace_int('save_cnt', info.child_value('save_cnt'))
|
||||||
|
newprofile.replace_int('saved_cnt', info.child_value('saved_cnt'))
|
||||||
|
newprofile.replace_int('fc_cnt', info.child_value('fc_cnt'))
|
||||||
|
newprofile.replace_int('ex_cnt', info.child_value('ex_cnt'))
|
||||||
|
newprofile.replace_int('clear_cnt', info.child_value('clear_cnt'))
|
||||||
|
newprofile.replace_int('match_cnt', info.child_value('match_cnt'))
|
||||||
|
newprofile.replace_int('beat_cnt', info.child_value('beat_cnt'))
|
||||||
|
newprofile.replace_int('mynews_cnt', info.child_value('mynews_cnt'))
|
||||||
|
|
||||||
|
newprofile.replace_int('bonus_tune_points', info.child_value('bonus_tune_points'))
|
||||||
|
newprofile.replace_bool('is_bonus_tune_played', info.child_value('is_bonus_tune_played'))
|
||||||
|
|
||||||
|
# Grab last settings
|
||||||
|
lastnode = player.child('last')
|
||||||
|
if lastnode is not None:
|
||||||
|
last.replace_int('expert_option', lastnode.child_value('expert_option'))
|
||||||
|
last.replace_int('sort', lastnode.child_value('sort'))
|
||||||
|
last.replace_int('category', lastnode.child_value('category'))
|
||||||
|
|
||||||
|
settings = lastnode.child('settings')
|
||||||
|
if settings is not None:
|
||||||
|
last.replace_int('matching', settings.child_value('matching'))
|
||||||
|
last.replace_int('hazard', settings.child_value('hazard'))
|
||||||
|
last.replace_int('hard', settings.child_value('hard'))
|
||||||
|
last.replace_int('marker', settings.child_value('marker'))
|
||||||
|
last.replace_int('theme', settings.child_value('theme'))
|
||||||
|
last.replace_int('title', settings.child_value('title'))
|
||||||
|
last.replace_int('parts', settings.child_value('parts'))
|
||||||
|
last.replace_int('rank_sort', settings.child_value('rank_sort'))
|
||||||
|
last.replace_int('combo_disp', settings.child_value('combo_disp'))
|
||||||
|
last.replace_int_array('emblem', 5, settings.child_value('emblem'))
|
||||||
|
|
||||||
|
# Grab unlock progress
|
||||||
|
item = player.child('item')
|
||||||
|
if item is not None:
|
||||||
|
newprofile.replace_int_array('music_list', 64, item.child_value('music_list'))
|
||||||
|
newprofile.replace_int_array('secret_list', 64, item.child_value('secret_list'))
|
||||||
|
newprofile.replace_int_array('theme_list', 16, item.child_value('theme_list'))
|
||||||
|
newprofile.replace_int_array('marker_list', 16, item.child_value('marker_list'))
|
||||||
|
newprofile.replace_int_array('title_list', 160, item.child_value('title_list'))
|
||||||
|
newprofile.replace_int_array('parts_list', 160, item.child_value('parts_list'))
|
||||||
|
newprofile.replace_int_array('emblem_list', 96, item.child_value('emblem_list'))
|
||||||
|
newprofile.replace_int_array('commu_list', 16, item.child_value('commu_list'))
|
||||||
|
|
||||||
|
newitem = item.child('new')
|
||||||
|
if newitem is not None:
|
||||||
|
newprofile.replace_int_array('secret_list_new', 64, newitem.child_value('secret_list'))
|
||||||
|
newprofile.replace_int_array('theme_list_new', 16, newitem.child_value('theme_list'))
|
||||||
|
newprofile.replace_int_array('marker_list_new', 16, newitem.child_value('marker_list'))
|
||||||
|
|
||||||
|
# Grab categories stuff
|
||||||
|
fill_in_category = player.child('fill_in_category')
|
||||||
|
fill_in_category_normal = fill_in_category.child('normal')
|
||||||
|
if fill_in_category is not None:
|
||||||
|
newprofile.replace_int_array('normal_no_gray_flag_list', 16, fill_in_category_normal.child_value('no_gray_flag_list'))
|
||||||
|
newprofile.replace_int_array('normal_all_yellow_flag_list', 16, fill_in_category_normal.child_value('all_yellow_flag_list'))
|
||||||
|
newprofile.replace_int_array('normal_full_combo_flag_list', 16, fill_in_category_normal.child_value('full_combo_flag_list'))
|
||||||
|
newprofile.replace_int_array('normal_excellent_flag_list', 16, fill_in_category_normal.child_value('excellent_flag_list'))
|
||||||
|
fill_in_category_hard = fill_in_category.child('hard')
|
||||||
|
if fill_in_category is not None:
|
||||||
|
newprofile.replace_int_array('hard_no_gray_flag_list', 16, fill_in_category_hard.child_value('no_gray_flag_list'))
|
||||||
|
newprofile.replace_int_array('hard_all_yellow_flag_list', 16, fill_in_category_hard.child_value('all_yellow_flag_list'))
|
||||||
|
newprofile.replace_int_array('hard_full_combo_flag_list', 16, fill_in_category_hard.child_value('full_combo_flag_list'))
|
||||||
|
newprofile.replace_int_array('hard_excellent_flag_list', 16, fill_in_category_hard.child_value('excellent_flag_list'))
|
||||||
|
|
||||||
|
# jbox stuff
|
||||||
|
jbox = player.child('jbox')
|
||||||
|
jboxdict = newprofile.get_dict('jbox')
|
||||||
|
if jbox is not None:
|
||||||
|
jboxdict.replace_int('point', jbox.child_value('point'))
|
||||||
|
emblemtype = jbox.child_value('emblem/type')
|
||||||
|
index = jbox.child_value('emblem/index')
|
||||||
|
if emblemtype == self.JBOX_EMBLEM_NORMAL:
|
||||||
|
jboxdict.replace_int('normal_index', index)
|
||||||
|
elif emblemtype == self.JBOX_EMBLEM_PREMIUM:
|
||||||
|
jboxdict.replace_int('premium_index', index)
|
||||||
|
newprofile.replace_dict('jbox', jboxdict)
|
||||||
|
|
||||||
|
# Drop list
|
||||||
|
drop_list = player.child('drop_list')
|
||||||
|
if drop_list is not None:
|
||||||
|
for drop in drop_list.children:
|
||||||
|
try:
|
||||||
|
dropid = int(drop.attribute('id'))
|
||||||
|
except TypeError:
|
||||||
|
# Unrecognized drop
|
||||||
|
continue
|
||||||
|
exp = drop.child_value('exp')
|
||||||
|
flag = drop.child_value('flag')
|
||||||
|
items: Dict[int, int] = {}
|
||||||
|
|
||||||
|
item_list = drop.child('item_list')
|
||||||
|
if item_list is not None:
|
||||||
|
for item in item_list.children:
|
||||||
|
try:
|
||||||
|
itemid = int(item.attribute('id'))
|
||||||
|
except TypeError:
|
||||||
|
# Unrecognized item
|
||||||
|
continue
|
||||||
|
items[itemid] = item.child_value('num')
|
||||||
|
|
||||||
|
olddrop = self.data.local.user.get_achievement(
|
||||||
|
self.game,
|
||||||
|
self.version,
|
||||||
|
userid,
|
||||||
|
dropid,
|
||||||
|
'drop',
|
||||||
|
)
|
||||||
|
|
||||||
|
if olddrop is None:
|
||||||
|
# Create a new event structure for this
|
||||||
|
olddrop = ValidatedDict()
|
||||||
|
|
||||||
|
olddrop.replace_int('exp', exp)
|
||||||
|
olddrop.replace_int('flag', flag)
|
||||||
|
for itemid, num in items.items():
|
||||||
|
olddrop.replace_int(f'item_{itemid}', num)
|
||||||
|
|
||||||
|
# Save it as an achievement
|
||||||
|
self.data.local.user.put_achievement(
|
||||||
|
self.game,
|
||||||
|
self.version,
|
||||||
|
userid,
|
||||||
|
dropid,
|
||||||
|
'drop',
|
||||||
|
olddrop,
|
||||||
|
)
|
||||||
|
|
||||||
|
# event stuff
|
||||||
|
newprofile.replace_int('event_flag', player.child_value('event_flag'))
|
||||||
|
event_info = player.child('event_info')
|
||||||
|
if event_info is not None:
|
||||||
|
for child in event_info.children:
|
||||||
|
try:
|
||||||
|
eventid = int(child.attribute('type'))
|
||||||
|
except TypeError:
|
||||||
|
# Event is empty
|
||||||
|
continue
|
||||||
|
is_completed = child.child_value('is_completed')
|
||||||
|
|
||||||
|
# Figure out if we should update the rating/scores or not
|
||||||
|
oldevent = self.data.local.user.get_achievement(
|
||||||
|
self.game,
|
||||||
|
self.version,
|
||||||
|
userid,
|
||||||
|
eventid,
|
||||||
|
'event',
|
||||||
|
)
|
||||||
|
|
||||||
|
if oldevent is None:
|
||||||
|
# Create a new event structure for this
|
||||||
|
oldevent = ValidatedDict()
|
||||||
|
|
||||||
|
oldevent.replace_bool('is_completed', is_completed)
|
||||||
|
|
||||||
|
# Save it as an achievement
|
||||||
|
self.data.local.user.put_achievement(
|
||||||
|
self.game,
|
||||||
|
self.version,
|
||||||
|
userid,
|
||||||
|
eventid,
|
||||||
|
'event',
|
||||||
|
oldevent,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Still don't know what this is for lol
|
||||||
|
newprofile.replace_int('navi_flag', player.child_value('navi/flag'))
|
||||||
|
|
||||||
|
# Grab scores and save those
|
||||||
|
if result is not None:
|
||||||
|
for tune in result.children:
|
||||||
|
if tune.name != 'tune':
|
||||||
|
continue
|
||||||
|
result = tune.child('player')
|
||||||
|
songid = tune.child_value('music')
|
||||||
|
timestamp = tune.child_value('timestamp') / 1000
|
||||||
|
chart = self.game_to_db_chart(int(result.child('score').attribute('seq')), bool(result.child_value('is_hard_mode')))
|
||||||
|
points = result.child_value('score')
|
||||||
|
flags = int(result.child('score').attribute('clear'))
|
||||||
|
combo = int(result.child('score').attribute('combo'))
|
||||||
|
ghost = result.child_value('mbar')
|
||||||
|
music_rate = result.child_value('music_rate')
|
||||||
|
|
||||||
|
stats = {
|
||||||
|
'perfect': result.child_value('nr_perfect'),
|
||||||
|
'great': result.child_value('nr_great'),
|
||||||
|
'good': result.child_value('nr_good'),
|
||||||
|
'poor': result.child_value('nr_poor'),
|
||||||
|
'miss': result.child_value('nr_miss'),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Miscelaneous last data for echoing to profile get
|
||||||
|
last.replace_int('music_id', songid)
|
||||||
|
last.replace_int('seq_id', int(result.child('score').attribute('seq')))
|
||||||
|
|
||||||
|
mapping = {
|
||||||
|
self.GAME_FLAG_BIT_CLEARED: self.PLAY_MEDAL_CLEARED,
|
||||||
|
self.GAME_FLAG_BIT_FULL_COMBO: self.PLAY_MEDAL_FULL_COMBO,
|
||||||
|
self.GAME_FLAG_BIT_EXCELLENT: self.PLAY_MEDAL_EXCELLENT,
|
||||||
|
self.GAME_FLAG_BIT_NEARLY_FULL_COMBO: self.PLAY_MEDAL_NEARLY_FULL_COMBO,
|
||||||
|
self.GAME_FLAG_BIT_NEARLY_EXCELLENT: self.PLAY_MEDAL_NEARLY_EXCELLENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Figure out the highest medal based on bits passed in
|
||||||
|
medal = self.PLAY_MEDAL_FAILED
|
||||||
|
for bit in mapping:
|
||||||
|
if flags & bit > 0:
|
||||||
|
medal = max(medal, mapping[bit])
|
||||||
|
|
||||||
|
self.update_score(userid, timestamp, songid, chart, points, medal,
|
||||||
|
combo, ghost, stats, music_rate)
|
||||||
|
|
||||||
|
# Born stuff
|
||||||
|
born = player.child('born')
|
||||||
|
if born is not None:
|
||||||
|
newprofile.replace_int('born_status', born.child_value('status'))
|
||||||
|
newprofile.replace_int('born_year', born.child_value('year'))
|
||||||
|
|
||||||
|
# jubility list sent looks like this
|
||||||
|
# <jubility>
|
||||||
|
# <target_music>
|
||||||
|
# <hot_music_list param="36385">
|
||||||
|
# <music>
|
||||||
|
# <music_id __type="s32">90000130</music_id>
|
||||||
|
# <seq __type="s8">2</seq>
|
||||||
|
# <rate __type="s32">975</rate>
|
||||||
|
# <value __type="s32">1280</value>
|
||||||
|
# <is_hard_mode __type="bool">0</is_hard_mode>
|
||||||
|
# </music>
|
||||||
|
# </hot_music_list>
|
||||||
|
# <other_music_list param="36770">
|
||||||
|
|
||||||
|
# Grab jubility
|
||||||
|
jubility = player.child('jubility')
|
||||||
|
if jubility is not None:
|
||||||
|
target_music = jubility.child('target_music')
|
||||||
|
|
||||||
|
# Pick up jubility stuff
|
||||||
|
hot_music_list = target_music.child('hot_music_list')
|
||||||
|
pick_up_chart = ValidatedDict()
|
||||||
|
for music in hot_music_list.children:
|
||||||
|
music_id = music.child_value('music_id')
|
||||||
|
chart = self.game_to_db_chart(int(music.child_value('seq')), bool(music.child_value('is_hard_mode')))
|
||||||
|
music_rate = float(music.child_value('rate')) / 10
|
||||||
|
value = float(music.child_value('value')) / 10
|
||||||
|
entry = {
|
||||||
|
'music_id': music_id,
|
||||||
|
'seq': chart,
|
||||||
|
'music_rate': music_rate,
|
||||||
|
'value': value,
|
||||||
|
}
|
||||||
|
pick_up_chart.replace_dict(f'{music_id}_{chart}', entry)
|
||||||
|
|
||||||
|
# Save it back
|
||||||
|
newprofile.replace_dict('pick_up_chart', pick_up_chart)
|
||||||
|
newprofile.replace_float('pick_up_jubility', float(hot_music_list.attribute('param')) / 10)
|
||||||
|
|
||||||
|
# Common jubility stuff
|
||||||
|
other_music_list = target_music.child('other_music_list')
|
||||||
|
common_chart = ValidatedDict()
|
||||||
|
for music in other_music_list.children:
|
||||||
|
music_id = music.child_value('music_id')
|
||||||
|
chart = self.game_to_db_chart(int(music.child_value('seq')), bool(music.child_value('is_hard_mode')))
|
||||||
|
music_rate = float(music.child_value('rate')) / 10
|
||||||
|
value = float(music.child_value('value')) / 10
|
||||||
|
entry = {
|
||||||
|
'music_id': music_id,
|
||||||
|
'seq': chart,
|
||||||
|
'music_rate': music_rate,
|
||||||
|
'value': value,
|
||||||
|
}
|
||||||
|
common_chart.replace_dict(f'{music_id}_{chart}', entry)
|
||||||
|
|
||||||
|
# Save it back
|
||||||
|
newprofile.replace_dict('common_chart', common_chart)
|
||||||
|
newprofile.replace_float('common_jubility', float(other_music_list.attribute('param')) / 10)
|
||||||
|
|
||||||
|
# Clan course saving
|
||||||
|
clan_course_list = player.child('course_list')
|
||||||
|
if clan_course_list is not None:
|
||||||
|
for course in clan_course_list.children:
|
||||||
|
if course.name != 'course':
|
||||||
|
continue
|
||||||
|
|
||||||
|
courseid = int(course.attribute('id'))
|
||||||
|
status = course.child_value('status')
|
||||||
|
is_seen = (status & self.COURSE_STATUS_SEEN) != 0
|
||||||
|
is_played = (status & self.COURSE_STATUS_PLAYED) != 0
|
||||||
|
|
||||||
|
# Update seen status and played status
|
||||||
|
oldcourse = self.data.local.user.get_achievement(
|
||||||
|
self.game,
|
||||||
|
self.version,
|
||||||
|
userid,
|
||||||
|
courseid,
|
||||||
|
'course',
|
||||||
|
)
|
||||||
|
|
||||||
|
if oldcourse is None:
|
||||||
|
# Create a new course structure for this
|
||||||
|
oldcourse = ValidatedDict()
|
||||||
|
|
||||||
|
oldcourse.replace_bool('seen', oldcourse.get_bool('seen') or is_seen)
|
||||||
|
oldcourse.replace_bool('played', oldcourse.get_bool('played') or is_played)
|
||||||
|
|
||||||
|
# Save it as an achievement
|
||||||
|
self.data.local.user.put_achievement(
|
||||||
|
self.game,
|
||||||
|
self.version,
|
||||||
|
userid,
|
||||||
|
courseid,
|
||||||
|
'course',
|
||||||
|
oldcourse,
|
||||||
|
)
|
||||||
|
|
||||||
|
# If they played a course, figure out if they cleared it.
|
||||||
|
select_course = player.child('select_course')
|
||||||
|
if select_course is not None:
|
||||||
|
try:
|
||||||
|
courseid = int(select_course.attribute('id'))
|
||||||
|
except Exception:
|
||||||
|
courseid = 0
|
||||||
|
cleared = select_course.child_value('is_cleared')
|
||||||
|
|
||||||
|
if courseid > 0 and cleared:
|
||||||
|
# Update course cleared status
|
||||||
|
oldcourse = self.data.local.user.get_achievement(
|
||||||
|
self.game,
|
||||||
|
self.version,
|
||||||
|
userid,
|
||||||
|
courseid,
|
||||||
|
'course',
|
||||||
|
)
|
||||||
|
|
||||||
|
if oldcourse is None:
|
||||||
|
# Create a new course structure for this
|
||||||
|
oldcourse = ValidatedDict()
|
||||||
|
|
||||||
|
oldcourse.replace_bool('cleared', True)
|
||||||
|
|
||||||
|
# Save it as an achievement
|
||||||
|
self.data.local.user.put_achievement(
|
||||||
|
self.game,
|
||||||
|
self.version,
|
||||||
|
userid,
|
||||||
|
courseid,
|
||||||
|
'course',
|
||||||
|
oldcourse,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Save back last information gleaned from results
|
||||||
|
newprofile.replace_dict('last', last)
|
||||||
|
|
||||||
|
festo_dungeon = player.child('festo_dungeon')
|
||||||
|
if festo_dungeon is not None:
|
||||||
|
newprofile.replace_int('festo_dungeon_phase', festo_dungeon.child_value('phase'))
|
||||||
|
newprofile.replace_int('festo_dungeon_clear_flag', festo_dungeon.child_value('clear_flag'))
|
||||||
|
|
||||||
|
# Keep track of play statistics
|
||||||
|
self.update_play_statistics(userid)
|
||||||
|
|
||||||
|
return newprofile
|
||||||
|
Loading…
Reference in New Issue
Block a user