def verify_game_play_e(self, location: str, refid: str) -> None: call = self.call_node() game = Node.void('game_3') call.add_child(game) game.set_attribute('ver', '0') game.set_attribute('method', 'play_e') game.add_child(Node.string('dataid', refid)) game.add_child(Node.s8('mode', 2)) game.add_child(Node.s16('track_num', 3)) game.add_child(Node.s32('s_coin', 0)) game.add_child(Node.s32('s_paseli', 0)) game.add_child(Node.s16('blaster_count', 0)) game.add_child(Node.s16('blaster_cartridge', 0)) game.add_child(Node.string('locid', location)) game.add_child(Node.u16('drop_frame', 396)) game.add_child(Node.u16('drop_frame_max', 396)) game.add_child(Node.u16('drop_count', 1)) game.add_child(Node.string('etc', 'StoryID:0,StoryPrg:0,PrgPrm:0')) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/game_3")
def verify_game_save_m(self, location: str, refid: str, score: Dict[str, int]) -> None: call = self.call_node() game = Node.void('game_2') call.add_child(game) game.set_attribute('ver', '0') game.set_attribute('method', 'save_m') game.add_child(Node.string('refid', refid)) game.add_child(Node.string('dataid', refid)) game.add_child(Node.u32('music_id', score['id'])) game.add_child(Node.u32('music_type', score['chart'])) game.add_child(Node.u32('score', score['score'])) game.add_child(Node.u32('clear_type', score['clear_type'])) game.add_child(Node.u32('score_grade', score['grade'])) game.add_child(Node.u32('max_chain', 0)) game.add_child(Node.u32('critical', 0)) game.add_child(Node.u32('near', 0)) game.add_child(Node.u32('error', 0)) game.add_child(Node.u32('effective_rate', 100)) game.add_child(Node.u32('btn_rate', 0)) game.add_child(Node.u32('long_rate', 0)) game.add_child(Node.u32('vol_rate', 0)) game.add_child(Node.u8('mode', 0)) game.add_child(Node.u8('gauge_type', 0)) game.add_child(Node.u16('online_num', 0)) game.add_child(Node.u16('local_num', 0)) game.add_child(Node.string('locid', location)) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/game_2")
def verify_game_play_e(self, location: str, refid: str, play_id: int) -> None: call = self.call_node() game = Node.void('game') call.add_child(game) game.set_attribute('ver', '0') game.set_attribute('method', 'sv4_play_e') game.add_child(Node.string('refid', refid)) game.add_child(Node.u32('play_id', play_id)) game.add_child(Node.s8('start_type', 1)) game.add_child(Node.s8('mode', 2)) game.add_child(Node.s16('track_num', 3)) game.add_child(Node.s32('s_coin', 0)) game.add_child(Node.s32('s_paseli', 247)) game.add_child(Node.u32('print_card', 0)) game.add_child(Node.u32('print_result', 0)) game.add_child(Node.u32('blaster_num', 0)) game.add_child(Node.u32('today_cnt', 1)) game.add_child(Node.u32('play_chain', 1)) game.add_child(Node.u32('week_play_cnt', 0)) game.add_child(Node.u32('week_chain', 0)) game.add_child(Node.string('locid', location)) game.add_child(Node.u16('drop_frame', 16169)) game.add_child(Node.u16('drop_frame_max', 11984)) game.add_child(Node.u16('drop_count', 6)) game.add_child(Node.string('etc', 'play_t:605')) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/game")
def verify_lobby_entry(self, location: str, extid: int) -> int: call = self.call_node() lobby = Node.void('lobby') lobby.set_attribute('method', 'entry') e = Node.void('e') lobby.add_child(e) e.add_child(Node.s32('eid', 0)) e.add_child(Node.u16('mid', 79)) e.add_child(Node.u8('ng', 0)) e.add_child(Node.s32('uid', extid)) e.add_child(Node.s32('uattr', 0)) e.add_child(Node.string('pn', self.NAME)) e.add_child(Node.s16('mg', 255)) e.add_child(Node.s32('mopt', 0)) e.add_child(Node.s32('tid', 0)) e.add_child(Node.string('tn', '')) e.add_child(Node.s32('topt', 0)) e.add_child(Node.string('lid', location)) e.add_child(Node.string('sn', '')) e.add_child(Node.u8('pref', 51)) e.add_child(Node.s8('stg', 4)) e.add_child(Node.s8('pside', 0)) e.add_child(Node.s16('eatime', 30)) e.add_child(Node.u8_array('ga', [127, 0, 0, 1])) e.add_child(Node.u16('gp', 10007)) e.add_child(Node.u8_array('la', [16, 0, 0, 0])) e.add_child(Node.u8('ver', 5)) lobby.add_child(Node.s32_array('friend', [])) call.add_child(lobby) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/lobby/interval") self.assert_path(resp, "response/lobby/interval_p") self.assert_path(resp, "response/lobby/eid") self.assert_path(resp, "response/lobby/e/eid") self.assert_path(resp, "response/lobby/e/mid") self.assert_path(resp, "response/lobby/e/ng") self.assert_path(resp, "response/lobby/e/uid") self.assert_path(resp, "response/lobby/e/uattr") self.assert_path(resp, "response/lobby/e/pn") self.assert_path(resp, "response/lobby/e/mg") self.assert_path(resp, "response/lobby/e/mopt") self.assert_path(resp, "response/lobby/e/tid") self.assert_path(resp, "response/lobby/e/tn") self.assert_path(resp, "response/lobby/e/topt") self.assert_path(resp, "response/lobby/e/lid") self.assert_path(resp, "response/lobby/e/sn") self.assert_path(resp, "response/lobby/e/pref") self.assert_path(resp, "response/lobby/e/stg") self.assert_path(resp, "response/lobby/e/pside") self.assert_path(resp, "response/lobby/e/eatime") self.assert_path(resp, "response/lobby/e/ga") self.assert_path(resp, "response/lobby/e/gp") self.assert_path(resp, "response/lobby/e/la") self.assert_path(resp, "response/lobby/e/ver") return resp.child_value('lobby/eid')
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'), }) 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.get_int('extid'))) e.add_child(Node.string('pn', profile.get_str('name'))) e.add_child(Node.s32('uattr', profile.get_int('uattr'))) e.add_child(Node.s32('mopt', lobby.get_int('mopt'))) e.add_child(Node.s16('mg', profile.get_int('mg'))) 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))) return root
def handle_lobby_rb5_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) info = self.data.local.lobby.get_play_session_info( self.game, self.version, userid) if profile is None or info is None: # No profile info, don't return this lobby return root 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.get_int('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.s32('plyid', info.get_int('id'))) e.add_child(Node.s16('mg', profile.get_int('mg'))) e.add_child(Node.s32('mopt', lobby.get_int('mopt'))) 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_facility_get_request(self, request: Node) -> Node: """ Handle a facility request. The only method of note is the 'get' request, which expects to return a bunch of information about the arcade this cabinet is in, as well as some settings for URLs and the name of the cab. """ machine = self.data.local.machine.get_machine(self.config['machine']['pcbid']) root = Node.void('facility') root.set_attribute('expire', '600') location = Node.void('location') location.add_child(Node.string('id', ID.format_machine_id(machine.id))) location.add_child(Node.string('country', 'US')) location.add_child(Node.string('region', '.')) location.add_child(Node.string('name', machine.name)) location.add_child(Node.u8('type', 0)) line = Node.void('line') line.add_child(Node.string('id', '.')) line.add_child(Node.u8('class', 0)) portfw = Node.void('portfw') portfw.add_child(Node.ipv4('globalip', self.config['client']['address'])) portfw.add_child(Node.u16('globalport', machine.port)) portfw.add_child(Node.u16('privateport', machine.port)) public = Node.void('public') public.add_child(Node.u8('flag', 1)) public.add_child(Node.string('name', '.')) public.add_child(Node.string('latitude', '0')) public.add_child(Node.string('longitude', '0')) share = Node.void('share') eacoin = Node.void('eacoin') eacoin.add_child(Node.s32('notchamount', 3000)) eacoin.add_child(Node.s32('notchcount', 3)) eacoin.add_child(Node.s32('supplylimit', 10000)) eapass = Node.void('eapass') eapass.add_child(Node.u16('valid', 365)) url = Node.void('url') url.add_child(Node.string('eapass', self.config['server']['uri'] or 'www.ea-pass.konami.net')) url.add_child(Node.string('arcadefan', self.config['server']['uri'] or 'www.konami.jp/am')) url.add_child(Node.string('konaminetdx', self.config['server']['uri'] or 'http://am.573.jp')) url.add_child(Node.string('konamiid', self.config['server']['uri'] or 'https://id.konami.net')) url.add_child(Node.string('eagate', self.config['server']['uri'] or 'http://eagate.573.jp')) share.add_child(eacoin) share.add_child(url) share.add_child(eapass) root.add_child(location) root.add_child(line) root.add_child(portfw) root.add_child(public) root.add_child(share) return root
def test_game_packet6(self) -> Node: root = Node.void('response') facility = Node.void('facility') root.add_child(facility) location = Node.void('location') facility.add_child(location) location.add_child(Node.string('id', 'US-6')) location.add_child(Node.string('country', 'US')) location.add_child(Node.string('region', '.')) location.add_child(Node.string('name', '')) location.add_child(Node.u8('type', 0)) line = Node.void('line') facility.add_child(line) line.add_child(Node.string('id', '.')) line.add_child(Node.u8('class', 0)) portfw = Node.void('portfw') facility.add_child(portfw) portfw.add_child(Node.ipv4('globalip', '10.0.0.1')) portfw.add_child(Node.u16('globalport', 20000)) portfw.add_child(Node.u16('privateport', 20000)) public = Node.void('public') facility.add_child(public) public.add_child(Node.u8('flag', 1)) public.add_child(Node.string('name', '.')) public.add_child(Node.string('latitude', '0')) public.add_child(Node.string('longitude', '0')) share = Node.void('share') facility.add_child(share) eacoin = Node.void('eacoin') share.add_child(eacoin) eacoin.add_child(Node.s32('notchamount', 0)) eacoin.add_child(Node.s32('notchcount', 0)) eacoin.add_child(Node.s32('supplylimit', 1000000)) url = Node.void('url') share.add_child(url) url.add_child(Node.string('eapass', 'http://some.dummy.net/')) url.add_child(Node.string('arcadefan', 'http://some.dummy.net/')) url.add_child(Node.string('konaminetdx', 'http://some.dummy.net/')) url.add_child(Node.string('konamiid', 'http://some.dummy.net/')) url.add_child(Node.string('eagate', 'http://some.dummy.net/')) self.assertLoopback(root)
def verify_game_save(self, location: str, refid: str, packet: int, block: int, blaster_energy: int) -> None: call = self.call_node() game = Node.void('game_3') call.add_child(game) game.set_attribute('method', 'save') game.set_attribute('ver', '0') game.add_child(Node.string('refid', refid)) game.add_child(Node.string('locid', location)) game.add_child(Node.u8('headphone', 0)) game.add_child(Node.u16('appeal_id', 1001)) game.add_child(Node.u16('comment_id', 0)) game.add_child(Node.s32('music_id', 29)) game.add_child(Node.u8('music_type', 1)) game.add_child(Node.u8('sort_type', 1)) game.add_child(Node.u8('narrow_down', 0)) game.add_child(Node.u8('gauge_option', 0)) game.add_child(Node.u32('earned_gamecoin_packet', packet)) game.add_child(Node.u32('earned_gamecoin_block', block)) item = Node.void('item') game.add_child(item) info = Node.void('info') item.add_child(info) info.add_child(Node.u32('id', 1)) info.add_child(Node.u32('type', 5)) info.add_child(Node.u32('param', 333333376)) info = Node.void('info') item.add_child(info) info.add_child(Node.u32('id', 0)) info.add_child(Node.u32('type', 5)) info.add_child(Node.u32('param', 600)) game.add_child( Node.s32_array( 'hidden_param', [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) game.add_child(Node.s16('skill_name_id', -1)) game.add_child(Node.s32('earned_blaster_energy', blaster_energy)) game.add_child(Node.u32('blaster_count', 0)) printn = Node.void('print') game.add_child(printn) printn.add_child(Node.s32('count', 0)) ea_shop = Node.void('ea_shop') game.add_child(ea_shop) ea_shop.add_child(Node.s32('used_packet_booster', 0)) ea_shop.add_child(Node.s32('used_block_booster', 0)) game.add_child(Node.s8('start_option', 0)) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/game_3")
def verify_player_rb5_player_start(self, refid: str) -> None: call = self.call_node() player = Node.void('player') player.set_attribute('method', 'rb5_player_start') player.add_child(Node.string('rid', refid)) player.add_child(Node.u8_array('ga', [127, 0, 0, 1])) player.add_child(Node.u16('gp', 10573)) player.add_child(Node.u8_array('la', [16, 0, 0, 0])) player.add_child( Node.u8_array( 'pnid', [39, 16, 0, 0, 0, 23, 62, 60, 39, 127, 0, 0, 1, 23, 62, 60])) call.add_child(player) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player/plyid") self.assert_path(resp, "response/player/start_time") self.assert_path(resp, "response/player/event_ctrl") self.assert_path(resp, "response/player/item_lock_ctrl") self.assert_path(resp, "response/player/mycourse_ctrl")
def verify_player22_write(self, ref_id: str, scores: List[Dict[str, Any]]) -> None: call = self.call_node() # Construct node player22 = Node.void('player22') call.add_child(player22) player22.set_attribute('method', 'write') player22.add_child(Node.string('ref_id', value=ref_id)) # Add required children config = Node.void('config') player22.add_child(config) config.add_child(Node.s16('chara', value=1543)) # Add requested scores for score in scores: stage = Node.void('stage') player22.add_child(stage) stage.add_child(Node.s16('no', score['id'])) stage.add_child(Node.u8('sheet', score['chart'])) stage.add_child(Node.u16('clearmedal', score['medal'])) stage.add_child(Node.s32('nscore', score['score'])) # Swap with server resp = self.exchange('', call) self.assert_path(resp, "response/player22/@status")
def verify_playerdata_set(self, ref_id: str, scores: List[Dict[str, Any]]) -> None: call = self.call_node() # Construct node playerdata = Node.void('playerdata') call.add_child(playerdata) playerdata.set_attribute('method', 'set') playerdata.set_attribute('ref_id', ref_id) playerdata.set_attribute('shop_name', '') # Add required children playerdata.add_child(Node.s16('chara', 1543)) # Add requested scores for score in scores: stage = Node.void('stage') playerdata.add_child(stage) stage.add_child(Node.s16('no', score['id'])) stage.add_child(Node.u8('sheet', score['chart'])) stage.add_child( Node.u16('n_data', (score['medal'] << (4 * score['chart'])))) stage.add_child(Node.s32('score', score['score'])) # Swap with server resp = self.exchange('pnm20/playerdata', call) # Verify nodes that cause crashes if they don't exist self.assert_path(resp, "response/playerdata/name") name = resp.child('playerdata').child('name').value if name != self.NAME: raise Exception( f'Invalid name \'{name}\' returned for Ref ID \'{ref_id}\'')
def verify_pcb24_boot(self, loc: str) -> None: call = self.call_node() # Construct node pcb24 = Node.void('pcb24') call.add_child(pcb24) pcb24.set_attribute('method', 'boot') pcb24.add_child(Node.string('loc_id', loc)) pcb24.add_child(Node.u8('loc_type', 0)) pcb24.add_child(Node.string('loc_name', '')) pcb24.add_child(Node.string('country', 'US')) pcb24.add_child(Node.string('region', '.')) pcb24.add_child(Node.s16('pref', 51)) pcb24.add_child(Node.string('customer', '')) pcb24.add_child(Node.string('company', '')) pcb24.add_child(Node.ipv4('gip', '127.0.0.1')) pcb24.add_child(Node.u16('gp', 10011)) pcb24.add_child(Node.string('rom_number', 'M39-JB-G01')) pcb24.add_child(Node.u64('c_drive', 10028228608)) pcb24.add_child(Node.u64('d_drive', 47945170944)) pcb24.add_child(Node.u64('e_drive', 10394677248)) pcb24.add_child(Node.string('etc', '')) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/pcb24/@status")
def verify_game_save(self, location: str, refid: str, packet: int, block: int, blaster_energy: int) -> None: call = self.call_node() game = Node.void('game') call.add_child(game) game.set_attribute('method', 'sv4_save') game.set_attribute('ver', '0') game.add_child(Node.string('refid', refid)) game.add_child(Node.string('locid', location)) game.add_child(Node.u8('headphone', 0)) game.add_child(Node.u16('appeal_id', 1001)) game.add_child(Node.u16('comment_id', 0)) game.add_child(Node.s32('music_id', 29)) game.add_child(Node.u8('music_type', 1)) game.add_child(Node.u8('sort_type', 1)) game.add_child(Node.u8('narrow_down', 0)) game.add_child(Node.u8('gauge_option', 0)) game.add_child(Node.u8('ars_option', 0)) game.add_child(Node.u8('notes_option', 0)) game.add_child(Node.u8('early_late_disp', 0)) game.add_child(Node.s32('draw_adjust', 0)) game.add_child(Node.u8('eff_c_left', 0)) game.add_child(Node.u8('eff_c_right', 1)) game.add_child(Node.u32('earned_gamecoin_packet', packet)) game.add_child(Node.u32('earned_gamecoin_block', block)) item = Node.void('item') game.add_child(item) game.add_child(Node.s16('skill_name_id', 0)) game.add_child(Node.s16('skill_base_id', 0)) game.add_child(Node.s16('skill_name', 0)) game.add_child(Node.s32('earned_blaster_energy', blaster_energy)) game.add_child(Node.u32('blaster_count', 0)) printn = Node.void('print') game.add_child(printn) printn.add_child(Node.s32('count', 0)) ea_shop = Node.void('ea_shop') game.add_child(ea_shop) ea_shop.add_child(Node.s32('used_packet_booster', 0)) ea_shop.add_child(Node.s32('used_block_booster', 0)) game.add_child(Node.s8('start_option', 1)) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/game")
def verify_player23_write( self, ref_id: str, medal: Optional[Dict[str, int]] = None, item: Optional[Dict[str, int]] = None, character: Optional[Dict[str, int]] = None, ) -> None: call = self.call_node() # Construct node player23 = Node.void('player23') call.add_child(player23) player23.set_attribute('method', 'write') player23.add_child(Node.string('ref_id', ref_id)) # Add required children config = Node.void('config') player23.add_child(config) config.add_child(Node.s16('chara', 1543)) if medal is not None: medalnode = Node.void('medal') player23.add_child(medalnode) medalnode.add_child(Node.s16('medal_id', medal['id'])) medalnode.add_child(Node.s16('level', medal['level'])) medalnode.add_child(Node.s32('exp', medal['exp'])) medalnode.add_child(Node.s32('set_count', 0)) medalnode.add_child(Node.s32('get_count', 0)) if item is not None: itemnode = Node.void('item') player23.add_child(itemnode) itemnode.add_child(Node.u8('type', item['type'])) itemnode.add_child(Node.u16('id', item['id'])) itemnode.add_child(Node.u16('param', item['param'])) itemnode.add_child(Node.bool('is_new', False)) if character is not None: chara_param = Node.void('chara_param') player23.add_child(chara_param) chara_param.add_child(Node.u16('chara_id', character['id'])) chara_param.add_child( Node.u16('friendship', character['friendship'])) # Swap with server resp = self.exchange('', call) self.assert_path(resp, "response/player23/@status")
def handle_lobby_read_request(self, request: Node) -> Node: root = Node.void('lobby') # Look up all lobbies matching the criteria specified 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 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.get_int('extid'))) e.add_child(Node.string('pn', profile.get_str('name'))) e.add_child(Node.s32('exp', profile.get_int('exp'))) e.add_child(Node.u8('mg', profile.get_int('mg'))) e.add_child(Node.s32('tid', lobby.get_int('tid'))) e.add_child(Node.string('tn', lobby.get_str('tn'))) 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.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))) limit = limit - 1 return root
def verify_player24_buy(self, ref_id: str, item: Dict[str, int]) -> None: call = self.call_node() # Construct node player24 = Node.void('player24') call.add_child(player24) player24.set_attribute('method', 'buy') player24.add_child(Node.s32('play_id', 0)) player24.add_child(Node.string('ref_id', ref_id)) player24.add_child(Node.u16('id', item['id'])) player24.add_child(Node.u8('type', item['type'])) player24.add_child(Node.u16('param', item['param'])) player24.add_child(Node.s32('lumina', item['points'])) player24.add_child(Node.u16('price', item['price'])) # Swap with server resp = self.exchange('', call) self.assert_path(resp, "response/player24/@status")
def verify_game_save(self, location: str, refid: str, packet: int, block: int, blaster_energy: int, appealcards: List[int]) -> None: call = self.call_node() game = Node.void('game_2') call.add_child(game) game.set_attribute('method', 'save') game.set_attribute('ver', '0') game.add_child(Node.string('refid', refid)) game.add_child(Node.string('locid', location)) game.add_child(Node.u8('headphone', 0)) game.add_child(Node.u8('hispeed', 52)) game.add_child(Node.u16('appeal_id', 1001)) game.add_child(Node.u16('comment_id', 0)) game.add_child(Node.s32('music_id', 29)) game.add_child(Node.u8('music_type', 1)) game.add_child(Node.u8('sort_type', 1)) game.add_child(Node.u8('narrow_down', 0)) game.add_child(Node.u8('gauge_option', 0)) game.add_child(Node.u32('earned_gamecoin_packet', packet)) game.add_child(Node.u32('earned_gamecoin_block', block)) game.add_child(Node.void('item')) appealcard = Node.void('appealcard') game.add_child(appealcard) for card in appealcards: info = Node.void('info') info.add_child(Node.u32('id', card)) info.add_child(Node.u32('count', 0)) appealcard.add_child(info) game.add_child( Node.s32_array( 'hidden_param', [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) game.add_child(Node.s16('skill_name_id', -1)) game.add_child(Node.s32('earned_blaster_energy', blaster_energy)) game.add_child(Node.u32('blaster_count', 0)) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/game_2")
def test_packet1(self) -> Node: root = Node.void('test') root.set_attribute('test', 'test string value') # Regular nodes root.add_child(Node.void('void_node')) root.add_child(Node.s8('s8_node', -1)) root.add_child(Node.u8('u8_node', 245)) root.add_child(Node.s16('s16_node', -8000)) root.add_child(Node.u16('u16_node', 65000)) root.add_child(Node.s32('s32_node', -2000000000)) root.add_child(Node.u32('u32_node', 4000000000)) root.add_child(Node.s64('s64_node', -1234567890000)) root.add_child(Node.u64('u64_node', 1234567890000)) root.add_child(Node.binary('bin_node', b'DEADBEEF')) root.add_child(Node.string('str_node', 'this is a string!')) root.add_child(Node.ipv4('ip4_node', '192.168.1.24')) root.add_child(Node.time('time_node', 1234567890)) root.add_child(Node.float('float_node', 2.5)) root.add_child(Node.fouru8('4u8_node', [0x20, 0x21, 0x22, 0x23])) root.add_child(Node.bool('bool_true_node', True)) root.add_child(Node.bool('bool_false_node', False)) # Array nodes root.add_child(Node.s8_array('s8_array_node', [-1, -2, 3, 4, -5])) root.add_child(Node.u8_array('u8_array_node', [245, 2, 0, 255, 1])) root.add_child(Node.s16_array('s16_array_node', [-8000, 8000])) root.add_child(Node.u16_array('u16_array_node', [65000, 1, 2, 65535])) root.add_child(Node.s32_array('s32_array_node', [-2000000000, -1])) root.add_child(Node.u32_array('u32_array_node', [4000000000, 0, 1, 2])) root.add_child( Node.s64_array('s64_array_node', [-1234567890000, -1, 1, 1337])) root.add_child( Node.u64_array('u64_array_node', [1234567890000, 123, 456, 7890])) root.add_child( Node.time_array('time_array_node', [1234567890, 98765432])) root.add_child( Node.float_array('float_array_node', [2.5, 0.0, 5.0, 20.5])) root.add_child( Node.bool_array('bool_array_node', [False, True, True, False])) # XML escaping escape = Node.string( 'escape_test', '\r\n<testing> & \'thing\' "thing" \r\nthing on new line\r\n ') escape.set_attribute('test', '<testing> & \'thing\' "thing" \r\n thing') root.add_child(escape) # Unicode unicode_node = Node.string('unicode', '今日は') unicode_node.set_attribute('unicode_attr', 'わたし') root.add_child(unicode_node) self.assertLoopback(root)
def handle_game_load_m_request(self, request: Node) -> Node: extid = intish(request.attribute('code')) refid = request.attribute('refid') if extid is not None: # Rival score loading userid = self.data.remote.user.from_extid(self.game, self.version, extid) else: # Self score loading userid = self.data.remote.user.from_refid(self.game, self.version, refid) if userid is not None: scores = self.data.remote.music.get_scores(self.game, self.music_version, userid) else: scores = [] sortedscores: Dict[int, Dict[int, Score]] = {} for score in scores: if score.id not in sortedscores: sortedscores[score.id] = {} sortedscores[score.id][score.chart] = score game = Node.void('game') for song in sortedscores: music = Node.void('music') game.add_child(music) music.set_attribute('reclink', str(song)) for chart in sortedscores[song]: score = sortedscores[song][chart] try: gamechart = self.db_to_game_chart(chart) except KeyError: # Don't support this chart in this game continue gamerank = self.db_to_game_rank(score.data.get_int('rank')) combo_type = self.db_to_game_halo(score.data.get_int('halo')) typenode = Node.void('type') music.add_child(typenode) typenode.set_attribute('diff', str(gamechart)) typenode.add_child(Node.u32('score', score.points)) typenode.add_child(Node.u16('count', score.plays)) typenode.add_child(Node.u8('rank', gamerank)) typenode.add_child(Node.u8('combo_type', combo_type)) # The game optionally receives hard, life8, life4, risky, assist_clear, normal_clear # u8 values too, and saves music scores with these set, but the UI doesn't appear to # do anything with them, so we don't care. return game
def handle_game_area_hiscore_request(self, request: Node) -> Node: shop_area = int(request.attribute('shop_area')) # First, get all users that are in the current shop's area area_users = { uid: prof for (uid, prof) in self.data.local.user.get_all_profiles(self.game, self.version) if prof.get_int('area', 51) == shop_area } # Second, look up records belonging only to those users records = self.data.local.music.get_all_records(self.game, self.music_version, userlist=list(area_users.keys())) # Now, do the same lazy thing as 'hiscore' because I don't want # to think about how to change this knowing that we only pulled # up area records. area_records: Dict[int, Dict[int, Tuple[UserID, Score]]] = {} for (userid, score) in records: if score.id not in area_records: area_records[score.id] = {} area_records[score.id][score.chart] = (userid, score) game = Node.void('game') for song in area_records: music = Node.void('music') game.add_child(music) music.set_attribute('reclink_num', str(song)) for chart in area_records[song]: userid, score = area_records[song][chart] if area_users[userid].get_int('area', 51) != shop_area: # Don't return this, this user isn't in this area continue try: gamechart = self.db_to_game_chart(chart) except KeyError: # Don't support this chart in this game continue gamerank = self.db_to_game_rank(score.data.get_int('rank')) combo_type = self.db_to_game_halo(score.data.get_int('halo')) typenode = Node.void('type') music.add_child(typenode) typenode.set_attribute('diff', str(gamechart)) typenode.add_child(Node.string('name', area_users[userid].get_str('name'))) typenode.add_child(Node.u32('score', score.points)) typenode.add_child(Node.u16('area', area_users[userid].get_int('area', 51))) typenode.add_child(Node.u8('rank', gamerank)) typenode.add_child(Node.u8('combo_type', combo_type)) typenode.add_child(Node.u32('code', area_users[userid].get_int('extid'))) return game
def verify_jbrbcollabo_save(self, refid: str) -> None: call = self.call_node() jbrbcollabo = Node.void('jbrbcollabo') jbrbcollabo.set_attribute('method', 'save') jbrbcollabo.add_child(Node.string('ref_id', refid)) jbrbcollabo.add_child(Node.u16('cre_count', 0)) call.add_child(jbrbcollabo) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/jbrbcollabo")
def handle_game_hiscore_request(self, request: Node) -> Node: # This is almost identical to X3 and above, except X3 added a 'code' field # that isn't present here. In the interest of correctness, keep a separate # implementation here. records = self.data.remote.music.get_all_records(self.game, self.music_version) sortedrecords: Dict[int, Dict[int, Tuple[UserID, Score]]] = {} missing_profiles = [] for (userid, score) in records: if score.id not in sortedrecords: sortedrecords[score.id] = {} sortedrecords[score.id][score.chart] = (userid, score) missing_profiles.append(userid) users = {userid: profile for (userid, profile) in self.get_any_profiles(missing_profiles)} game = Node.void('game') for song in sortedrecords: music = Node.void('music') game.add_child(music) music.set_attribute('reclink_num', str(song)) for chart in sortedrecords[song]: userid, score = sortedrecords[song][chart] try: gamechart = self.db_to_game_chart(chart) except KeyError: # Don't support this chart in this game continue gamerank = self.db_to_game_rank(score.data.get_int('rank')) combo_type = self.db_to_game_halo(score.data.get_int('halo')) typenode = Node.void('type') music.add_child(typenode) typenode.set_attribute('diff', str(gamechart)) typenode.add_child(Node.string('name', users[userid].get_str('name'))) typenode.add_child(Node.u32('score', score.points)) typenode.add_child(Node.u16('area', users[userid].get_int('area', 51))) typenode.add_child(Node.u8('rank', gamerank)) typenode.add_child(Node.u8('combo_type', combo_type)) return game
def verify_player_start(self, refid: str) -> None: call = self.call_node() player = Node.void('player') player.set_attribute('method', 'start') player.add_child(Node.string('rid', refid)) player.add_child(Node.u8_array('ga', [127, 0, 0, 1])) player.add_child(Node.u16('gp', 10573)) player.add_child(Node.u8_array('la', [16, 0, 0, 0])) call.add_child(player) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player/plyid") self.assert_path(resp, "response/player/start_time") self.assert_path(resp, "response/player/event_ctrl") self.assert_path(resp, "response/player/item_lock_ctrl") self.assert_path(resp, "response/player/lincle_link_4") self.assert_path(resp, "response/player/jbrbcollabo") self.assert_path(resp, "response/player/tricolettepark")
def verify_game_save(self, location: str, refid: str, packet: int, block: int, exp: int) -> None: call = self.call_node() game = Node.void('game') call.add_child(game) game.set_attribute('method', 'save') game.set_attribute('refid', refid) game.set_attribute('locid', location) game.set_attribute('ver', '0') game.add_child(Node.u8('headphone', 0)) game.add_child(Node.u8('hispeed', 16)) game.add_child(Node.u16('appeal_id', 19)) game.add_child(Node.u16('frame0', 0)) game.add_child(Node.u16('frame1', 0)) game.add_child(Node.u16('frame2', 0)) game.add_child(Node.u16('frame3', 0)) game.add_child(Node.u16('frame4', 0)) last = Node.void('last') game.add_child(last) last.set_attribute('music_type', '1') last.set_attribute('music_id', '29') last.set_attribute('sort_type', '4') game.add_child(Node.u32('earned_gamecoin_packet', packet)) game.add_child(Node.u32('earned_gamecoin_block', block)) game.add_child(Node.u32('gain_exp', exp)) game.add_child(Node.u32('m_user_cnt', 0)) game.add_child(Node.bool_array('have_item', [False] * 512)) game.add_child(Node.bool_array('have_note', [False] * 512)) tracking = Node.void('tracking') game.add_child(tracking) m0 = Node.void('m0') tracking.add_child(m0) m0.add_child(Node.u8('type', 2)) m0.add_child(Node.u32('id', 5)) m0.add_child(Node.u32('score', 774566)) tracking.add_child(Node.time('p_start', Time.now() - 300)) tracking.add_child(Node.time('p_end', Time.now())) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/game")
def verify_game_entry_s(self) -> int: call = self.call_node() game = Node.void('game') call.add_child(game) game.set_attribute('ver', '0') game.set_attribute('method', 'sv4_entry_s') game.add_child(Node.u8('c_ver', 174)) game.add_child(Node.u8('p_num', 1)) game.add_child(Node.u8('p_rest', 1)) game.add_child(Node.u8('filter', 1)) game.add_child(Node.u32('mid', 492)) game.add_child(Node.u32('sec', 45)) game.add_child(Node.u16('port', 10007)) game.add_child(Node.fouru8('gip', [127, 0, 0, 1])) game.add_child(Node.fouru8('lip', [10, 0, 5, 73])) game.add_child(Node.u8('claim', 0)) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/game/entry_id") return resp.child_value('game/entry_id')
def parse_psmap(data: bytes, offset: str, rootname: str) -> Node: pe = pefile.PE(data=data, fast_load=True) root = Node.void(rootname) base = int(offset, 16) def virtual_to_physical(offset: int) -> int: for section in pe.sections: start = section.VirtualAddress + pe.OPTIONAL_HEADER.ImageBase end = start + section.SizeOfRawData if offset >= start and offset < end: return (offset - start) + section.PointerToRawData raise Exception( f'Couldn\'t find raw offset for virtual offset 0x{offset:08x}') if base >= pe.OPTIONAL_HEADER.ImageBase: # Assume this is virtual base = virtual_to_physical(base) def read_string(offset: int) -> str: # First, translate load offset in memory to disk offset offset = virtual_to_physical(offset) # Now, grab bytes until we're null-terminated bytestring = [] while data[offset] != 0: bytestring.append(data[offset]) offset = offset + 1 # Its shift-jis encoded, so decode it now return bytes(bytestring).decode('shift_jisx0213') # For recursing into nodes saved_root: List[Node] = [] saved_loc: List[int] = [] while True: chunk = data[base:(base + 16)] base = base + 16 (nodetype, mandatory, outoffset, width, nameptr, defaultptr) = struct.unpack('<BBHIII', chunk) if nodetype == 0xFF: # End of nodes, see if we should exit if len(saved_root) == 0: break else: root = saved_root.pop() oldbase = saved_loc.pop() if oldbase is not None: base = oldbase continue # Grab name, get rid of parse numbers name = read_string(nameptr) try: if name.index('#') >= 0: name = name[:name.index('#')] except ValueError: pass if nodetype == 0x00: raise Exception(f'Invalid node type 0x{nodetype:02x}') elif nodetype == 0x01: # This is a void node, so we should handle by recursing node = Node.void(name) root.add_child(node) # Recurse here saved_root.append(root) if defaultptr != 0: saved_loc.append(base) base = virtual_to_physical(defaultptr) else: saved_loc.append(None) root = node continue elif nodetype == 0x02 or nodetype == 0x43: if nodetype < 0x40: elements = int(width / 1) else: elements = width if elements > 1: node = Node.s8_array(name, [-1] * elements) else: node = Node.s8(name, -1) elif nodetype == 0x03 or nodetype == 0x44: if nodetype < 0x40: elements = int(width / 1) else: elements = width if elements > 1: node = Node.u8_array(name, [0] * elements) else: node = Node.u8(name, 0) elif nodetype == 0x04 or nodetype == 0x45: if nodetype < 0x40: elements = int(width / 2) else: elements = width if elements > 1: node = Node.s16_array(name, [-1] * elements) else: node = Node.s16(name, -1) elif nodetype == 0x05 or nodetype == 0x46: if nodetype < 0x40: elements = int(width / 2) else: elements = width if elements > 1: node = Node.u16_array(name, [0] * elements) else: node = Node.u16(name, 0) elif nodetype == 0x06 or nodetype == 0x47: if nodetype < 0x40: elements = int(width / 4) else: elements = width if elements > 1: node = Node.s32_array(name, [-1] * elements) else: node = Node.s32(name, -1) elif nodetype == 0x07 or nodetype == 0x48: if nodetype < 0x40: elements = int(width / 4) else: elements = width if elements > 1: node = Node.u32_array(name, [0] * elements) else: node = Node.u32(name, 0) elif nodetype == 0x08 or nodetype == 0x49: if nodetype < 0x40: elements = int(width / 8) else: elements = width if elements > 1: node = Node.s64_array(name, [-1] * elements) else: node = Node.s64(name, -1) elif nodetype == 0x09 or nodetype == 0x4A: if nodetype < 0x40: elements = int(width / 8) else: elements = width if elements > 1: node = Node.u64_array(name, [0] * elements) else: node = Node.u64(name, 0) elif nodetype == 0x0A: node = Node.string(name, '') elif nodetype == 0x0D: node = Node.float(name, 0.0) elif nodetype == 0x32 or nodetype == 0x6D: if nodetype < 0x40: elements = int(width / 1) else: elements = width if elements > 1: node = Node.bool_array(name, [False] * elements) else: node = Node.bool(name, False) elif nodetype == 0x2F: # Special case, this is an attribute if name[-1] != '@': raise Exception( f'Attribute name {name} expected to end with @') root.set_attribute(name[:-1], '') continue else: raise Exception(f'Unimplemented node type 0x{nodetype:02x}') # Append it root.add_child(node) return root
def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: root = Node.void('player22') # Result root.add_child(Node.s8('result', 0)) # Set up account account = Node.void('account') root.add_child(account) account.add_child(Node.string('name', profile.get_str('name', 'なし'))) account.add_child( Node.string('g_pm_id', ID.format_extid(profile.get_int('extid')))) account.add_child(Node.s8('tutorial', profile.get_int('tutorial', -1))) account.add_child( Node.s16('read_news', profile.get_int('read_news', 0))) account.add_child(Node.s8('staff', 0)) account.add_child(Node.s8('is_conv', 0)) account.add_child(Node.s16('item_type', 0)) account.add_child(Node.s16('item_id', 0)) account.add_child( Node.s16_array('license_data', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1])) # Statistics section and scores section statistics = self.get_play_statistics(userid) last_play_date = statistics.get_int_array('last_play_date', 3) today_play_date = Time.todays_date() if (last_play_date[0] == today_play_date[0] and last_play_date[1] == today_play_date[1] and last_play_date[2] == today_play_date[2]): today_count = statistics.get_int('today_plays', 0) else: today_count = 0 account.add_child(Node.u8('active_fr_num', 0)) # TODO: Hook up rivals code? account.add_child( Node.s16('total_play_cnt', statistics.get_int('total_plays', 0))) account.add_child(Node.s16('today_play_cnt', today_count)) account.add_child( Node.s16('consecutive_days', statistics.get_int('consecutive_days', 0))) account.add_child( Node.s16('total_days', statistics.get_int('total_days', 0))) account.add_child(Node.s16('interval_day', 0)) # Add scores section last_played = [ x[0] for x in self.data.local.music.get_last_played( self.game, self.version, userid, 5) ] most_played = [ x[0] for x in self.data.local.music.get_most_played( self.game, self.version, userid, 10) ] while len(last_played) < 5: last_played.append(-1) while len(most_played) < 10: most_played.append(-1) account.add_child(Node.s16_array('my_best', most_played)) account.add_child(Node.s16_array('latest_music', last_played)) scores = self.data.remote.music.get_scores(self.game, self.version, userid) for score in scores: # Skip any scores for chart types we don't support if score.chart not in [ self.CHART_TYPE_EASY, self.CHART_TYPE_NORMAL, self.CHART_TYPE_HYPER, self.CHART_TYPE_EX, ]: continue points = score.points medal = score.data.get_int('medal') music = Node.void('music') root.add_child(music) music.add_child(Node.s16('music_num', score.id)) music.add_child( Node.u8( 'sheet_num', { self.CHART_TYPE_EASY: self.GAME_CHART_TYPE_EASY, self.CHART_TYPE_NORMAL: self.GAME_CHART_TYPE_NORMAL, self.CHART_TYPE_HYPER: self.GAME_CHART_TYPE_HYPER, self.CHART_TYPE_EX: self.GAME_CHART_TYPE_EX, }[score.chart])) music.add_child(Node.s16('cnt', score.plays)) music.add_child(Node.s32('score', points)) music.add_child( Node.u8( 'clear_type', { self.PLAY_MEDAL_CIRCLE_FAILED: self.GAME_PLAY_MEDAL_CIRCLE_FAILED, self.PLAY_MEDAL_DIAMOND_FAILED: self.GAME_PLAY_MEDAL_DIAMOND_FAILED, self.PLAY_MEDAL_STAR_FAILED: self.GAME_PLAY_MEDAL_STAR_FAILED, self.PLAY_MEDAL_EASY_CLEAR: self.GAME_PLAY_MEDAL_EASY_CLEAR, self.PLAY_MEDAL_CIRCLE_CLEARED: self.GAME_PLAY_MEDAL_CIRCLE_CLEARED, self.PLAY_MEDAL_DIAMOND_CLEARED: self.GAME_PLAY_MEDAL_DIAMOND_CLEARED, self.PLAY_MEDAL_STAR_CLEARED: self.GAME_PLAY_MEDAL_STAR_CLEARED, self.PLAY_MEDAL_CIRCLE_FULL_COMBO: self.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO, self.PLAY_MEDAL_DIAMOND_FULL_COMBO: self.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO, self.PLAY_MEDAL_STAR_FULL_COMBO: self.GAME_PLAY_MEDAL_STAR_FULL_COMBO, self.PLAY_MEDAL_PERFECT: self.GAME_PLAY_MEDAL_PERFECT, }[medal])) music.add_child(Node.s32('old_score', 0)) music.add_child(Node.u8('old_clear_type', 0)) # Net VS section netvs = Node.void('netvs') root.add_child(netvs) netvs.add_child(Node.s32('rank_point', 0)) netvs.add_child(Node.s16_array('record', [0, 0, 0, 0, 0, 0])) netvs.add_child(Node.u8('rank', 0)) netvs.add_child(Node.s8('vs_rank_old', 0)) netvs.add_child(Node.s8_array('ojama_condition', [0] * 74)) netvs.add_child(Node.s8_array('set_ojama', [0, 0, 0])) netvs.add_child(Node.s8_array('set_recommend', [0, 0, 0])) netvs.add_child(Node.u32('netvs_play_cnt', 0)) for dialog in [0, 1, 2, 3, 4, 5]: # TODO: Configure this, maybe? netvs.add_child(Node.string('dialog', f'dialog#{dialog}')) # Set up config config = Node.void('config') root.add_child(config) config.add_child(Node.u8('mode', profile.get_int('mode', 0))) config.add_child(Node.s16('chara', profile.get_int('chara', -1))) config.add_child(Node.s16('music', profile.get_int('music', -1))) config.add_child(Node.u8('sheet', profile.get_int('sheet', 0))) config.add_child(Node.s8('category', profile.get_int('category', 1))) config.add_child( Node.s8('sub_category', profile.get_int('sub_category', -1))) config.add_child( Node.s8('chara_category', profile.get_int('chara_category', -1))) config.add_child(Node.s16('story_id', profile.get_int('story_id', -1))) config.add_child( Node.s16('course_id', profile.get_int('course_id', -1))) config.add_child( Node.s8('course_folder', profile.get_int('course_folder', -1))) config.add_child( Node.s8('story_folder', profile.get_int('story_folder', -1))) config.add_child( Node.s8('ms_banner_disp', profile.get_int('ms_banner_disp'))) config.add_child( Node.s8('ms_down_info', profile.get_int('ms_down_info'))) config.add_child( Node.s8('ms_side_info', profile.get_int('ms_side_info'))) config.add_child( Node.s8('ms_raise_type', profile.get_int('ms_raise_type'))) config.add_child(Node.s8('ms_rnd_type', profile.get_int('ms_rnd_type'))) # Set up option option_dict = profile.get_dict('option') option = Node.void('option') root.add_child(option) option.add_child( Node.s16('hispeed', option_dict.get_int('hispeed', 10))) option.add_child(Node.u8('popkun', option_dict.get_int('popkun', 0))) option.add_child( Node.bool('hidden', option_dict.get_bool('hidden', False))) option.add_child( Node.s16('hidden_rate', option_dict.get_int('hidden_rate', -1))) option.add_child( Node.bool('sudden', option_dict.get_bool('sudden', False))) option.add_child( Node.s16('sudden_rate', option_dict.get_int('sudden_rate', -1))) option.add_child(Node.s8('randmir', option_dict.get_int('randmir', 0))) option.add_child( Node.s8('gauge_type', option_dict.get_int('gauge_type', 0))) option.add_child(Node.u8('ojama_0', option_dict.get_int('ojama_0', 0))) option.add_child(Node.u8('ojama_1', option_dict.get_int('ojama_1', 0))) option.add_child( Node.bool('forever_0', option_dict.get_bool('forever_0', False))) option.add_child( Node.bool('forever_1', option_dict.get_bool('forever_1', False))) option.add_child( Node.bool('full_setting', option_dict.get_bool('full_setting', False))) # Set up info info = Node.void('info') root.add_child(info) info.add_child(Node.u16('ep', profile.get_int('ep', 0))) info.add_child(Node.u16('ap', profile.get_int('ap', 0))) # Set up custom_cate custom_cate = Node.void('custom_cate') root.add_child(custom_cate) custom_cate.add_child(Node.s8('valid', 0)) custom_cate.add_child(Node.s8('lv_min', -1)) custom_cate.add_child(Node.s8('lv_max', -1)) custom_cate.add_child(Node.s8('medal_min', -1)) custom_cate.add_child(Node.s8('medal_max', -1)) custom_cate.add_child(Node.s8('friend_no', -1)) custom_cate.add_child(Node.s8('score_flg', -1)) # Set up customize customize_dict = profile.get_dict('customize') customize = Node.void('customize') root.add_child(customize) customize.add_child( Node.u16('effect', customize_dict.get_int('effect'))) customize.add_child( Node.u16('hukidashi', customize_dict.get_int('hukidashi'))) customize.add_child(Node.u16('font', customize_dict.get_int('font'))) customize.add_child( Node.u16('comment_1', customize_dict.get_int('comment_1'))) customize.add_child( Node.u16('comment_2', customize_dict.get_int('comment_2'))) # Set up achievements achievements = self.data.local.user.get_achievements( self.game, self.version, userid) for achievement in achievements: if achievement.type == 'item': itemtype = achievement.data.get_int('type') param = achievement.data.get_int('param') item = Node.void('item') root.add_child(item) item.add_child(Node.u8('type', itemtype)) item.add_child(Node.u16('id', achievement.id)) item.add_child(Node.u16('param', param)) item.add_child(Node.bool('is_new', False)) elif achievement.type == 'achievement': count = achievement.data.get_int('count') ach_node = Node.void('achievement') root.add_child(ach_node) ach_node.add_child(Node.u8('type', achievement.id)) ach_node.add_child(Node.u32('count', count)) elif achievement.type == 'chara': friendship = achievement.data.get_int('friendship') chara = Node.void('chara_param') root.add_child(chara) chara.add_child(Node.u16('chara_id', achievement.id)) chara.add_child(Node.u16('friendship', friendship)) elif achievement.type == 'story': chapter = achievement.data.get_int('chapter') gauge = achievement.data.get_int('gauge') cleared = achievement.data.get_bool('cleared') clear_chapter = achievement.data.get_int('clear_chapter') story = Node.void('story') root.add_child(story) story.add_child(Node.u32('story_id', achievement.id)) story.add_child(Node.u32('chapter_id', chapter)) story.add_child(Node.u16('gauge_point', gauge)) story.add_child(Node.bool('is_cleared', cleared)) story.add_child(Node.u32('clear_chapter', clear_chapter)) return root
def 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: 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) root = Node.void('player') pdata = Node.void('pdata') root.add_child(pdata) base = Node.void('base') pdata.add_child(base) base.add_child(Node.s32('uid', profile.get_int('extid'))) base.add_child(Node.string('name', profile.get_str('name'))) base.add_child(Node.s16('lv', profile.get_int('lvl'))) base.add_child(Node.s32('exp', profile.get_int('exp'))) base.add_child(Node.s16('mg', profile.get_int('mg'))) base.add_child(Node.s16('ap', profile.get_int('ap'))) base.add_child(Node.s32('flag', profile.get_int('flag'))) 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 con = Node.void('con') pdata.add_child(con) con.add_child(Node.s32('day', today_count)) con.add_child(Node.s32('cnt', statistics.get_int('total_plays'))) con.add_child( Node.s32('last', statistics.get_int('last_play_timestamp'))) con.add_child(Node.s32('now', Time.now())) team = Node.void('team') pdata.add_child(team) team.add_child(Node.s32('id', -1)) team.add_child(Node.string('name', '')) custom = Node.void('custom') customdict = profile.get_dict('custom') pdata.add_child(custom) custom.add_child(Node.u8('bgm_m', customdict.get_int('bgm_m'))) custom.add_child(Node.u8('st_f', customdict.get_int('st_f'))) custom.add_child(Node.u8('st_bg', customdict.get_int('st_bg'))) custom.add_child(Node.u8('st_bg_b', customdict.get_int('st_bg_b'))) custom.add_child(Node.u8('eff_e', customdict.get_int('eff_e'))) custom.add_child(Node.u8('se_s', customdict.get_int('se_s'))) custom.add_child(Node.u8('se_s_v', customdict.get_int('se_s_v'))) 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)) if game_config.get_bool('force_unlock_songs'): songs = { song.id for song in self.data.local.music.get_all_songs( self.game, self.version) } for songid in songs: info = Node.void('info') released.add_child(info) info.add_child(Node.u8('type', 0)) info.add_child(Node.u16('id', songid)) # Scores record = Node.void('record') pdata.add_child(record) for score in scores: rec = Node.void('rec') record.add_child(rec) rec.add_child(Node.u16('mid', score.id)) rec.add_child(Node.u8('ng', score.chart)) rec.add_child( Node.s32('win', score.data.get_dict('stats').get_int('win'))) rec.add_child( Node.s32('lose', score.data.get_dict('stats').get_int('lose'))) rec.add_child( Node.s32('draw', score.data.get_dict('stats').get_int('draw'))) rec.add_child( Node.u8( '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', int(score.data.get_int('achievement_rate') / 10))) rec.add_child(Node.s16('bs', score.points)) rec.add_child(Node.s16('mc', score.data.get_int('combo'))) rec.add_child(Node.s16('bmc', score.data.get_int('miss_count'))) # In original ReflecBeat, the entire battle log was returned for each battle. # We don't support storing all of that info, so don't return anything here. blog = Node.void('blog') pdata.add_child(blog) # Comment (seems unused?) pdata.add_child(Node.string('cmnt', '')) return root