1216 lines
53 KiB
Python
1216 lines
53 KiB
Python
from typing import Optional, Dict, List, Tuple, Any
|
||
from typing_extensions import Final
|
||
|
||
from bemani.backend.reflec.base import ReflecBeatBase
|
||
from bemani.backend.reflec.limelight import ReflecBeatLimelight
|
||
|
||
from bemani.common import Profile, ValidatedDict, VersionConstants, ID, Time
|
||
from bemani.data import UserID, Achievement
|
||
from bemani.protocol import Node
|
||
|
||
|
||
class ReflecBeatColette(ReflecBeatBase):
|
||
|
||
name: str = "REFLEC BEAT colette"
|
||
version: int = VersionConstants.REFLEC_BEAT_COLETTE
|
||
|
||
# Clear types according to the game
|
||
GAME_CLEAR_TYPE_NO_PLAY: Final[int] = 0
|
||
GAME_CLEAR_TYPE_FAILED: Final[int] = 1
|
||
GAME_CLEAR_TYPE_CLEARED: Final[int] = 2
|
||
GAME_CLEAR_TYPE_ALMOST_COMBO: Final[int] = 3
|
||
GAME_CLEAR_TYPE_FULL_COMBO: Final[int] = 4
|
||
|
||
def previous_version(self) -> Optional[ReflecBeatBase]:
|
||
return ReflecBeatLimelight(self.data, self.config, self.model)
|
||
|
||
@classmethod
|
||
def get_settings(cls) -> Dict[str, Any]:
|
||
"""
|
||
Return all of our front-end modifiably settings.
|
||
"""
|
||
return {
|
||
'bools': [
|
||
{
|
||
'name': 'Force Song Unlock',
|
||
'tip': 'Force unlock all songs.',
|
||
'category': 'game_config',
|
||
'setting': 'force_unlock_songs',
|
||
},
|
||
],
|
||
'ints': [],
|
||
}
|
||
|
||
def __db_to_game_clear_type(self, db_clear_type: int, db_combo_type: int) -> int:
|
||
if db_clear_type == self.CLEAR_TYPE_NO_PLAY:
|
||
return self.GAME_CLEAR_TYPE_NO_PLAY
|
||
if db_clear_type == self.CLEAR_TYPE_FAILED:
|
||
return self.GAME_CLEAR_TYPE_FAILED
|
||
if db_clear_type in [
|
||
self.CLEAR_TYPE_CLEARED,
|
||
self.CLEAR_TYPE_HARD_CLEARED,
|
||
self.CLEAR_TYPE_S_HARD_CLEARED,
|
||
]:
|
||
if db_combo_type == self.COMBO_TYPE_NONE:
|
||
return self.GAME_CLEAR_TYPE_CLEARED
|
||
if db_combo_type == self.COMBO_TYPE_ALMOST_COMBO:
|
||
return self.GAME_CLEAR_TYPE_ALMOST_COMBO
|
||
if db_combo_type in [
|
||
self.COMBO_TYPE_FULL_COMBO,
|
||
self.COMBO_TYPE_FULL_COMBO_ALL_JUST,
|
||
]:
|
||
return self.GAME_CLEAR_TYPE_FULL_COMBO
|
||
raise Exception(f'Invalid db_combo_type {db_combo_type}')
|
||
raise Exception(f'Invalid db_clear_type {db_clear_type}')
|
||
|
||
def __game_to_db_clear_type(self, game_clear_type: int) -> Tuple[int, int]:
|
||
if game_clear_type == self.GAME_CLEAR_TYPE_NO_PLAY:
|
||
return (self.CLEAR_TYPE_NO_PLAY, self.COMBO_TYPE_NONE)
|
||
if game_clear_type == self.GAME_CLEAR_TYPE_FAILED:
|
||
return (self.CLEAR_TYPE_FAILED, self.COMBO_TYPE_NONE)
|
||
if game_clear_type == self.GAME_CLEAR_TYPE_CLEARED:
|
||
return (self.CLEAR_TYPE_CLEARED, self.COMBO_TYPE_NONE)
|
||
if game_clear_type == self.GAME_CLEAR_TYPE_ALMOST_COMBO:
|
||
return (self.CLEAR_TYPE_CLEARED, self.COMBO_TYPE_ALMOST_COMBO)
|
||
if game_clear_type == self.GAME_CLEAR_TYPE_FULL_COMBO:
|
||
return (self.CLEAR_TYPE_CLEARED, self.COMBO_TYPE_FULL_COMBO)
|
||
|
||
raise Exception(f'Invalid game_clear_type {game_clear_type}')
|
||
|
||
def handle_pcb_error_request(self, request: Node) -> Node:
|
||
return Node.void('pcb')
|
||
|
||
def handle_pcb_uptime_update_request(self, request: Node) -> Node:
|
||
return Node.void('pcb')
|
||
|
||
def handle_pcb_boot_request(self, request: Node) -> Node:
|
||
shop_id = ID.parse_machine_id(request.child_value('lid'))
|
||
machine = self.get_machine_by_id(shop_id)
|
||
if machine is not None:
|
||
machine_name = machine.name
|
||
close = machine.data.get_bool('close')
|
||
hour = machine.data.get_int('hour')
|
||
minute = machine.data.get_int('minute')
|
||
else:
|
||
machine_name = ''
|
||
close = False
|
||
hour = 0
|
||
minute = 0
|
||
|
||
root = Node.void('pcb')
|
||
sinfo = Node.void('sinfo')
|
||
root.add_child(sinfo)
|
||
sinfo.add_child(Node.string('nm', machine_name))
|
||
sinfo.add_child(Node.bool('cl_enbl', close))
|
||
sinfo.add_child(Node.u8('cl_h', hour))
|
||
sinfo.add_child(Node.u8('cl_m', minute))
|
||
return root
|
||
|
||
def handle_shop_setting_write_request(self, request: Node) -> Node:
|
||
return Node.void('shop')
|
||
|
||
def handle_shop_info_write_request(self, request: Node) -> Node:
|
||
self.update_machine_name(request.child_value('sinfo/nm'))
|
||
self.update_machine_data({
|
||
'close': request.child_value('sinfo/cl_enbl'),
|
||
'hour': request.child_value('sinfo/cl_h'),
|
||
'minute': request.child_value('sinfo/cl_m'),
|
||
'pref': request.child_value('sinfo/prf'),
|
||
})
|
||
return Node.void('shop')
|
||
|
||
def __add_event_info(self, root: Node) -> None:
|
||
event_ctrl = Node.void('event_ctrl')
|
||
root.add_child(event_ctrl)
|
||
|
||
events: Dict[int, int] = {
|
||
# Tricolette Park unlock event.
|
||
9: 0,
|
||
}
|
||
|
||
for (eventid, phase) in events.items():
|
||
data = Node.void('data')
|
||
event_ctrl.add_child(data)
|
||
data.add_child(Node.s32('type', eventid))
|
||
data.add_child(Node.s32('phase', phase))
|
||
|
||
item_lock_ctrl = Node.void('item_lock_ctrl')
|
||
root.add_child(item_lock_ctrl)
|
||
# Contains zero or more nodes like:
|
||
# <item>
|
||
# <type __type="u8">any</type>
|
||
# <id __type="u16">any</id>
|
||
# <param __type="u16">0-3</param>
|
||
# </item>
|
||
|
||
def handle_info_common_request(self, request: Node) -> Node:
|
||
root = Node.void('info')
|
||
self.__add_event_info(root)
|
||
return root
|
||
|
||
def handle_info_ranking_request(self, request: Node) -> Node:
|
||
version = request.child_value('ver')
|
||
|
||
root = Node.void('info')
|
||
root.add_child(Node.s32('ver', version))
|
||
ranking = Node.void('ranking')
|
||
root.add_child(ranking)
|
||
|
||
def add_hitchart(name: str, start: int, end: int, hitchart: List[Tuple[int, int]]) -> None:
|
||
base = Node.void(name)
|
||
ranking.add_child(base)
|
||
base.add_child(Node.s32('bt', start))
|
||
base.add_child(Node.s32('et', end))
|
||
new = Node.void('new')
|
||
base.add_child(new)
|
||
|
||
for (mid, plays) in hitchart:
|
||
d = Node.void('d')
|
||
new.add_child(d)
|
||
d.add_child(Node.s16('mid', mid))
|
||
d.add_child(Node.s32('cnt', plays))
|
||
|
||
# Weekly hit chart
|
||
add_hitchart(
|
||
'weekly',
|
||
Time.now() - Time.SECONDS_IN_WEEK,
|
||
Time.now(),
|
||
self.data.local.music.get_hit_chart(self.game, self.version, 1024, 7),
|
||
)
|
||
|
||
# Monthly hit chart
|
||
add_hitchart(
|
||
'monthly',
|
||
Time.now() - Time.SECONDS_IN_DAY * 30,
|
||
Time.now(),
|
||
self.data.local.music.get_hit_chart(self.game, self.version, 1024, 30),
|
||
)
|
||
|
||
# All time hit chart
|
||
add_hitchart(
|
||
'total',
|
||
Time.now() - Time.SECONDS_IN_DAY * 365,
|
||
Time.now(),
|
||
self.data.local.music.get_hit_chart(self.game, self.version, 1024, 365),
|
||
)
|
||
|
||
return root
|
||
|
||
def handle_info_pzlcmt_read_request(self, request: Node) -> Node:
|
||
extid = request.child_value('uid')
|
||
teamid = request.child_value('tid')
|
||
limit = request.child_value('limit')
|
||
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
||
|
||
comments = [
|
||
achievement for achievement in
|
||
self.data.local.user.get_all_time_based_achievements(self.game, self.version)
|
||
if achievement[1].type == 'puzzle_comment'
|
||
]
|
||
comments.sort(key=lambda x: x[1].timestamp, reverse=True)
|
||
favorites = [
|
||
comment for comment in comments
|
||
if comment[0] == userid
|
||
]
|
||
teamcomments = [
|
||
comment for comment in comments
|
||
if comment[1].data.get_int('teamid') == teamid
|
||
]
|
||
|
||
# Cap all comment blocks to the limit
|
||
if limit >= 0:
|
||
comments = comments[:limit]
|
||
favorites = favorites[:limit]
|
||
teamcomments = teamcomments[:limit]
|
||
|
||
root = Node.void('info')
|
||
comment = Node.void('comment')
|
||
root.add_child(comment)
|
||
comment.add_child(Node.s32('time', Time.now()))
|
||
|
||
# Mapping of profiles to userIDs
|
||
uid_mapping = {
|
||
uid: prof for (uid, prof) in self.get_any_profiles([c[0] for c in comments])
|
||
}
|
||
|
||
# Handle anonymous comments by returning a default profile
|
||
uid_mapping[UserID(0)] = Profile(
|
||
self.game,
|
||
self.version,
|
||
"",
|
||
0,
|
||
{'name': 'PLAYER'},
|
||
)
|
||
|
||
def add_comments(name: str, selected: List[Tuple[UserID, Achievement]]) -> None:
|
||
for (uid, ach) in selected:
|
||
cmnt = Node.void(name)
|
||
root.add_child(cmnt)
|
||
cmnt.add_child(Node.s32('uid', uid_mapping[uid].extid))
|
||
cmnt.add_child(Node.string('name', uid_mapping[uid].get_str('name')))
|
||
cmnt.add_child(Node.s16('icon', ach.data.get_int('icon')))
|
||
cmnt.add_child(Node.s8('bln', ach.data.get_int('bln')))
|
||
cmnt.add_child(Node.s32('tid', ach.data.get_int('teamid')))
|
||
cmnt.add_child(Node.string('t_name', ach.data.get_str('teamname')))
|
||
cmnt.add_child(Node.s8('pref', ach.data.get_int('prefecture')))
|
||
cmnt.add_child(Node.s32('time', ach.timestamp))
|
||
cmnt.add_child(Node.string('comment', ach.data.get_str('comment')))
|
||
cmnt.add_child(Node.bool('is_tweet', ach.data.get_bool('tweet')))
|
||
|
||
# Add all comments
|
||
add_comments('c', comments)
|
||
|
||
# Add personal comments (favorites)
|
||
add_comments('cf', favorites)
|
||
|
||
# Add team comments
|
||
add_comments('ct', teamcomments)
|
||
|
||
return root
|
||
|
||
def handle_info_pzlcmt_write_request(self, request: Node) -> Node:
|
||
extid = request.child_value('uid')
|
||
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
||
if userid is None:
|
||
# Anonymous comment
|
||
userid = UserID(0)
|
||
|
||
icon = request.child_value('icon')
|
||
bln = request.child_value('bln')
|
||
teamid = request.child_value('tid')
|
||
teamname = request.child_value('t_name')
|
||
prefecture = request.child_value('pref')
|
||
comment = request.child_value('comment')
|
||
is_tweet = request.child_value('is_tweet')
|
||
|
||
# Link comment to user's profile
|
||
self.data.local.user.put_time_based_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
0, # We never have an ID for this, since comments are add-only
|
||
'puzzle_comment',
|
||
{
|
||
'icon': icon,
|
||
'bln': bln,
|
||
'teamid': teamid,
|
||
'teamname': teamname,
|
||
'prefecture': prefecture,
|
||
'comment': comment,
|
||
'tweet': is_tweet,
|
||
},
|
||
)
|
||
|
||
return Node.void('info')
|
||
|
||
def handle_jbrbcollabo_save_request(self, request: Node) -> Node:
|
||
jbrbcollabo = Node.void('jbrbcollabo')
|
||
jbrbcollabo.add_child(Node.u16('marathontype', 0))
|
||
jbrbcollabo.add_child(Node.u32('smith_start', 0))
|
||
jbrbcollabo.add_child(Node.u32('pastel_start', 0))
|
||
jbrbcollabo.add_child(Node.u32('smith_run', 0))
|
||
jbrbcollabo.add_child(Node.u32('pastel_run', 0))
|
||
jbrbcollabo.add_child(Node.u16('smith_ouen', 0))
|
||
jbrbcollabo.add_child(Node.u16('pastel_ouen', 0))
|
||
jbrbcollabo.add_child(Node.u32('smith_water_run', 0))
|
||
jbrbcollabo.add_child(Node.u32('pastel_water_run', 0))
|
||
jbrbcollabo.add_child(Node.bool('getwater', False))
|
||
jbrbcollabo.add_child(Node.bool('smith_goal', False))
|
||
jbrbcollabo.add_child(Node.bool('pastel_goal', False))
|
||
jbrbcollabo.add_child(Node.u16('distancetype', 0))
|
||
jbrbcollabo.add_child(Node.bool('run1_1_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_2_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_3_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_1_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_2_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_3_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_1_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_2_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_3_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_1_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_2_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_3_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_1_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_2_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_3_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_1_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_2_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_3_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run4_1_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run4_1_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run4_2_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run4_2_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('start_flg', False))
|
||
return jbrbcollabo
|
||
|
||
def handle_lobby_entry_request(self, request: Node) -> Node:
|
||
root = Node.void('lobby')
|
||
root.add_child(Node.s32('interval', 120))
|
||
root.add_child(Node.s32('interval_p', 120))
|
||
|
||
# Create a lobby entry for this user
|
||
extid = request.child_value('e/uid')
|
||
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
||
if userid is not None:
|
||
profile = self.get_profile(userid)
|
||
self.data.local.lobby.put_lobby(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
{
|
||
'mid': request.child_value('e/mid'),
|
||
'ng': request.child_value('e/ng'),
|
||
'mopt': request.child_value('e/mopt'),
|
||
'tid': request.child_value('e/tid'),
|
||
'tn': request.child_value('e/tn'),
|
||
'topt': request.child_value('e/topt'),
|
||
'lid': request.child_value('e/lid'),
|
||
'sn': request.child_value('e/sn'),
|
||
'pref': request.child_value('e/pref'),
|
||
'stg': request.child_value('e/stg'),
|
||
'pside': request.child_value('e/pside'),
|
||
'eatime': request.child_value('e/eatime'),
|
||
'ga': request.child_value('e/ga'),
|
||
'gp': request.child_value('e/gp'),
|
||
'la': request.child_value('e/la'),
|
||
'ver': request.child_value('e/ver'),
|
||
}
|
||
)
|
||
lobby = self.data.local.lobby.get_lobby(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
)
|
||
root.add_child(Node.s32('eid', lobby.get_int('id')))
|
||
e = Node.void('e')
|
||
root.add_child(e)
|
||
e.add_child(Node.s32('eid', lobby.get_int('id')))
|
||
e.add_child(Node.u16('mid', lobby.get_int('mid')))
|
||
e.add_child(Node.u8('ng', lobby.get_int('ng')))
|
||
e.add_child(Node.s32('uid', profile.extid))
|
||
e.add_child(Node.s32('uattr', profile.get_int('uattr')))
|
||
e.add_child(Node.string('pn', profile.get_str('name')))
|
||
e.add_child(Node.s16('mg', profile.get_int('mg')))
|
||
e.add_child(Node.s32('mopt', lobby.get_int('mopt')))
|
||
e.add_child(Node.s32('tid', lobby.get_int('tid')))
|
||
e.add_child(Node.string('tn', lobby.get_str('tn')))
|
||
e.add_child(Node.s32('topt', lobby.get_int('topt')))
|
||
e.add_child(Node.string('lid', lobby.get_str('lid')))
|
||
e.add_child(Node.string('sn', lobby.get_str('sn')))
|
||
e.add_child(Node.u8('pref', lobby.get_int('pref')))
|
||
e.add_child(Node.s8('stg', lobby.get_int('stg')))
|
||
e.add_child(Node.s8('pside', lobby.get_int('pside')))
|
||
e.add_child(Node.s16('eatime', lobby.get_int('eatime')))
|
||
e.add_child(Node.u8_array('ga', lobby.get_int_array('ga', 4)))
|
||
e.add_child(Node.u16('gp', lobby.get_int('gp')))
|
||
e.add_child(Node.u8_array('la', lobby.get_int_array('la', 4)))
|
||
e.add_child(Node.u8('ver', lobby.get_int('ver')))
|
||
|
||
return root
|
||
|
||
def handle_lobby_read_request(self, request: Node) -> Node:
|
||
root = Node.void('lobby')
|
||
root.add_child(Node.s32('interval', 120))
|
||
root.add_child(Node.s32('interval_p', 120))
|
||
|
||
# Look up all lobbies matching the criteria specified
|
||
ver = request.child_value('var')
|
||
mg = request.child_value('m_grade') # noqa: F841
|
||
extid = request.child_value('uid')
|
||
limit = request.child_value('max')
|
||
userid = self.data.remote.user.from_extid(self.game, self.version, extid)
|
||
if userid is not None:
|
||
lobbies = self.data.local.lobby.get_all_lobbies(self.game, self.version)
|
||
for (user, lobby) in lobbies:
|
||
if limit <= 0:
|
||
break
|
||
|
||
if user == userid:
|
||
# If we have our own lobby, don't return it
|
||
continue
|
||
if ver != lobby.get_int('ver'):
|
||
# Don't return lobby data for different versions
|
||
continue
|
||
|
||
profile = self.get_profile(user)
|
||
if profile is None:
|
||
# No profile info, don't return this lobby
|
||
continue
|
||
|
||
e = Node.void('e')
|
||
root.add_child(e)
|
||
e.add_child(Node.s32('eid', lobby.get_int('id')))
|
||
e.add_child(Node.u16('mid', lobby.get_int('mid')))
|
||
e.add_child(Node.u8('ng', lobby.get_int('ng')))
|
||
e.add_child(Node.s32('uid', profile.extid))
|
||
e.add_child(Node.s32('uattr', profile.get_int('uattr')))
|
||
e.add_child(Node.string('pn', profile.get_str('name')))
|
||
e.add_child(Node.s16('mg', profile.get_int('mg')))
|
||
e.add_child(Node.s32('mopt', lobby.get_int('mopt')))
|
||
e.add_child(Node.s32('tid', lobby.get_int('tid')))
|
||
e.add_child(Node.string('tn', lobby.get_str('tn')))
|
||
e.add_child(Node.s32('topt', lobby.get_int('topt')))
|
||
e.add_child(Node.string('lid', lobby.get_str('lid')))
|
||
e.add_child(Node.string('sn', lobby.get_str('sn')))
|
||
e.add_child(Node.u8('pref', lobby.get_int('pref')))
|
||
e.add_child(Node.s8('stg', lobby.get_int('stg')))
|
||
e.add_child(Node.s8('pside', lobby.get_int('pside')))
|
||
e.add_child(Node.s16('eatime', lobby.get_int('eatime')))
|
||
e.add_child(Node.u8_array('ga', lobby.get_int_array('ga', 4)))
|
||
e.add_child(Node.u16('gp', lobby.get_int('gp')))
|
||
e.add_child(Node.u8_array('la', lobby.get_int_array('la', 4)))
|
||
e.add_child(Node.u8('ver', lobby.get_int('ver')))
|
||
|
||
limit = limit - 1
|
||
|
||
return root
|
||
|
||
def handle_lobby_delete_request(self, request: Node) -> Node:
|
||
eid = request.child_value('eid')
|
||
self.data.local.lobby.destroy_lobby(eid)
|
||
return Node.void('lobby')
|
||
|
||
def handle_player_start_request(self, request: Node) -> Node:
|
||
root = Node.void('player')
|
||
|
||
# Create a new play session based on info from the request
|
||
refid = request.child_value('rid')
|
||
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
||
if userid is not None:
|
||
self.data.local.lobby.put_play_session_info(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
{
|
||
'ga': request.child_value('ga'),
|
||
'gp': request.child_value('gp'),
|
||
'la': request.child_value('la'),
|
||
},
|
||
)
|
||
info = self.data.local.lobby.get_play_session_info(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
)
|
||
if info is not None:
|
||
play_id = info.get_int('id')
|
||
else:
|
||
play_id = 0
|
||
else:
|
||
play_id = 0
|
||
|
||
# Session stuff, and resend global defaults
|
||
root.add_child(Node.s32('plyid', play_id))
|
||
root.add_child(Node.u64('start_time', Time.now() * 1000))
|
||
self.__add_event_info(root)
|
||
|
||
# Event settings and such
|
||
lincle_link_4 = Node.void('lincle_link_4')
|
||
root.add_child(lincle_link_4)
|
||
lincle_link_4.add_child(Node.u32('qpro', 0))
|
||
lincle_link_4.add_child(Node.u32('glass', 0))
|
||
lincle_link_4.add_child(Node.u32('treasure', 0))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_0_0', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_0_1', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_0_2', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_0_3', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_0_4', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_0_5', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_0_6', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_0', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_1', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_2', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_3', False))
|
||
lincle_link_4.add_child(Node.bool('for_iidx_4', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_0_0', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_0_1', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_0_2', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_0_3', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_0_4', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_0_5', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_0_6', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_0', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_1', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_2', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_3', False))
|
||
lincle_link_4.add_child(Node.bool('for_rb_4', False))
|
||
lincle_link_4.add_child(Node.bool('qproflg', False))
|
||
lincle_link_4.add_child(Node.bool('glassflg', False))
|
||
lincle_link_4.add_child(Node.bool('complete', False))
|
||
|
||
jbrbcollabo = Node.void('jbrbcollabo')
|
||
root.add_child(jbrbcollabo)
|
||
jbrbcollabo.add_child(Node.bool('run1_1_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_2_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_3_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_1_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_2_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_3_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run1_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_1_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_2_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_3_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_1_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_2_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_3_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run2_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_1_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_2_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_3_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_4_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_1_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_2_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_3_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run3_4_flg', False))
|
||
jbrbcollabo.add_child(Node.u16('marathontype', 0))
|
||
jbrbcollabo.add_child(Node.u32('smith_start', 0))
|
||
jbrbcollabo.add_child(Node.u32('pastel_start', 0))
|
||
jbrbcollabo.add_child(Node.u16('smith_ouen', 0))
|
||
jbrbcollabo.add_child(Node.u16('pastel_ouen', 0))
|
||
jbrbcollabo.add_child(Node.u16('distancetype', 0))
|
||
jbrbcollabo.add_child(Node.bool('smith_goal', False))
|
||
jbrbcollabo.add_child(Node.bool('pastel_goal', False))
|
||
jbrbcollabo.add_child(Node.bool('run4_1_j_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run4_1_r_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run4_2_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('run4_2_flg', False))
|
||
jbrbcollabo.add_child(Node.bool('start_flg', False))
|
||
|
||
tricolettepark = Node.void('tricolettepark')
|
||
root.add_child(tricolettepark)
|
||
tricolettepark.add_child(Node.s32('open_music', -1))
|
||
tricolettepark.add_child(Node.s32('boss0_damage', -1))
|
||
tricolettepark.add_child(Node.s32('boss1_damage', -1))
|
||
tricolettepark.add_child(Node.s32('boss2_damage', -1))
|
||
tricolettepark.add_child(Node.s32('boss3_damage', -1))
|
||
tricolettepark.add_child(Node.s32('boss0_stun', -1))
|
||
tricolettepark.add_child(Node.s32('boss1_stun', -1))
|
||
tricolettepark.add_child(Node.s32('boss2_stun', -1))
|
||
tricolettepark.add_child(Node.s32('boss3_stun', -1))
|
||
tricolettepark.add_child(Node.s32('magic_gauge', -1))
|
||
tricolettepark.add_child(Node.s32('today_party', -1))
|
||
tricolettepark.add_child(Node.bool('union_magic', False))
|
||
tricolettepark.add_child(Node.bool('is_complete', False))
|
||
tricolettepark.add_child(Node.float('base_attack_rate', 1.0))
|
||
|
||
return root
|
||
|
||
def handle_player_delete_request(self, request: Node) -> Node:
|
||
return Node.void('player')
|
||
|
||
def handle_player_end_request(self, request: Node) -> Node:
|
||
# Destroy play session based on info from the request
|
||
refid = request.child_value('rid')
|
||
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
||
if userid is not None:
|
||
# Kill any lingering lobbies by this user
|
||
lobby = self.data.local.lobby.get_lobby(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
)
|
||
if lobby is not None:
|
||
self.data.local.lobby.destroy_lobby(lobby.get_int('id'))
|
||
self.data.local.lobby.destroy_play_session_info(self.game, self.version, userid)
|
||
|
||
return Node.void('player')
|
||
|
||
def handle_player_succeed_request(self, request: Node) -> Node:
|
||
refid = request.child_value('rid')
|
||
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
||
if userid is not None:
|
||
previous_version = self.previous_version()
|
||
profile = previous_version.get_profile(userid)
|
||
achievements = self.data.local.user.get_achievements(previous_version.game, previous_version.version, userid)
|
||
scores = self.data.remote.music.get_scores(previous_version.game, previous_version.version, userid)
|
||
else:
|
||
profile = None
|
||
|
||
root = Node.void('player')
|
||
|
||
if profile is None:
|
||
root.add_child(Node.string('name', ''))
|
||
root.add_child(Node.s16('lv', -1))
|
||
root.add_child(Node.s32('exp', -1))
|
||
root.add_child(Node.s32('grd', -1))
|
||
root.add_child(Node.s32('ap', -1))
|
||
|
||
root.add_child(Node.void('released'))
|
||
root.add_child(Node.void('mrecord'))
|
||
else:
|
||
root.add_child(Node.string('name', profile.get_str('name')))
|
||
root.add_child(Node.s16('lv', profile.get_int('lvl')))
|
||
root.add_child(Node.s32('exp', profile.get_int('exp')))
|
||
root.add_child(Node.s32('grd', profile.get_int('mg'))) # This is a guess
|
||
root.add_child(Node.s32('ap', profile.get_int('ap')))
|
||
|
||
released = Node.void('released')
|
||
root.add_child(released)
|
||
for item in achievements:
|
||
if item.type != 'item_0':
|
||
continue
|
||
|
||
released.add_child(Node.s16('i', item.id))
|
||
|
||
mrecord = Node.void('mrecord')
|
||
root.add_child(mrecord)
|
||
for score in scores:
|
||
mrec = Node.void('mrec')
|
||
mrecord.add_child(mrec)
|
||
mrec.add_child(Node.s16('mid', score.id))
|
||
mrec.add_child(Node.s8('ntgrd', score.chart))
|
||
mrec.add_child(Node.s32('pc', score.plays))
|
||
mrec.add_child(Node.s8('ct', self.__db_to_game_clear_type(score.data.get_int('clear_type'), score.data.get_int('combo_type'))))
|
||
mrec.add_child(Node.s16('ar', score.data.get_int('achievement_rate')))
|
||
mrec.add_child(Node.s16('scr', score.points))
|
||
mrec.add_child(Node.s16('cmb', score.data.get_int('combo')))
|
||
mrec.add_child(Node.s16('ms', score.data.get_int('miss_count')))
|
||
mrec.add_child(Node.u16('ver', 0))
|
||
|
||
return root
|
||
|
||
def handle_player_read_request(self, request: Node) -> Node:
|
||
refid = request.child_value('rid')
|
||
profile = self.get_profile_by_refid(refid)
|
||
if profile:
|
||
return profile
|
||
return Node.void('player')
|
||
|
||
def handle_player_write_request(self, request: Node) -> Node:
|
||
refid = request.child_value('pdata/account/rid')
|
||
profile = self.put_profile_by_refid(refid, request)
|
||
root = Node.void('player')
|
||
|
||
if profile is None:
|
||
root.add_child(Node.s32('uid', 0))
|
||
else:
|
||
root.add_child(Node.s32('uid', profile.extid))
|
||
return root
|
||
|
||
def format_profile(self, userid: UserID, profile: Profile) -> Node:
|
||
statistics = self.get_play_statistics(userid)
|
||
game_config = self.get_game_config()
|
||
achievements = self.data.local.user.get_achievements(self.game, self.version, userid)
|
||
scores = self.data.remote.music.get_scores(self.game, self.version, userid)
|
||
links = self.data.local.user.get_links(self.game, self.version, userid)
|
||
root = Node.void('player')
|
||
pdata = Node.void('pdata')
|
||
root.add_child(pdata)
|
||
|
||
account = Node.void('account')
|
||
pdata.add_child(account)
|
||
account.add_child(Node.s32('usrid', profile.extid))
|
||
account.add_child(Node.s32('tpc', statistics.total_plays))
|
||
account.add_child(Node.s32('dpc', statistics.today_plays))
|
||
account.add_child(Node.s32('crd', 1))
|
||
account.add_child(Node.s32('brd', 1))
|
||
account.add_child(Node.s32('tdc', statistics.total_days))
|
||
account.add_child(Node.s32('intrvld', 0))
|
||
account.add_child(Node.s16('ver', 5))
|
||
account.add_child(Node.u64('pst', 0))
|
||
account.add_child(Node.u64('st', Time.now() * 1000))
|
||
|
||
# Base account info
|
||
base = Node.void('base')
|
||
pdata.add_child(base)
|
||
base.add_child(Node.string('name', profile.get_str('name')))
|
||
base.add_child(Node.s32('exp', profile.get_int('exp')))
|
||
base.add_child(Node.s32('lv', profile.get_int('lvl')))
|
||
base.add_child(Node.s32('mg', profile.get_int('mg')))
|
||
base.add_child(Node.s32('ap', profile.get_int('ap')))
|
||
base.add_child(Node.s32('tid', profile.get_int('team_id', -1)))
|
||
base.add_child(Node.string('tname', profile.get_str('team_name', '')))
|
||
base.add_child(Node.string('cmnt', ''))
|
||
base.add_child(Node.s32('uattr', profile.get_int('uattr')))
|
||
base.add_child(Node.s32_array('hidden_param', profile.get_int_array('hidden_param', 50)))
|
||
base.add_child(Node.s32('tbs', -1))
|
||
base.add_child(Node.s32('tbs_r', -1))
|
||
|
||
# Rivals
|
||
rival = Node.void('rival')
|
||
pdata.add_child(rival)
|
||
slotid = 0
|
||
for link in links:
|
||
if link.type != 'rival':
|
||
continue
|
||
|
||
rprofile = self.get_profile(link.other_userid)
|
||
if rprofile is None:
|
||
continue
|
||
|
||
r = Node.void('r')
|
||
rival.add_child(r)
|
||
r.add_child(Node.s32('slot_id', slotid))
|
||
r.add_child(Node.s32('id', rprofile.extid))
|
||
r.add_child(Node.string('name', rprofile.get_str('name')))
|
||
r.add_child(Node.bool('friend', True))
|
||
r.add_child(Node.bool('locked', False))
|
||
r.add_child(Node.s32('rc', 0))
|
||
slotid = slotid + 1
|
||
|
||
# Player customizations
|
||
custom = Node.void('custom')
|
||
customdict = profile.get_dict('custom')
|
||
pdata.add_child(custom)
|
||
custom.add_child(Node.u8('st_shot', customdict.get_int('st_shot')))
|
||
custom.add_child(Node.u8('st_frame', customdict.get_int('st_frame')))
|
||
custom.add_child(Node.u8('st_expl', customdict.get_int('st_expl')))
|
||
custom.add_child(Node.u8('st_bg', customdict.get_int('st_bg')))
|
||
custom.add_child(Node.u8('st_shot_vol', customdict.get_int('st_shot_vol')))
|
||
custom.add_child(Node.u8('st_bg_bri', customdict.get_int('st_bg_bri')))
|
||
custom.add_child(Node.u8('st_obj_size', customdict.get_int('st_obj_size')))
|
||
custom.add_child(Node.u8('st_jr_gauge', customdict.get_int('st_jr_gauge')))
|
||
custom.add_child(Node.u8('st_clr_gauge', customdict.get_int('st_clr_gauge')))
|
||
custom.add_child(Node.u8('st_jdg_disp', customdict.get_int('st_jdg_disp')))
|
||
custom.add_child(Node.u8('st_tm_disp', customdict.get_int('st_tm_disp')))
|
||
custom.add_child(Node.u8('st_rnd', customdict.get_int('st_rnd')))
|
||
custom.add_child(Node.s16_array('schat_0', customdict.get_int_array('schat_0', 9)))
|
||
custom.add_child(Node.s16_array('schat_1', customdict.get_int_array('schat_1', 9)))
|
||
custom.add_child(Node.s16_array('ichat_0', customdict.get_int_array('ichat_0', 6)))
|
||
custom.add_child(Node.s16_array('ichat_1', customdict.get_int_array('ichat_1', 6)))
|
||
|
||
# Player external config
|
||
config = Node.void('config')
|
||
configdict = profile.get_dict('config')
|
||
pdata.add_child(config)
|
||
config.add_child(Node.u8('msel_bgm', configdict.get_int('msel_bgm')))
|
||
config.add_child(Node.u8('narrowdown_type', configdict.get_int('narrowdown_type')))
|
||
config.add_child(Node.s16('icon_id', configdict.get_int('icon_id')))
|
||
config.add_child(Node.s16('byword_0', configdict.get_int('byword_0')))
|
||
config.add_child(Node.s16('byword_1', configdict.get_int('byword_1')))
|
||
config.add_child(Node.bool('is_auto_byword_0', configdict.get_bool('is_auto_byword_0')))
|
||
config.add_child(Node.bool('is_auto_byword_1', configdict.get_bool('is_auto_byword_1')))
|
||
config.add_child(Node.u8('mrec_type', configdict.get_int('mrec_type')))
|
||
config.add_child(Node.u8('tab_sel', configdict.get_int('tab_sel')))
|
||
config.add_child(Node.u8('card_disp', configdict.get_int('card_disp')))
|
||
config.add_child(Node.u8('score_tab_disp', configdict.get_int('score_tab_disp')))
|
||
config.add_child(Node.s16('last_music_id', configdict.get_int('last_music_id', -1)))
|
||
config.add_child(Node.u8('last_note_grade', configdict.get_int('last_note_grade')))
|
||
config.add_child(Node.u8('sort_type', configdict.get_int('sort_type')))
|
||
config.add_child(Node.u8('rival_panel_type', configdict.get_int('rival_panel_type')))
|
||
config.add_child(Node.u64('random_entry_work', configdict.get_int('random_entry_work')))
|
||
config.add_child(Node.u8('folder_lamp_type', configdict.get_int('folder_lamp_type')))
|
||
config.add_child(Node.bool('is_tweet', configdict.get_bool('is_tweet')))
|
||
config.add_child(Node.bool('is_link_twitter', configdict.get_bool('is_link_twitter')))
|
||
|
||
# Stamps
|
||
stamp = Node.void('stamp')
|
||
stampdict = profile.get_dict('stamp')
|
||
pdata.add_child(stamp)
|
||
stamp.add_child(Node.s32_array('stmpcnt', stampdict.get_int_array('stmpcnt', 5)))
|
||
stamp.add_child(Node.s32_array('tcktcnt', stampdict.get_int_array('tcktcnt', 5)))
|
||
stamp.add_child(Node.s64('area', stampdict.get_int('area')))
|
||
stamp.add_child(Node.s64('prfvst', stampdict.get_int('prfvst')))
|
||
stamp.add_child(Node.s32('reserve', stampdict.get_int('reserve')))
|
||
|
||
# Unlocks
|
||
released = Node.void('released')
|
||
pdata.add_child(released)
|
||
|
||
for item in achievements:
|
||
if item.type[:5] != 'item_':
|
||
continue
|
||
itemtype = int(item.type[5:])
|
||
if game_config.get_bool('force_unlock_songs') and itemtype == 0:
|
||
# Don't echo unlocks when we're force unlocking, we'll do it later
|
||
continue
|
||
|
||
info = Node.void('info')
|
||
released.add_child(info)
|
||
info.add_child(Node.u8('type', itemtype))
|
||
info.add_child(Node.u16('id', item.id))
|
||
info.add_child(Node.u16('param', item.data.get_int('param')))
|
||
|
||
if game_config.get_bool('force_unlock_songs'):
|
||
ids: Dict[int, int] = {}
|
||
songs = self.data.local.music.get_all_songs(self.game, self.version)
|
||
for song in songs:
|
||
if song.id not in ids:
|
||
ids[song.id] = 0
|
||
|
||
if song.data.get_int('difficulty') > 0:
|
||
ids[song.id] = ids[song.id] | (1 << song.chart)
|
||
|
||
for songid in ids:
|
||
if ids[songid] == 0:
|
||
continue
|
||
|
||
info = Node.void('info')
|
||
released.add_child(info)
|
||
info.add_child(Node.u8('type', 0))
|
||
info.add_child(Node.u16('id', songid))
|
||
info.add_child(Node.u16('param', ids[songid]))
|
||
|
||
# Favorite songs
|
||
fav_music_slot = Node.void('fav_music_slot')
|
||
pdata.add_child(fav_music_slot)
|
||
|
||
for item in achievements:
|
||
if item.type != 'music':
|
||
continue
|
||
|
||
slot = Node.void('slot')
|
||
fav_music_slot.add_child(slot)
|
||
slot.add_child(Node.u8('slot_id', item.id))
|
||
slot.add_child(Node.s16('music_id', item.data.get_int('music_id')))
|
||
|
||
# Event stuff
|
||
order = Node.void('order')
|
||
pdata.add_child(order)
|
||
order.add_child(Node.s32('exp', profile.get_int('order_exp')))
|
||
for item in achievements:
|
||
if item.type != 'order':
|
||
continue
|
||
|
||
data = Node.void('d')
|
||
order.add_child(data)
|
||
data.add_child(Node.s16('order', item.id))
|
||
data.add_child(Node.s16('slt', item.data.get_int('slt')))
|
||
data.add_child(Node.s32('ccnt', item.data.get_int('ccnt')))
|
||
data.add_child(Node.s32('fcnt', item.data.get_int('fcnt')))
|
||
data.add_child(Node.s32('fcnt1', item.data.get_int('fcnt1')))
|
||
data.add_child(Node.s32('prm', item.data.get_int('param')))
|
||
|
||
seedpod = Node.void('seedpod')
|
||
pdata.add_child(seedpod)
|
||
for item in achievements:
|
||
if item.type != 'seedpod':
|
||
continue
|
||
|
||
data = Node.void('data')
|
||
seedpod.add_child(data)
|
||
data.add_child(Node.s16('id', item.id))
|
||
data.add_child(Node.s16('pod', item.data.get_int('pod')))
|
||
|
||
eqpexp = Node.void('eqpexp')
|
||
pdata.add_child(eqpexp)
|
||
for item in achievements:
|
||
if item.type[:7] != 'eqpexp_':
|
||
continue
|
||
stype = int(item.type[7:])
|
||
|
||
data = Node.void('data')
|
||
eqpexp.add_child(data)
|
||
data.add_child(Node.s16('id', item.id))
|
||
data.add_child(Node.s32('exp', item.data.get_int('exp')))
|
||
data.add_child(Node.s16('stype', stype))
|
||
|
||
eventexp = Node.void('evntexp')
|
||
pdata.add_child(eventexp)
|
||
for item in achievements:
|
||
if item.type != 'eventexp':
|
||
continue
|
||
|
||
data = Node.void('data')
|
||
eventexp.add_child(data)
|
||
data.add_child(Node.s16('id', item.id))
|
||
data.add_child(Node.s32('exp', item.data.get_int('exp')))
|
||
|
||
# Scores
|
||
record = Node.void('record')
|
||
pdata.add_child(record)
|
||
record_old = Node.void('record_old')
|
||
pdata.add_child(record_old)
|
||
|
||
for score in scores:
|
||
rec = Node.void('rec')
|
||
record.add_child(rec)
|
||
rec.add_child(Node.s16('mid', score.id))
|
||
rec.add_child(Node.s8('ntgrd', score.chart))
|
||
rec.add_child(Node.s32('pc', score.plays))
|
||
rec.add_child(Node.s8('ct', self.__db_to_game_clear_type(score.data.get_int('clear_type'), score.data.get_int('combo_type'))))
|
||
rec.add_child(Node.s16('ar', score.data.get_int('achievement_rate')))
|
||
rec.add_child(Node.s16('scr', score.points))
|
||
rec.add_child(Node.s16('cmb', score.data.get_int('combo')))
|
||
rec.add_child(Node.s16('ms', score.data.get_int('miss_count')))
|
||
rec.add_child(Node.s32('bscrt', score.timestamp))
|
||
rec.add_child(Node.s32('bart', score.data.get_int('best_achievement_rate_time')))
|
||
rec.add_child(Node.s32('bctt', score.data.get_int('best_clear_type_time')))
|
||
rec.add_child(Node.s32('bmst', score.data.get_int('best_miss_count_time')))
|
||
rec.add_child(Node.s32('time', score.data.get_int('last_played_time')))
|
||
|
||
return root
|
||
|
||
def unformat_profile(self, userid: UserID, request: Node, oldprofile: Profile) -> Profile:
|
||
game_config = self.get_game_config()
|
||
newprofile = oldprofile.clone()
|
||
|
||
newprofile.replace_int('lid', ID.parse_machine_id(request.child_value('pdata/account/lid')))
|
||
newprofile.replace_str('name', request.child_value('pdata/base/name'))
|
||
newprofile.replace_int('exp', request.child_value('pdata/base/exp'))
|
||
newprofile.replace_int('lvl', request.child_value('pdata/base/lvl'))
|
||
newprofile.replace_int('mg', request.child_value('pdata/base/mg'))
|
||
newprofile.replace_int('ap', request.child_value('pdata/base/ap'))
|
||
newprofile.replace_int_array('hidden_param', 50, request.child_value('pdata/base/hidden_param'))
|
||
|
||
configdict = newprofile.get_dict('config')
|
||
config = request.child('pdata/config')
|
||
if config:
|
||
configdict.replace_int('msel_bgm', config.child_value('msel_bgm'))
|
||
configdict.replace_int('narrowdown_type', config.child_value('narrowdown_type'))
|
||
configdict.replace_int('icon_id', config.child_value('icon_id'))
|
||
configdict.replace_int('byword_0', config.child_value('byword_0'))
|
||
configdict.replace_int('byword_1', config.child_value('byword_1'))
|
||
configdict.replace_bool('is_auto_byword_0', config.child_value('is_auto_byword_0'))
|
||
configdict.replace_bool('is_auto_byword_1', config.child_value('is_auto_byword_1'))
|
||
configdict.replace_int('mrec_type', config.child_value('mrec_type'))
|
||
configdict.replace_int('tab_sel', config.child_value('tab_sel'))
|
||
configdict.replace_int('card_disp', config.child_value('card_disp'))
|
||
configdict.replace_int('score_tab_disp', config.child_value('score_tab_disp'))
|
||
configdict.replace_int('last_music_id', config.child_value('last_music_id'))
|
||
configdict.replace_int('last_note_grade', config.child_value('last_note_grade'))
|
||
configdict.replace_int('sort_type', config.child_value('sort_type'))
|
||
configdict.replace_int('rival_panel_type', config.child_value('rival_panel_type'))
|
||
configdict.replace_int('random_entry_work', config.child_value('random_entry_work'))
|
||
configdict.replace_int('folder_lamp_type', config.child_value('folder_lamp_type'))
|
||
configdict.replace_bool('is_tweet', config.child_value('is_tweet'))
|
||
configdict.replace_bool('is_link_twitter', config.child_value('is_link_twitter'))
|
||
newprofile.replace_dict('config', configdict)
|
||
|
||
customdict = newprofile.get_dict('custom')
|
||
custom = request.child('pdata/custom')
|
||
if custom:
|
||
customdict.replace_int('st_shot', custom.child_value('st_shot'))
|
||
customdict.replace_int('st_frame', custom.child_value('st_frame'))
|
||
customdict.replace_int('st_expl', custom.child_value('st_expl'))
|
||
customdict.replace_int('st_bg', custom.child_value('st_bg'))
|
||
customdict.replace_int('st_shot_vol', custom.child_value('st_shot_vol'))
|
||
customdict.replace_int('st_bg_bri', custom.child_value('st_bg_bri'))
|
||
customdict.replace_int('st_obj_size', custom.child_value('st_obj_size'))
|
||
customdict.replace_int('st_jr_gauge', custom.child_value('st_jr_gauge'))
|
||
customdict.replace_int('st_clr_gauge', custom.child_value('st_clr_gauge'))
|
||
customdict.replace_int('st_jdg_disp', custom.child_value('st_jdg_disp'))
|
||
customdict.replace_int('st_tm_disp', custom.child_value('st_tm_disp'))
|
||
customdict.replace_int('st_rnd', custom.child_value('st_rnd'))
|
||
customdict.replace_int_array('schat_0', 9, custom.child_value('schat_0'))
|
||
customdict.replace_int_array('schat_1', 9, custom.child_value('schat_1'))
|
||
customdict.replace_int_array('ichat_0', 6, custom.child_value('ichat_0'))
|
||
customdict.replace_int_array('ichat_1', 6, custom.child_value('ichat_1'))
|
||
newprofile.replace_dict('custom', customdict)
|
||
|
||
# Stamps
|
||
stampdict = newprofile.get_dict('stamp')
|
||
stamp = request.child('pdata/stamp')
|
||
if stamp:
|
||
stampdict.replace_int_array('stmpcnt', 5, stamp.child_value('stmpcnt'))
|
||
stampdict.replace_int_array('tcktcnt', 5, stamp.child_value('tcktcnt'))
|
||
stampdict.replace_int('area', stamp.child_value('area'))
|
||
stampdict.replace_int('prfvst', stamp.child_value('prfvst'))
|
||
stampdict.replace_int('reserve', stamp.child_value('reserve'))
|
||
newprofile.replace_dict('stamp', stampdict)
|
||
|
||
# Unlockable orders
|
||
newprofile.replace_int('order_exp', request.child_value('pdata/order/exp'))
|
||
order = request.child('pdata/order')
|
||
if order:
|
||
for child in order.children:
|
||
if child.name != 'd':
|
||
continue
|
||
|
||
orderid = child.child_value('order')
|
||
slt = child.child_value('slt')
|
||
ccnt = child.child_value('ccnt')
|
||
fcnt = child.child_value('fcnt')
|
||
fcnt1 = child.child_value('fcnt1')
|
||
param = child.child_value('prm')
|
||
|
||
if slt == -1:
|
||
# The game doesn't return valid data for this selection
|
||
# type, so be sure not to accidentally overwrite the
|
||
# finished flags.
|
||
continue
|
||
|
||
self.data.local.user.put_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
orderid,
|
||
'order',
|
||
{
|
||
'slt': slt,
|
||
'ccnt': ccnt,
|
||
'fcnt': fcnt,
|
||
'fcnt1': fcnt1,
|
||
'param': param,
|
||
},
|
||
)
|
||
|
||
# Music unlocks and other stuff
|
||
released = request.child('pdata/released')
|
||
if released:
|
||
for child in released.children:
|
||
if child.name != 'info':
|
||
continue
|
||
|
||
item_id = child.child_value('id')
|
||
item_type = child.child_value('type')
|
||
param = child.child_value('param')
|
||
if game_config.get_bool('force_unlock_songs') and item_type == 0:
|
||
# Don't save unlocks when we're force unlocking
|
||
continue
|
||
|
||
self.data.local.user.put_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
item_id,
|
||
f'item_{item_type}',
|
||
{
|
||
'param': param,
|
||
},
|
||
)
|
||
|
||
# Favorite music
|
||
fav_music_slot = request.child('pdata/fav_music_slot')
|
||
if fav_music_slot:
|
||
for child in fav_music_slot.children:
|
||
if child.name != 'slot':
|
||
continue
|
||
|
||
slot_id = child.child_value('slot_id')
|
||
music_id = child.child_value('music_id')
|
||
if music_id == -1:
|
||
# Delete this favorite
|
||
self.data.local.user.destroy_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
slot_id,
|
||
'music',
|
||
)
|
||
else:
|
||
# Add/update this favorite
|
||
self.data.local.user.put_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
slot_id,
|
||
'music',
|
||
{
|
||
'music_id': music_id,
|
||
},
|
||
)
|
||
|
||
# Event stuff
|
||
seedpod = request.child('pdata/seedpod')
|
||
if seedpod:
|
||
for child in seedpod.children:
|
||
if child.name != 'data':
|
||
continue
|
||
|
||
seedpod_id = child.child_value('id')
|
||
seedpod_pod = child.child_value('pod')
|
||
self.data.local.user.put_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
seedpod_id,
|
||
'seedpod',
|
||
{
|
||
'pod': seedpod_pod,
|
||
},
|
||
)
|
||
|
||
eventexp = request.child('pdata/evntexp')
|
||
if eventexp:
|
||
for child in eventexp.children:
|
||
if child.name != 'data':
|
||
continue
|
||
|
||
eventexp_id = child.child_value('id')
|
||
eventexp_exp = child.child_value('exp')
|
||
|
||
# Experience is additive, so load it first and add the updated amount
|
||
data = self.data.local.user.get_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
eventexp_id,
|
||
'eventexp',
|
||
) or ValidatedDict()
|
||
|
||
self.data.local.user.put_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
eventexp_id,
|
||
'eventexp',
|
||
{
|
||
'exp': data.get_int('exp') + eventexp_exp,
|
||
},
|
||
)
|
||
|
||
eqpexp = request.child('pdata/eqpexp')
|
||
if eqpexp:
|
||
for child in eqpexp.children:
|
||
if child.name != 'data':
|
||
continue
|
||
|
||
eqpexp_id = child.child_value('id')
|
||
eqpexp_exp = child.child_value('exp')
|
||
eqpexp_stype = child.child_value('stype')
|
||
|
||
# Experience is additive, so load it first and add the updated amount
|
||
data = self.data.local.user.get_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
eqpexp_id,
|
||
f'eqpexp_{eqpexp_stype}',
|
||
) or ValidatedDict()
|
||
|
||
self.data.local.user.put_achievement(
|
||
self.game,
|
||
self.version,
|
||
userid,
|
||
eqpexp_id,
|
||
f'eqpexp_{eqpexp_stype}',
|
||
{
|
||
'exp': data.get_int('exp') + eqpexp_exp,
|
||
},
|
||
)
|
||
|
||
# Grab any new records set during this play session
|
||
songplays = request.child('pdata/stglog')
|
||
if songplays:
|
||
for child in songplays.children:
|
||
if child.name != 'log':
|
||
continue
|
||
|
||
songid = child.child_value('mid')
|
||
chart = child.child_value('ng')
|
||
clear_type = child.child_value('ct')
|
||
if songid == 0 and chart == 0 and clear_type == -1:
|
||
# Dummy song save during profile create
|
||
continue
|
||
|
||
points = child.child_value('sc')
|
||
achievement_rate = child.child_value('ar')
|
||
clear_type, combo_type = self.__game_to_db_clear_type(clear_type)
|
||
combo = child.child_value('cmb')
|
||
miss_count = child.child_value('jt_ms')
|
||
self.update_score(
|
||
userid,
|
||
songid,
|
||
chart,
|
||
points,
|
||
achievement_rate,
|
||
clear_type,
|
||
combo_type,
|
||
miss_count,
|
||
combo=combo,
|
||
)
|
||
|
||
# Keep track of play statistics
|
||
self.update_play_statistics(userid)
|
||
|
||
return newprofile
|