import random import time from typing import Any, Dict, List, Optional from bemani.client.base import BaseClient from bemani.protocol import Node class ReflecBeatGroovinUpper(BaseClient): NAME = 'TEST' def verify_pcb_rb4boot(self, loc: str) -> None: call = self.call_node() pcb = Node.void('pcb') pcb.set_attribute('method', 'rb4boot') pcb.add_child(Node.string('lid', loc)) pcb.add_child(Node.string('rno', 'Unknown')) call.add_child(pcb) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/pcb/sinfo/nm") self.assert_path(resp, "response/pcb/sinfo/cl_enbl") self.assert_path(resp, "response/pcb/sinfo/cl_h") self.assert_path(resp, "response/pcb/sinfo/cl_m") self.assert_path(resp, "response/pcb/sinfo/shop_flag") def verify_pcb_rb4error(self, loc: str) -> None: call = self.call_node() pcb = Node.void('pcb') call.add_child(pcb) pcb.set_attribute('method', 'rb4error') pcb.add_child(Node.string('lid', loc)) pcb.add_child(Node.string('code', 'exception')) pcb.add_child(Node.string('msg', 'exceptionstring')) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/pcb/@status") def verify_info_rb4common(self, loc: str) -> None: call = self.call_node() info = Node.void('info') call.add_child(info) info.set_attribute('method', 'rb4common') info.add_child(Node.string('lid', loc)) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/info/event_ctrl") self.assert_path(resp, "response/info/item_lock_ctrl") self.assert_path(resp, "response/info/shop_score/today") self.assert_path(resp, "response/info/shop_score/yesterday") def verify_info_rb4shop_score_ranking(self, loc: str) -> None: call = self.call_node() info = Node.void('info') call.add_child(info) info.set_attribute('method', 'rb4shop_score_ranking') # Arbitrarily chosen based on the song IDs we send in the # score section below. info.add_child(Node.s16('min', 1)) info.add_child(Node.s16('max', 3)) info.add_child(Node.string('lid', loc)) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/info/shop_score/time") self.assert_path(resp, "response/info/shop_score/data/rank") self.assert_path(resp, "response/info/shop_score/data/music_id") self.assert_path(resp, "response/info/shop_score/data/note_grade") self.assert_path(resp, "response/info/shop_score/data/clear_type") self.assert_path(resp, "response/info/shop_score/data/user_id") self.assert_path(resp, "response/info/shop_score/data/icon_id") self.assert_path(resp, "response/info/shop_score/data/score") self.assert_path(resp, "response/info/shop_score/data/time") self.assert_path(resp, "response/info/shop_score/data/name") def verify_info_rb4ranking(self) -> None: call = self.call_node() info = Node.void('info') info.set_attribute('method', 'rb4ranking') info.add_child(Node.s32('ver', 0)) call.add_child(info) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/info/ver") self.assert_path(resp, "response/info/ranking/weekly/bt") self.assert_path(resp, "response/info/ranking/weekly/et") self.assert_path(resp, "response/info/ranking/weekly/new/d/mid") self.assert_path(resp, "response/info/ranking/weekly/new/d/cnt") self.assert_path(resp, "response/info/ranking/monthly/bt") self.assert_path(resp, "response/info/ranking/monthly/et") self.assert_path(resp, "response/info/ranking/monthly/new/d/mid") self.assert_path(resp, "response/info/ranking/monthly/new/d/cnt") self.assert_path(resp, "response/info/ranking/total/bt") self.assert_path(resp, "response/info/ranking/total/et") self.assert_path(resp, "response/info/ranking/total/new/d/mid") self.assert_path(resp, "response/info/ranking/total/new/d/cnt") def verify_player_rb4start(self, refid: str) -> None: call = self.call_node() player = Node.void('player') player.set_attribute('method', 'rb4start') 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") def verify_player_rb4end(self, refid: str) -> None: call = self.call_node() player = Node.void('player') player.set_attribute('method', 'rb4end') player.add_child(Node.string('rid', refid)) call.add_child(player) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player") def verify_player_rb4total_bestallrank_read(self) -> None: call = self.call_node() player = Node.void('player') player.set_attribute('method', 'rb4total_bestallrank_read') player.add_child(Node.s32('uid', 0)) player.add_child(Node.s32_array('score', [897, 897, 0, 0, 0, 284])) call.add_child(player) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player/score/rank") self.assert_path(resp, "response/player/score/score") self.assert_path(resp, "response/player/score/allrank") def verify_player_rb4selectscore(self, extid: int) -> None: call = self.call_node() player = Node.void('player') player.set_attribute('method', 'rb4selectscore') player.add_child(Node.s32('uid', extid)) player.add_child(Node.s32('music_id', 1)) player.add_child(Node.s32('note_grade', 0)) call.add_child(player) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player/@status") # Verify that we got a score if the extid is nonzero if extid != 0: self.assert_path(resp, "response/player/player_select_score/user_id") self.assert_path(resp, "response/player/player_select_score/name") self.assert_path(resp, "response/player/player_select_score/m_score") self.assert_path(resp, "response/player/player_select_score/m_scoreTime") self.assert_path(resp, "response/player/player_select_score/m_iconID") if resp.child_value('player/player_select_score/name') != self.NAME: raise Exception( f'Invalid name {resp.child_value("player/player_select_score/name")} returned on score read!' ) if resp.child_value('player/player_select_score/user_id') != extid: raise Exception( f'Invalid name {resp.child_value("player/player_select_score/user_id")} returned on score read!' ) def verify_player_rb4succeed(self, refid: str) -> None: call = self.call_node() player = Node.void('player') player.set_attribute('method', 'rb4succeed') player.add_child(Node.string('rid', refid)) call.add_child(player) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player/name") self.assert_path(resp, "response/player/lv") self.assert_path(resp, "response/player/exp") self.assert_path(resp, "response/player/grd") self.assert_path(resp, "response/player/ap") self.assert_path(resp, "response/player/money") self.assert_path(resp, "response/player/released") self.assert_path(resp, "response/player/mrecord") def verify_player_rb4read(self, refid: str, cardid: str, location: str) -> None: call = self.call_node() player = Node.void('player') player.set_attribute('method', 'rb4read') player.add_child(Node.string('rid', refid)) player.add_child(Node.string('lid', location)) player.add_child(Node.s16('ver', 1)) player.add_child(Node.string('card_id', cardid)) player.add_child(Node.s16('card_type', 1)) call.add_child(player) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player/pdata/account/usrid") self.assert_path(resp, "response/player/pdata/account/tpc") self.assert_path(resp, "response/player/pdata/account/dpc") self.assert_path(resp, "response/player/pdata/account/crd") self.assert_path(resp, "response/player/pdata/account/brd") self.assert_path(resp, "response/player/pdata/account/tdc") self.assert_path(resp, "response/player/pdata/account/intrvld") self.assert_path(resp, "response/player/pdata/account/ver") self.assert_path(resp, "response/player/pdata/account/pst") self.assert_path(resp, "response/player/pdata/account/st") self.assert_path(resp, "response/player/pdata/account/debutVer") self.assert_path(resp, "response/player/pdata/base/name") self.assert_path(resp, "response/player/pdata/base/exp") self.assert_path(resp, "response/player/pdata/base/lv") self.assert_path(resp, "response/player/pdata/base/mg") self.assert_path(resp, "response/player/pdata/base/ap") self.assert_path(resp, "response/player/pdata/base/cmnt") self.assert_path(resp, "response/player/pdata/base/uattr") self.assert_path(resp, "response/player/pdata/base/money") self.assert_path(resp, "response/player/pdata/base/tbs") self.assert_path(resp, "response/player/pdata/base/tbs_r") self.assert_path(resp, "response/player/pdata/base/tbgs") self.assert_path(resp, "response/player/pdata/base/tbgs_r") self.assert_path(resp, "response/player/pdata/base/tbms") self.assert_path(resp, "response/player/pdata/base/tbms_r") self.assert_path(resp, "response/player/pdata/base/qe_win") self.assert_path(resp, "response/player/pdata/base/qe_legend") self.assert_path(resp, "response/player/pdata/base/qe2_win") self.assert_path(resp, "response/player/pdata/base/qe2_legend") self.assert_path(resp, "response/player/pdata/base/qe3_win") self.assert_path(resp, "response/player/pdata/base/qe3_legend") self.assert_path(resp, "response/player/pdata/base/mlog") self.assert_path(resp, "response/player/pdata/base/class") self.assert_path(resp, "response/player/pdata/base/class_ar") self.assert_path(resp, "response/player/pdata/base/getrfl") self.assert_path(resp, "response/player/pdata/base/upper_pt") self.assert_path(resp, "response/player/pdata/rival") self.assert_path(resp, "response/player/pdata/stamp") self.assert_path(resp, "response/player/pdata/config") self.assert_path(resp, "response/player/pdata/custom") self.assert_path(resp, "response/player/pdata/released") self.assert_path(resp, "response/player/pdata/announce") self.assert_path(resp, "response/player/pdata/dojo") self.assert_path(resp, "response/player/pdata/player_param") self.assert_path(resp, "response/player/pdata/shop_score") self.assert_path(resp, "response/player/pdata/quest") self.assert_path(resp, "response/player/pdata/derby/is_open") self.assert_path(resp, "response/player/pdata/codebreaking") self.assert_path(resp, "response/player/pdata/iidx_linkage") self.assert_path(resp, "response/player/pdata/pue") if resp.child_value('player/pdata/base/name') != self.NAME: raise Exception(f'Invalid name {resp.child_value("player/pdata/base/name")} returned on profile read!') def verify_player_rb4readscore(self, refid: str, location: str) -> List[Dict[str, int]]: call = self.call_node() player = Node.void('player') call.add_child(player) player.set_attribute('method', 'rb4readscore') player.add_child(Node.string('rid', refid)) player.add_child(Node.string('lid', location)) player.add_child(Node.s16('ver', 1)) # Swap with server resp = self.exchange('', call) scores = [] for child in resp.child('player/pdata/record').children: if child.name != 'rec': continue score = { 'id': child.child_value('mid'), 'chart': child.child_value('ntgrd'), 'clear_type': child.child_value('ct'), 'combo_type': child.child_value('param'), 'achievement_rate': child.child_value('ar'), 'score': child.child_value('scr'), 'miss_count': child.child_value('ms'), } scores.append(score) return scores def verify_player_rb4readepisode(self, extid: int) -> List[Dict[str, int]]: call = self.call_node() player = Node.void('player') call.add_child(player) player.set_attribute('method', 'rb4readepisode') player.add_child(Node.s32('user_id', extid)) player.add_child(Node.s32('limit', 20)) # Swap with server resp = self.exchange('', call) episodes = [] for child in resp.child('player/pdata/episode').children: if child.name != 'info': continue if child.child_value('user_id') != extid: raise Exception(f'Invalid user ID returned {child.child_value("user_id")}') episode = { 'id': child.child_value('type'), 'user': child.child_value('user_id'), 'values': [ child.child_value('value0'), child.child_value('value1'), ], 'text': child.child_value('text'), 'time': child.child_value('time'), } episodes.append(episode) return episodes def verify_player_rb4write( self, refid: str, loc: str, scores: List[Dict[str, int]]=[], episodes: List[Dict[str, Any]]=[], ) -> int: call = self.call_node() player = Node.void('player') call.add_child(player) player.set_attribute('method', 'rb4write') pdata = Node.void('pdata') player.add_child(pdata) account = Node.void('account') pdata.add_child(account) account.add_child(Node.s32('usrid', 0)) account.add_child(Node.s32('plyid', 0)) account.add_child(Node.s32('tpc', 1)) account.add_child(Node.s32('dpc', 1)) account.add_child(Node.s32('crd', 1)) account.add_child(Node.s32('brd', 1)) account.add_child(Node.s32('tdc', 1)) account.add_child(Node.string('rid', refid)) account.add_child(Node.string('lid', loc)) account.add_child(Node.u8('wmode', 0)) account.add_child(Node.u8('gmode', 0)) account.add_child(Node.s16('ver', 1)) account.add_child(Node.bool('pp', False)) account.add_child(Node.bool('ps', False)) account.add_child(Node.s16('pay', 0)) account.add_child(Node.s16('pay_pc', 0)) account.add_child(Node.u64('st', int(time.time() * 1000))) account.add_child(Node.u8('debutVer', 3)) account.add_child(Node.s32('upper_pt', 0)) account.add_child(Node.s32('upper_op', -1)) base = Node.void('base') pdata.add_child(base) base.add_child(Node.string('name', self.NAME)) base.add_child(Node.s32('exp', 0)) base.add_child(Node.s32('lv', 1)) base.add_child(Node.s32('mg', -1)) base.add_child(Node.s32('ap', -1)) base.add_child(Node.s32('money', 0)) base.add_child(Node.bool('is_tut', False)) base.add_child(Node.s32('class', -1)) base.add_child(Node.s32('class_ar', 0)) base.add_child(Node.s32('upper_pt', 0)) stglog = Node.void('stglog') pdata.add_child(stglog) index = 0 for score in scores: log = Node.void('log') stglog.add_child(log) log.add_child(Node.s8('stg', index)) log.add_child(Node.s16('mid', score['id'])) log.add_child(Node.s8('ng', score['chart'])) log.add_child(Node.s8('col', 1)) log.add_child(Node.s8('mt', 0)) log.add_child(Node.s8('rt', 0)) log.add_child(Node.s8('ct', score['clear_type'])) log.add_child(Node.s16('param', score['combo_type'])) log.add_child(Node.s16('grd', 0)) log.add_child(Node.s16('ar', score['achievement_rate'])) log.add_child(Node.s16('sc', score['score'])) log.add_child(Node.s16('jt_jst', 0)) log.add_child(Node.s16('jt_grt', 0)) log.add_child(Node.s16('jt_gd', 0)) log.add_child(Node.s16('jt_ms', score['miss_count'])) log.add_child(Node.s16('jt_jr', 0)) log.add_child(Node.s32('r_uid', 0)) log.add_child(Node.s32('r_plyid', 0)) log.add_child(Node.s8('r_stg', 0)) log.add_child(Node.s8('r_ct', -1)) log.add_child(Node.s16('r_sc', 0)) log.add_child(Node.s16('r_grd', 0)) log.add_child(Node.s16('r_ar', 0)) log.add_child(Node.s8('r_cpuid', -1)) log.add_child(Node.s32('time', int(time.time()))) log.add_child(Node.s8('decide', 0)) log.add_child(Node.s8('hazard', 0)) index = index + 1 episode = Node.void('episode') pdata.add_child(episode) for ep in episodes: info = Node.void('info') episode.add_child(info) info.add_child(Node.s32('user_id', ep['user'])) info.add_child(Node.u8('type', ep['id'])) info.add_child(Node.u16('value0', ep['values'][0])) info.add_child(Node.u16('value1', ep['values'][1])) info.add_child(Node.string('text', ep['text'])) info.add_child(Node.s32('time', ep['time'])) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player/uid") return resp.child_value('player/uid') def verify_lobby_rb4read(self, location: str, extid: int) -> None: call = self.call_node() lobby = Node.void('lobby') lobby.set_attribute('method', 'rb4read') lobby.add_child(Node.s32('uid', extid)) lobby.add_child(Node.s32('plyid', 0)) lobby.add_child(Node.u8('m_grade', 255)) lobby.add_child(Node.string('lid', location)) lobby.add_child(Node.s32('max', 128)) lobby.add_child(Node.s32_array('friend', [])) lobby.add_child(Node.u8('var', 2)) 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") def verify_lobby_rb4entry(self, location: str, extid: int) -> int: call = self.call_node() lobby = Node.void('lobby') lobby.set_attribute('method', 'rb4entry') 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.s32('plyid', 0)) e.add_child(Node.s16('mg', 255)) e.add_child(Node.s32('mopt', 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', 2)) e.add_child(Node.s8('tension', 0)) 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/plyid") self.assert_path(resp, "response/lobby/e/mg") self.assert_path(resp, "response/lobby/e/mopt") 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") self.assert_path(resp, "response/lobby/e/tension") return resp.child_value('lobby/eid') def verify_lobby_rb4delete(self, eid: int) -> None: call = self.call_node() lobby = Node.void('lobby') lobby.set_attribute('method', 'rb4delete') lobby.add_child(Node.s32('eid', eid)) call.add_child(lobby) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/lobby") def verify_rb4pzlcmt_read(self, loc: str, extid: int) -> None: call = self.call_node() info = Node.void('info') info.set_attribute('method', 'rb4pzlcmt_read') info.add_child(Node.s32('uid', extid)) info.add_child(Node.string('lid', loc)) info.add_child(Node.s32('time', 0)) info.add_child(Node.s32('limit', 30)) call.add_child(info) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/info/comment/time") self.assert_path(resp, "response/info/c/uid") self.assert_path(resp, "response/info/c/name") self.assert_path(resp, "response/info/c/icon") self.assert_path(resp, "response/info/c/bln") self.assert_path(resp, "response/info/c/lid") self.assert_path(resp, "response/info/c/pref") self.assert_path(resp, "response/info/c/time") self.assert_path(resp, "response/info/c/comment") self.assert_path(resp, "response/info/c/is_tweet") # Verify we posted our comment earlier found = False for child in resp.child('info').children: if child.name != 'c': continue if child.child_value('uid') == extid: name = child.child_value('name') comment = child.child_value('comment') if name != self.NAME: raise Exception(f'Invalid name \'{name}\' returned for comment!') if comment != 'アメ〜〜!': raise Exception(f'Invalid comment \'{comment}\' returned for comment!') found = True if not found: raise Exception('Comment we posted was not found!') def verify_rb4pzlcmt_write(self, loc: str, extid: int) -> None: call = self.call_node() info = Node.void('info') info.set_attribute('method', 'rb4pzlcmt_write') info.add_child(Node.s32('uid', extid)) info.add_child(Node.string('name', self.NAME)) info.add_child(Node.s16('icon', 0)) info.add_child(Node.s8('bln', 0)) info.add_child(Node.string('lid', loc)) info.add_child(Node.s8('pref', 51)) info.add_child(Node.s32('time', int(time.time()))) info.add_child(Node.string('comment', 'アメ〜〜!')) info.add_child(Node.bool('is_tweet', False)) call.add_child(info) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/info/@status") def verify_player_rbsvLinkageSave(self, refid: str) -> None: call = self.call_node() player = Node.void('player') call.add_child(player) player.set_attribute('method', 'rbsvLinkageSave') player.add_child(Node.string('rid', refid)) # Swap with server resp = self.exchange('', call) # Verify that response is correct self.assert_path(resp, "response/player/before_pk_value") self.assert_path(resp, "response/player/after_pk_value") self.assert_path(resp, "response/player/before_bn_value") self.assert_path(resp, "response/player/after_bn_value") def verify(self, cardid: Optional[str]) -> None: # Verify boot sequence is okay self.verify_services_get( expected_services=[ 'pcbtracker', 'pcbevent', 'local', 'message', 'facility', 'cardmng', 'package', 'posevent', 'pkglist', 'dlstatus', 'eacoin', 'lobby', 'ntp', 'keepalive' ] ) paseli_enabled = self.verify_pcbtracker_alive() self.verify_message_get() self.verify_package_list() self.verify_dlstatus_progress() location = self.verify_facility_get() self.verify_pcbevent_put() self.verify_info_rb4common(location) self.verify_pcb_rb4error(location) self.verify_pcb_rb4boot(location) # Verify card registration and profile lookup if cardid is not None: card = cardid else: card = self.random_card() print(f"Generated random card ID {card} for use.") if cardid is None: self.verify_cardmng_inquire(card, msg_type='unregistered', paseli_enabled=paseli_enabled) ref_id = self.verify_cardmng_getrefid(card) if len(ref_id) != 16: raise Exception(f'Invalid refid \'{ref_id}\' returned when registering card') if ref_id != self.verify_cardmng_inquire(card, msg_type='new', paseli_enabled=paseli_enabled): raise Exception(f'Invalid refid \'{ref_id}\' returned when querying card') # Always get a player start, regardless of new profile or not self.verify_player_rb4start(ref_id) self.verify_player_rb4succeed(ref_id) extid = self.verify_player_rb4write( ref_id, location, [], ) else: print("Skipping new card checks for existing card") ref_id = self.verify_cardmng_inquire(card, msg_type='query', paseli_enabled=paseli_enabled) # Verify pin handling and return card handling self.verify_cardmng_authpass(ref_id, correct=True) self.verify_cardmng_authpass(ref_id, correct=False) if ref_id != self.verify_cardmng_inquire(card, msg_type='query', paseli_enabled=paseli_enabled): raise Exception(f'Invalid refid \'{ref_id}\' returned when querying card') # Verify lobby functionality self.verify_lobby_rb4read(location, extid) eid = self.verify_lobby_rb4entry(location, extid) self.verify_lobby_rb4delete(eid) # Verify puzzle comment read and write self.verify_rb4pzlcmt_write(location, extid) self.verify_rb4pzlcmt_read(location, extid) # Verify Sound Voltex/ReflecBeat collabo save self.verify_player_rbsvLinkageSave(ref_id) # Verify user episode functionalty episodes = self.verify_player_rb4readepisode(extid) if len(episodes) > 0: raise Exception('Existing episodes returned on new card?') dummyepisodes = sorted( [ { 'id': 1, 'user': extid, 'values': [5, 10], 'text': 'test1', 'time': 12345, }, { 'id': 2, 'user': extid, 'values': [6, 11], 'text': 'test2', 'time': 54321, }, ], key=lambda ep: ep['id'], ) self.verify_player_rb4write(ref_id, location, episodes=dummyepisodes) episodes = sorted( self.verify_player_rb4readepisode(extid), key=lambda ep: ep['id'], ) if len(episodes) != len(dummyepisodes): raise Exception('Unexpected number of episodes returned!') for i in range(len(dummyepisodes)): for key in dummyepisodes[i]: if dummyepisodes[i][key] != episodes[i][key]: raise Exception(f'Invalid value {episodes[i][key]} returned for episode {dummyepisodes[i]["id"]} key {key}') # Verify we start with empty scores scores = self.verify_player_rb4readscore(ref_id, location) if len(scores) > 0: raise Exception('Existing scores returned on new card?') if cardid is None: # Verify score saving and updating for phase in [1, 2]: if phase == 1: dummyscores = [ # An okay score on a chart { 'id': 1, 'chart': 1, 'clear_type': 9, 'combo_type': 0, 'achievement_rate': 7543, 'score': 432, 'miss_count': 5, }, # A good score on an easier chart of the same song { 'id': 1, 'chart': 0, 'clear_type': 9, 'combo_type': 1, 'achievement_rate': 9876, 'score': 543, 'miss_count': 0, }, # A bad score on a hard chart { 'id': 3, 'chart': 2, 'clear_type': 9, 'combo_type': 0, 'achievement_rate': 1234, 'score': 123, 'miss_count': 54, }, # A terrible score on an easy chart { 'id': 3, 'chart': 0, 'clear_type': 9, 'combo_type': 0, 'achievement_rate': 1024, 'score': 50, 'miss_count': 90, }, ] if phase == 2: dummyscores = [ # A better score on the same chart { 'id': 1, 'chart': 1, 'clear_type': 9, 'combo_type': 0, 'achievement_rate': 8765, 'score': 469, 'miss_count': 1, }, # A worse score on another same chart { 'id': 1, 'chart': 0, 'clear_type': 9, 'combo_type': 0, 'achievement_rate': 8765, 'score': 432, 'miss_count': 15, 'expected_score': 543, 'expected_clear_type': 9, 'expected_combo_type': 1, 'expected_achievement_rate': 9876, 'expected_miss_count': 0, }, ] self.verify_player_rb4write(ref_id, location, scores=dummyscores) self.verify_player_rb4read(ref_id, card, location) scores = self.verify_player_rb4readscore(ref_id, location) for expected in dummyscores: actual = None for received in scores: if received['id'] == expected['id'] and received['chart'] == expected['chart']: actual = received break if actual is None: raise Exception(f"Didn't find song {expected['id']} chart {expected['chart']} in response!") if 'expected_score' in expected: expected_score = expected['expected_score'] else: expected_score = expected['score'] if 'expected_achievement_rate' in expected: expected_achievement_rate = expected['expected_achievement_rate'] else: expected_achievement_rate = expected['achievement_rate'] if 'expected_clear_type' in expected: expected_clear_type = expected['expected_clear_type'] else: expected_clear_type = expected['clear_type'] if 'expected_combo_type' in expected: expected_combo_type = expected['expected_combo_type'] else: expected_combo_type = expected['combo_type'] if 'expected_miss_count' in expected: expected_miss_count = expected['expected_miss_count'] else: expected_miss_count = expected['miss_count'] if actual['score'] != expected_score: raise Exception(f'Expected a score of \'{expected_score}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got score \'{actual["score"]}\'') if actual['achievement_rate'] != expected_achievement_rate: raise Exception(f'Expected an achievement rate of \'{expected_achievement_rate}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got achievement rate \'{actual["achievement_rate"]}\'') if actual['clear_type'] != expected_clear_type: raise Exception(f'Expected a clear_type of \'{expected_clear_type}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got clear_type \'{actual["clear_type"]}\'') if actual['combo_type'] != expected_combo_type: raise Exception(f'Expected a combo_type of \'{expected_combo_type}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got combo_type \'{actual["combo_type"]}\'') if actual['miss_count'] != expected_miss_count: raise Exception(f'Expected a miss count of \'{expected_miss_count}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got miss count \'{actual["miss_count"]}\'') # Sleep so we don't end up putting in score history on the same second time.sleep(1) else: print("Skipping score checks for existing card") # Verify ending game self.verify_player_rb4end(ref_id) # Verify empty and non-empty select score self.verify_player_rb4selectscore(0) self.verify_player_rb4selectscore(extid) # Verify high score tables and shop rank self.verify_info_rb4ranking() self.verify_info_rb4shop_score_ranking(location) self.verify_player_rb4total_bestallrank_read() # Verify paseli handling if paseli_enabled: print("PASELI enabled for this PCBID, executing PASELI checks") else: print("PASELI disabled for this PCBID, skipping PASELI checks") return sessid, balance = self.verify_eacoin_checkin(card) if balance == 0: print("Skipping PASELI consume check because card has 0 balance") else: self.verify_eacoin_consume(sessid, balance, random.randint(0, balance)) self.verify_eacoin_checkout(sessid)