1
0
mirror of synced 2024-12-01 00:57:18 +01:00
bemaniutils/bemani/client/iidx/spada.py
Jennifer Taylor 509cb4f0d9 Convert most of the format() string calls to f-strings using libcst.
Exact commands run were:

  python3 -m libcst.tool codemod convert_format_to_fstring.ConvertFormatStringCommand . --no-format
  python3 setup.py build_ext --inplace
2020-01-07 21:29:07 +00:00

781 lines
32 KiB
Python

import random
import time
from typing import Any, Dict, Optional, Tuple
from bemani.client.base import BaseClient
from bemani.protocol import Node
class IIDXSpadaClient(BaseClient):
NAME = 'TEST'
def verify_iidx21shop_getname(self, lid: str) -> str:
call = self.call_node()
# Construct node
IIDX21shop = Node.void('IIDX21shop')
call.add_child(IIDX21shop)
IIDX21shop.set_attribute('method', 'getname')
IIDX21shop.set_attribute('lid', lid)
# Swap with server
resp = self.exchange('', call)
# Verify that response is correct
self.assert_path(resp, "response/IIDX21shop/@opname")
self.assert_path(resp, "response/IIDX21shop/@pid")
self.assert_path(resp, "response/IIDX21shop/@cls_opt")
return resp.child('IIDX21shop').attribute('opname')
def verify_iidx21shop_savename(self, lid: str, name: str) -> None:
call = self.call_node()
# Construct node
IIDX21shop = Node.void('IIDX21shop')
IIDX21shop.set_attribute('lid', lid)
IIDX21shop.set_attribute('pid', '51')
IIDX21shop.set_attribute('method', 'savename')
IIDX21shop.set_attribute('cls_opt', '0')
IIDX21shop.set_attribute('ccode', 'US')
IIDX21shop.set_attribute('opname', name)
IIDX21shop.set_attribute('rcode', '.')
call.add_child(IIDX21shop)
# Swap with server
resp = self.exchange('', call)
# Verify that response is correct
self.assert_path(resp, "response/IIDX21shop")
def verify_iidx21pc_common(self) -> None:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21pc')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('method', 'common')
# Swap with server
resp = self.exchange('', call)
# Verify that response is correct
self.assert_path(resp, "response/IIDX21pc/ir/@beat")
self.assert_path(resp, "response/IIDX21pc/limit/@phase")
self.assert_path(resp, "response/IIDX21pc/boss/@phase")
self.assert_path(resp, "response/IIDX21pc/boss1/@phase")
self.assert_path(resp, "response/IIDX21pc/medal/@phase")
self.assert_path(resp, "response/IIDX21pc/tricolettepark_skip/@phase")
self.assert_path(resp, "response/IIDX21pc/superstar/@phase")
self.assert_path(resp, "response/IIDX21pc/tricolettepark/@open")
self.assert_path(resp, "response/IIDX21pc/cafe/@open")
self.assert_path(resp, "response/IIDX21pc/newsong_another/@open")
self.assert_path(resp, "response/IIDX21pc/vip_pass_black")
def verify_iidx21music_crate(self) -> None:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21music')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('method', 'crate')
# Swap with server
resp = self.exchange('', call)
self.assert_path(resp, "response/IIDX21music")
for child in resp.child("IIDX21music").children:
if child.name != 'c':
raise Exception(f'Invalid node {child} in clear rate response!')
if len(child.value) != 12:
raise Exception(f'Invalid node data {child} in clear rate response!')
for v in child.value:
if v < 0 or v > 101:
raise Exception(f'Invalid clear percent {child} in clear rate response!')
def verify_iidx21shop_getconvention(self, lid: str) -> None:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21shop')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('method', 'getconvention')
IIDX21pc.set_attribute('lid', lid)
# Swap with server
resp = self.exchange('', call)
# Verify that response is correct
self.assert_path(resp, "response/IIDX21shop/valid")
self.assert_path(resp, "response/IIDX21shop/@music_0")
self.assert_path(resp, "response/IIDX21shop/@music_1")
self.assert_path(resp, "response/IIDX21shop/@music_2")
self.assert_path(resp, "response/IIDX21shop/@music_3")
def verify_iidx21pc_visit(self, extid: int, lid: str) -> None:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21pc')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('iidxid', str(extid))
IIDX21pc.set_attribute('lid', lid)
IIDX21pc.set_attribute('method', 'visit')
IIDX21pc.set_attribute('pid', '51')
# Swap with server
resp = self.exchange('', call)
# Verify that response is correct
self.assert_path(resp, "response/IIDX21pc/@aflg")
self.assert_path(resp, "response/IIDX21pc/@anum")
self.assert_path(resp, "response/IIDX21pc/@pflg")
self.assert_path(resp, "response/IIDX21pc/@pnum")
self.assert_path(resp, "response/IIDX21pc/@sflg")
self.assert_path(resp, "response/IIDX21pc/@snum")
def verify_iidx21ranking_getranker(self, lid: str) -> None:
for clid in [0, 1, 2, 3, 4, 5, 6]:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21ranking')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('method', 'getranker')
IIDX21pc.set_attribute('lid', lid)
IIDX21pc.set_attribute('clid', str(clid))
# Swap with server
resp = self.exchange('', call)
# Verify that response is correct
self.assert_path(resp, "response/IIDX21ranking")
def verify_iidx21shop_sentinfo(self, lid: str) -> None:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21shop')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('method', 'sentinfo')
IIDX21pc.set_attribute('lid', lid)
IIDX21pc.set_attribute('bflg', '1')
IIDX21pc.set_attribute('bnum', '2')
IIDX21pc.set_attribute('ioid', '0')
IIDX21pc.set_attribute('tax_phase', '0')
# Swap with server
resp = self.exchange('', call)
# Verify that response is correct
self.assert_path(resp, "response/IIDX21shop")
def verify_iidx21pc_get(self, ref_id: str, card_id: str, lid: str) -> Dict[str, Any]:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21pc')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('rid', ref_id)
IIDX21pc.set_attribute('did', ref_id)
IIDX21pc.set_attribute('pid', '51')
IIDX21pc.set_attribute('lid', lid)
IIDX21pc.set_attribute('cid', card_id)
IIDX21pc.set_attribute('method', 'get')
IIDX21pc.set_attribute('ctype', '1')
# Swap with server
resp = self.exchange('', call)
# Verify that the response is correct
self.assert_path(resp, "response/IIDX21pc/pcdata/@name")
self.assert_path(resp, "response/IIDX21pc/pcdata/@pid")
self.assert_path(resp, "response/IIDX21pc/pcdata/@id")
self.assert_path(resp, "response/IIDX21pc/pcdata/@idstr")
self.assert_path(resp, "response/IIDX21pc/packinfo")
self.assert_path(resp, "response/IIDX21pc/deller")
self.assert_path(resp, "response/IIDX21pc/secret/flg1")
self.assert_path(resp, "response/IIDX21pc/secret/flg2")
self.assert_path(resp, "response/IIDX21pc/secret/flg3")
self.assert_path(resp, "response/IIDX21pc/achievements/trophy")
self.assert_path(resp, "response/IIDX21pc/skin")
self.assert_path(resp, "response/IIDX21pc/grade")
self.assert_path(resp, "response/IIDX21pc/rlist")
self.assert_path(resp, "response/IIDX21pc/step/album")
self.assert_path(resp, "response/IIDX21pc/favorite/sp_mlist")
self.assert_path(resp, "response/IIDX21pc/favorite/sp_clist")
self.assert_path(resp, "response/IIDX21pc/favorite/dp_mlist")
self.assert_path(resp, "response/IIDX21pc/favorite/dp_clist")
name = resp.child('IIDX21pc/pcdata').attribute('name')
if name != self.NAME:
raise Exception(f'Invalid name \'{name}\' returned for Ref ID \'{ref_id}\'')
return {
'extid': int(resp.child('IIDX21pc/pcdata').attribute('id')),
'sp_dan': int(resp.child('IIDX21pc/grade').attribute('sgid')),
'dp_dan': int(resp.child('IIDX21pc/grade').attribute('dgid')),
'deller': int(resp.child('IIDX21pc/deller').attribute('deller')),
}
def verify_iidx21music_getrank(self, extid: int) -> Dict[int, Dict[int, Dict[str, int]]]:
scores: Dict[int, Dict[int, Dict[str, int]]] = {}
for cltype in [0, 1]: # singles, doubles
call = self.call_node()
# Construct node
IIDX21music = Node.void('IIDX21music')
call.add_child(IIDX21music)
IIDX21music.set_attribute('method', 'getrank')
IIDX21music.set_attribute('iidxid', str(extid))
IIDX21music.set_attribute('cltype', str(cltype))
# Swap with server
resp = self.exchange('', call)
self.assert_path(resp, "response/IIDX21music/style")
if int(resp.child('IIDX21music/style').attribute('type')) != cltype:
raise Exception('Returned wrong clear type for IIDX21music.getrank!')
for child in resp.child('IIDX21music').children:
if child.name == 'm':
if child.value[0] != -1:
raise Exception('Got non-self score back when requesting only our scores!')
music_id = child.value[1]
normal_clear_status = child.value[2]
hyper_clear_status = child.value[3]
another_clear_status = child.value[4]
normal_ex_score = child.value[5]
hyper_ex_score = child.value[6]
another_ex_score = child.value[7]
normal_miss_count = child.value[8]
hyper_miss_count = child.value[9]
another_miss_count = child.value[10]
if cltype == 0:
normal = 0
hyper = 1
another = 2
else:
normal = 3
hyper = 4
another = 5
if music_id not in scores:
scores[music_id] = {}
scores[music_id][normal] = {
'clear_status': normal_clear_status,
'ex_score': normal_ex_score,
'miss_count': normal_miss_count,
}
scores[music_id][hyper] = {
'clear_status': hyper_clear_status,
'ex_score': hyper_ex_score,
'miss_count': hyper_miss_count,
}
scores[music_id][another] = {
'clear_status': another_clear_status,
'ex_score': another_ex_score,
'miss_count': another_miss_count,
}
elif child.name == 'b':
music_id = child.value[0]
clear_status = child.value[1]
scores[music_id][6] = {
'clear_status': clear_status,
'ex_score': -1,
'miss_count': -1,
}
return scores
def verify_iidx21pc_save(self, extid: int, card: str, lid: str) -> None:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21pc')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('s_disp_judge', '1')
IIDX21pc.set_attribute('mode', '6')
IIDX21pc.set_attribute('pmode', '0')
IIDX21pc.set_attribute('method', 'save')
IIDX21pc.set_attribute('s_sorttype', '0')
IIDX21pc.set_attribute('s_exscore', '0')
IIDX21pc.set_attribute('d_notes', '0.000000')
IIDX21pc.set_attribute('gpos', '0')
IIDX21pc.set_attribute('s_gno', '8')
IIDX21pc.set_attribute('s_hispeed', '5.771802')
IIDX21pc.set_attribute('s_judge', '0')
IIDX21pc.set_attribute('d_timing', '0')
IIDX21pc.set_attribute('rtype', '0')
IIDX21pc.set_attribute('d_largejudge', '0')
IIDX21pc.set_attribute('d_lift', '60')
IIDX21pc.set_attribute('s_pace', '0')
IIDX21pc.set_attribute('d_exscore', '0')
IIDX21pc.set_attribute('d_sdtype', '0')
IIDX21pc.set_attribute('s_opstyle', '1')
IIDX21pc.set_attribute('s_achi', '449')
IIDX21pc.set_attribute('s_largejudge', '0')
IIDX21pc.set_attribute('d_gno', '0')
IIDX21pc.set_attribute('s_lift', '60')
IIDX21pc.set_attribute('s_notes', '31.484070')
IIDX21pc.set_attribute('d_tune', '0')
IIDX21pc.set_attribute('d_sdlen', '0')
IIDX21pc.set_attribute('d_achi', '4')
IIDX21pc.set_attribute('d_opstyle', '0')
IIDX21pc.set_attribute('sp_opt', '8208')
IIDX21pc.set_attribute('iidxid', str(extid))
IIDX21pc.set_attribute('lid', lid)
IIDX21pc.set_attribute('s_judgeAdj', '0')
IIDX21pc.set_attribute('s_tune', '3')
IIDX21pc.set_attribute('s_sdtype', '1')
IIDX21pc.set_attribute('s_gtype', '2')
IIDX21pc.set_attribute('d_judge', '0')
IIDX21pc.set_attribute('cid', card)
IIDX21pc.set_attribute('cltype', '0')
IIDX21pc.set_attribute('ctype', '1')
IIDX21pc.set_attribute('bookkeep', '0')
IIDX21pc.set_attribute('d_hispeed', '0.000000')
IIDX21pc.set_attribute('d_pace', '0')
IIDX21pc.set_attribute('d_judgeAdj', '0')
IIDX21pc.set_attribute('s_timing', '1')
IIDX21pc.set_attribute('d_disp_judge', '0')
IIDX21pc.set_attribute('s_sdlen', '121')
IIDX21pc.set_attribute('dp_opt2', '0')
IIDX21pc.set_attribute('d_gtype', '0')
IIDX21pc.set_attribute('d_sorttype', '0')
IIDX21pc.set_attribute('dp_opt', '0')
pyramid = Node.void('pyramid')
IIDX21pc.add_child(pyramid)
pyramid.set_attribute('point', '290')
destiny_catharsis = Node.void('destiny_catharsis')
IIDX21pc.add_child(destiny_catharsis)
destiny_catharsis.set_attribute('point', '290')
bemani_summer_collabo = Node.void('bemani_summer_collabo')
IIDX21pc.add_child(bemani_summer_collabo)
bemani_summer_collabo.set_attribute('point', '290')
deller = Node.void('deller')
IIDX21pc.add_child(deller)
deller.set_attribute('deller', '150')
# Swap with server
resp = self.exchange('', call)
self.assert_path(resp, "response/IIDX21pc")
def verify_iidx21music_reg(self, extid: int, lid: str, score: Dict[str, Any]) -> None:
call = self.call_node()
# Construct node
IIDX21music = Node.void('IIDX21music')
call.add_child(IIDX21music)
IIDX21music.set_attribute('convid', '-1')
IIDX21music.set_attribute('iidxid', str(extid))
IIDX21music.set_attribute('pgnum', str(score['pgnum']))
IIDX21music.set_attribute('pid', '51')
IIDX21music.set_attribute('rankside', '1')
IIDX21music.set_attribute('cflg', str(score['clear_status']))
IIDX21music.set_attribute('method', 'reg')
IIDX21music.set_attribute('gnum', str(score['gnum']))
IIDX21music.set_attribute('clid', str(score['chart']))
IIDX21music.set_attribute('mnum', str(score['mnum']))
IIDX21music.set_attribute('is_death', '0')
IIDX21music.set_attribute('theory', '0')
IIDX21music.set_attribute('shopconvid', lid)
IIDX21music.set_attribute('mid', str(score['id']))
IIDX21music.set_attribute('shopflg', '1')
IIDX21music.add_child(Node.binary('ghost', bytes([1] * 64)))
# Swap with server
resp = self.exchange('', call)
self.assert_path(resp, "response/IIDX21music/shopdata/@rank")
self.assert_path(resp, "response/IIDX21music/ranklist/data")
def verify_iidx21music_appoint(self, extid: int, musicid: int, chart: int) -> Tuple[int, bytes]:
call = self.call_node()
# Construct node
IIDX21music = Node.void('IIDX21music')
call.add_child(IIDX21music)
IIDX21music.set_attribute('clid', str(chart))
IIDX21music.set_attribute('method', 'appoint')
IIDX21music.set_attribute('ctype', '0')
IIDX21music.set_attribute('iidxid', str(extid))
IIDX21music.set_attribute('subtype', '')
IIDX21music.set_attribute('mid', str(musicid))
# Swap with server
resp = self.exchange('', call)
self.assert_path(resp, "response/IIDX21music/mydata/@score")
return (
int(resp.child('IIDX21music/mydata').attribute('score')),
resp.child_value('IIDX21music/mydata'),
)
def verify_iidx21pc_reg(self, ref_id: str, card_id: str, lid: str) -> int:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21pc')
call.add_child(IIDX21pc)
IIDX21pc.set_attribute('lid', lid)
IIDX21pc.set_attribute('pid', '51')
IIDX21pc.set_attribute('method', 'reg')
IIDX21pc.set_attribute('cid', card_id)
IIDX21pc.set_attribute('did', ref_id)
IIDX21pc.set_attribute('rid', ref_id)
IIDX21pc.set_attribute('name', self.NAME)
# Swap with server
resp = self.exchange('', call)
# Verify nodes that cause crashes if they don't exist
self.assert_path(resp, "response/IIDX21pc/@id")
self.assert_path(resp, "response/IIDX21pc/@id_str")
return int(resp.child('IIDX21pc').attribute('id'))
def verify_iidx21pc_playstart(self) -> None:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21pc')
IIDX21pc.set_attribute('method', 'playstart')
IIDX21pc.set_attribute('side', '1')
call.add_child(IIDX21pc)
# Swap with server
resp = self.exchange('', call)
# Verify nodes that cause crashes if they don't exist
self.assert_path(resp, "response/IIDX21pc")
def verify_iidx21music_play(self, score: Dict[str, int]) -> None:
call = self.call_node()
# Construct node
IIDX21music = Node.void('IIDX21music')
IIDX21music.set_attribute('opt', '64')
IIDX21music.set_attribute('clid', str(score['chart']))
IIDX21music.set_attribute('mid', str(score['id']))
IIDX21music.set_attribute('gnum', str(score['gnum']))
IIDX21music.set_attribute('cflg', str(score['clear_status']))
IIDX21music.set_attribute('pgnum', str(score['pgnum']))
IIDX21music.set_attribute('pid', '51')
IIDX21music.set_attribute('method', 'play')
call.add_child(IIDX21music)
# Swap with server
resp = self.exchange('', call)
# Verify nodes that cause crashes if they don't exist
self.assert_path(resp, "response/IIDX21music/@clid")
self.assert_path(resp, "response/IIDX21music/@crate")
self.assert_path(resp, "response/IIDX21music/@frate")
self.assert_path(resp, "response/IIDX21music/@mid")
def verify_iidx21pc_playend(self) -> None:
call = self.call_node()
# Construct node
IIDX21pc = Node.void('IIDX21pc')
IIDX21pc.set_attribute('cltype', '0')
IIDX21pc.set_attribute('bookkeep', '0')
IIDX21pc.set_attribute('mode', '1')
IIDX21pc.set_attribute('method', 'playend')
call.add_child(IIDX21pc)
# Swap with server
resp = self.exchange('', call)
# Verify nodes that cause crashes if they don't exist
self.assert_path(resp, "response/IIDX21pc")
def verify_iidx21music_breg(self, iidxid: int, score: Dict[str, int]) -> None:
call = self.call_node()
# Construct node
IIDX21music = Node.void('IIDX21music')
IIDX21music.set_attribute('gnum', str(score['gnum']))
IIDX21music.set_attribute('iidxid', str(iidxid))
IIDX21music.set_attribute('mid', str(score['id']))
IIDX21music.set_attribute('method', 'breg')
IIDX21music.set_attribute('pgnum', str(score['pgnum']))
IIDX21music.set_attribute('cflg', str(score['clear_status']))
call.add_child(IIDX21music)
# Swap with server
resp = self.exchange('', call)
# Verify nodes that cause crashes if they don't exist
self.assert_path(resp, "response/IIDX21music")
def verify_iidx21grade_raised(self, iidxid: int, shop_name: str, dantype: str) -> None:
call = self.call_node()
# Construct node
IIDX21grade = Node.void('IIDX21grade')
IIDX21grade.set_attribute('opname', shop_name)
IIDX21grade.set_attribute('is_mirror', '0')
IIDX21grade.set_attribute('oppid', '51')
IIDX21grade.set_attribute('achi', '50')
IIDX21grade.set_attribute('cflg', '4' if dantype == 'sp' else '3')
IIDX21grade.set_attribute('gid', '5')
IIDX21grade.set_attribute('iidxid', str(iidxid))
IIDX21grade.set_attribute('gtype', '0' if dantype == 'sp' else '1')
IIDX21grade.set_attribute('is_ex', '0')
IIDX21grade.set_attribute('pside', '0')
IIDX21grade.set_attribute('method', 'raised')
call.add_child(IIDX21grade)
# Swap with server
resp = self.exchange('', call)
# Verify nodes that cause crashes if they don't exist
self.assert_path(resp, "response/IIDX21grade/@pnum")
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_package_list()
self.verify_message_get()
lid = self.verify_facility_get()
self.verify_pcbevent_put()
self.verify_iidx21shop_getname(lid)
self.verify_iidx21pc_common()
self.verify_iidx21music_crate()
self.verify_iidx21shop_getconvention(lid)
self.verify_iidx21ranking_getranker(lid)
self.verify_iidx21shop_sentinfo(lid)
# 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')
self.verify_iidx21pc_reg(ref_id, card, lid)
self.verify_iidx21pc_get(ref_id, card, lid)
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')
if cardid is None:
# Verify score handling
profile = self.verify_iidx21pc_get(ref_id, card, lid)
if profile['sp_dan'] != -1:
raise Exception('Somehow has SP DAN ranking on new profile!')
if profile['dp_dan'] != -1:
raise Exception('Somehow has DP DAN ranking on new profile!')
if profile['deller'] != 0:
raise Exception('Somehow has deller on new profile!')
scores = self.verify_iidx21music_getrank(profile['extid'])
if len(scores.keys()) > 0:
raise Exception('Somehow have scores on a new profile!')
for phase in [1, 2]:
if phase == 1:
dummyscores = [
# An okay score on a chart
{
'id': 1000,
'chart': 2,
'clear_status': 4,
'pgnum': 123,
'gnum': 123,
'mnum': 5,
},
# A good score on an easier chart of the same song
{
'id': 1000,
'chart': 0,
'clear_status': 7,
'pgnum': 246,
'gnum': 0,
'mnum': 0,
},
# A bad score on a hard chart
{
'id': 1003,
'chart': 2,
'clear_status': 1,
'pgnum': 10,
'gnum': 20,
'mnum': 50,
},
# A terrible score on an easy chart
{
'id': 1003,
'chart': 0,
'clear_status': 1,
'pgnum': 2,
'gnum': 5,
'mnum': 75,
},
]
if phase == 2:
dummyscores = [
# A better score on the same chart
{
'id': 1000,
'chart': 2,
'clear_status': 5,
'pgnum': 234,
'gnum': 234,
'mnum': 3,
},
# A worse score on another same chart
{
'id': 1000,
'chart': 0,
'clear_status': 4,
'pgnum': 123,
'gnum': 123,
'mnum': 35,
'expected_clear_status': 7,
'expected_ex_score': 492,
'expected_miss_count': 0,
},
]
for dummyscore in dummyscores:
self.verify_iidx21music_reg(profile['extid'], lid, dummyscore)
self.verify_iidx21pc_visit(profile['extid'], lid)
self.verify_iidx21pc_save(profile['extid'], card, lid)
scores = self.verify_iidx21music_getrank(profile['extid'])
for score in dummyscores:
data = scores.get(score['id'], {}).get(score['chart'], None)
if data is None:
raise Exception(f'Expected to get score back for song {score["id"]} chart {score["chart"]}!')
if 'expected_ex_score' in score:
expected_score = score['expected_ex_score']
else:
expected_score = (score['pgnum'] * 2) + score['gnum']
if 'expected_clear_status' in score:
expected_clear_status = score['expected_clear_status']
else:
expected_clear_status = score['clear_status']
if 'expected_miss_count' in score:
expected_miss_count = score['expected_miss_count']
else:
expected_miss_count = score['mnum']
if data['ex_score'] != expected_score:
raise Exception(f'Expected a score of \'{expected_score}\' for song \'{score["id"]}\' chart \'{score["chart"]}\' but got score \'{data["ex_score"]}\'')
if data['clear_status'] != expected_clear_status:
raise Exception(f'Expected a clear status of \'{expected_clear_status}\' for song \'{score["id"]}\' chart \'{score["chart"]}\' but got clear status \'{data["clear_status"]}\'')
if data['miss_count'] != expected_miss_count:
raise Exception(f'Expected a miss count of \'{expected_miss_count}\' for song \'{score["id"]}\' chart \'{score["chart"]}\' but got miss count \'{data["miss_count"]}\'')
# Verify we can fetch our own ghost
ex_score, ghost = self.verify_iidx21music_appoint(profile['extid'], score['id'], score['chart'])
if ex_score != expected_score:
raise Exception(f'Expected a score of \'{expected_score}\' for song \'{score["id"]}\' chart \'{score["chart"]}\' but got score \'{data["ex_score"]}\'')
if len(ghost) != 64:
raise Exception(f'Wrong ghost length {len(ghost)} for ghost!')
for g in ghost:
if g != 0x01:
raise Exception(f'Got back wrong ghost data for song \'{score["id"]}\' chart \'{score["chart"]}\'')
# Sleep so we don't end up putting in score history on the same second
time.sleep(1)
# Verify that a player without a card can play
self.verify_iidx21pc_playstart()
self.verify_iidx21music_play({
'id': 1000,
'chart': 2,
'clear_status': 4,
'pgnum': 123,
'gnum': 123,
})
self.verify_iidx21pc_playend()
# Verify shop name change setting
self.verify_iidx21shop_savename(lid, 'newname1')
newname = self.verify_iidx21shop_getname(lid)
if newname != 'newname1':
raise Exception('Invalid shop name returned after change!')
self.verify_iidx21shop_savename(lid, 'newname2')
newname = self.verify_iidx21shop_getname(lid)
if newname != 'newname2':
raise Exception('Invalid shop name returned after change!')
# Verify beginner score saving
self.verify_iidx21music_breg(profile['extid'], {
'id': 1000,
'clear_status': 4,
'pgnum': 123,
'gnum': 123,
})
scores = self.verify_iidx21music_getrank(profile['extid'])
if 1000 not in scores:
raise Exception(f'Didn\'t get expected scores back for song {1000} beginner chart!')
if 6 not in scores[1000]:
raise Exception(f'Didn\'t get beginner score back for song {1000}!')
if scores[1000][6] != {'clear_status': 4, 'ex_score': -1, 'miss_count': -1}:
raise Exception('Didn\'t get correct status back from beginner save!')
# Verify DAN score saving and loading
self.verify_iidx21grade_raised(profile['extid'], newname, 'sp')
self.verify_iidx21grade_raised(profile['extid'], newname, 'dp')
profile = self.verify_iidx21pc_get(ref_id, card, lid)
if profile['sp_dan'] != 5:
raise Exception('Got wrong DAN score back for SP!')
if profile['dp_dan'] != 5:
raise Exception('Got wrong DAN score back for DP!')
else:
print("Skipping score checks for existing card")
# 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)