684 lines
29 KiB
Python
684 lines
29 KiB
Python
import random
|
||
import time
|
||
from typing import Any, Dict, Optional
|
||
|
||
from bemani.client.base import BaseClient
|
||
from bemani.protocol import Node
|
||
|
||
|
||
class PopnMusicKaimeiClient(BaseClient):
|
||
NAME = "TEST"
|
||
|
||
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_common(self, root: str, resp: Node) -> None:
|
||
self.assert_path(resp, f"response/{root}/phase/event_id")
|
||
self.assert_path(resp, f"response/{root}/phase/phase")
|
||
|
||
# Area stuff is not needed unless enabling events.
|
||
# self.assert_path(resp, f"response/{root}/area/area_id")
|
||
# self.assert_path(resp, f"response/{root}/area/end_date")
|
||
# self.assert_path(resp, f"response/{root}/area/medal_id")
|
||
# self.assert_path(resp, f"response/{root}/area/is_limit")
|
||
|
||
self.assert_path(resp, f"response/{root}/choco/choco_id")
|
||
self.assert_path(resp, f"response/{root}/choco/param")
|
||
self.assert_path(resp, f"response/{root}/goods/item_id")
|
||
self.assert_path(resp, f"response/{root}/goods/item_type")
|
||
self.assert_path(resp, f"response/{root}/goods/price")
|
||
self.assert_path(resp, f"response/{root}/goods/goods_type")
|
||
|
||
def verify_info24_common(self, loc: str) -> None:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
info24 = Node.void("info24")
|
||
call.add_child(info24)
|
||
info24.set_attribute("loc_id", loc)
|
||
info24.set_attribute("method", "common")
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
|
||
# Verify that response is correct
|
||
self.__verify_common("info24", resp)
|
||
|
||
def verify_lobby24_getlist(self, loc: str) -> None:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
lobby24 = Node.void("lobby24")
|
||
call.add_child(lobby24)
|
||
lobby24.set_attribute("method", "getList")
|
||
lobby24.add_child(Node.string("location_id", loc))
|
||
lobby24.add_child(Node.u8("net_version", 63))
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
|
||
# Verify that response is correct
|
||
self.assert_path(resp, "response/lobby24/@status")
|
||
|
||
def __verify_profile(self, resp: Node) -> None:
|
||
self.assert_path(resp, "response/player24/account/name")
|
||
self.assert_path(resp, "response/player24/account/g_pm_id")
|
||
self.assert_path(resp, "response/player24/account/tutorial")
|
||
self.assert_path(resp, "response/player24/account/area_id")
|
||
self.assert_path(resp, "response/player24/account/use_navi")
|
||
self.assert_path(resp, "response/player24/account/read_news")
|
||
self.assert_path(resp, "response/player24/account/nice")
|
||
self.assert_path(resp, "response/player24/account/favorite_chara")
|
||
self.assert_path(resp, "response/player24/account/special_area")
|
||
self.assert_path(resp, "response/player24/account/chocolate_charalist")
|
||
self.assert_path(resp, "response/player24/account/chocolate_sp_chara")
|
||
self.assert_path(resp, "response/player24/account/chocolate_pass_cnt")
|
||
self.assert_path(resp, "response/player24/account/chocolate_hon_cnt")
|
||
self.assert_path(resp, "response/player24/account/teacher_setting")
|
||
self.assert_path(resp, "response/player24/account/welcom_pack")
|
||
self.assert_path(resp, "response/player24/account/ranking_node")
|
||
self.assert_path(resp, "response/player24/account/chara_ranking_kind_id")
|
||
self.assert_path(resp, "response/player24/account/navi_evolution_flg")
|
||
self.assert_path(resp, "response/player24/account/ranking_news_last_no")
|
||
self.assert_path(resp, "response/player24/account/power_point")
|
||
self.assert_path(resp, "response/player24/account/player_point")
|
||
self.assert_path(resp, "response/player24/account/power_point_list")
|
||
self.assert_path(resp, "response/player24/account/staff")
|
||
self.assert_path(resp, "response/player24/account/item_type")
|
||
self.assert_path(resp, "response/player24/account/item_id")
|
||
self.assert_path(resp, "response/player24/account/is_conv")
|
||
self.assert_path(resp, "response/player24/account/license_data")
|
||
self.assert_path(resp, "response/player24/account/my_best")
|
||
self.assert_path(resp, "response/player24/account/latest_music")
|
||
self.assert_path(resp, "response/player24/account/total_play_cnt")
|
||
self.assert_path(resp, "response/player24/account/today_play_cnt")
|
||
self.assert_path(resp, "response/player24/account/consecutive_days")
|
||
self.assert_path(resp, "response/player24/account/total_days")
|
||
self.assert_path(resp, "response/player24/account/interval_day")
|
||
self.assert_path(resp, "response/player24/account/active_fr_num")
|
||
self.assert_path(resp, "response/player24/eaappli/relation")
|
||
self.assert_path(resp, "response/player24/info/ep")
|
||
self.assert_path(resp, "response/player24/config")
|
||
self.assert_path(resp, "response/player24/option")
|
||
self.assert_path(resp, "response/player24/custom_cate")
|
||
self.assert_path(resp, "response/player24/navi_data")
|
||
self.assert_path(resp, "response/player24/mission/mission_id")
|
||
self.assert_path(resp, "response/player24/mission/gauge_point")
|
||
self.assert_path(resp, "response/player24/mission/mission_comp")
|
||
self.assert_path(resp, "response/player24/netvs")
|
||
self.assert_path(resp, "response/player24/customize")
|
||
self.assert_path(resp, "response/player24/stamp/stamp_id")
|
||
self.assert_path(resp, "response/player24/stamp/cnt")
|
||
|
||
def verify_player24_read(self, ref_id: str, msg_type: str) -> Dict[str, Dict[int, Dict[str, int]]]:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
player24 = Node.void("player24")
|
||
call.add_child(player24)
|
||
player24.set_attribute("method", "read")
|
||
|
||
player24.add_child(Node.string("ref_id", ref_id))
|
||
player24.add_child(Node.s8("pref", 51))
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
|
||
if msg_type == "new":
|
||
# Verify that response is correct
|
||
self.assert_path(resp, "response/player24/result")
|
||
status = resp.child_value("player24/result")
|
||
if status != 2:
|
||
raise Exception(f"Reference ID '{ref_id}' returned invalid status '{status}'")
|
||
|
||
return {
|
||
"items": {},
|
||
"characters": {},
|
||
"points": {},
|
||
}
|
||
elif msg_type == "query":
|
||
# Verify that the response is correct
|
||
self.__verify_profile(resp)
|
||
|
||
self.assert_path(resp, "response/player24/result")
|
||
status = resp.child_value("player24/result")
|
||
if status != 0:
|
||
raise Exception(f"Reference ID '{ref_id}' returned invalid status '{status}'")
|
||
name = resp.child_value("player24/account/name")
|
||
if name != self.NAME:
|
||
raise Exception(f"Invalid name '{name}' returned for Ref ID '{ref_id}'")
|
||
|
||
# Medals and items
|
||
items: Dict[int, Dict[str, int]] = {}
|
||
charas: Dict[int, Dict[str, int]] = {}
|
||
courses: Dict[int, Dict[str, int]] = {}
|
||
for obj in resp.child("player24").children:
|
||
if obj.name == "item":
|
||
items[obj.child_value("id")] = {
|
||
"type": obj.child_value("type"),
|
||
"param": obj.child_value("param"),
|
||
}
|
||
elif obj.name == "chara_param":
|
||
charas[obj.child_value("chara_id")] = {
|
||
"friendship": obj.child_value("friendship"),
|
||
}
|
||
elif obj.name == "course_data":
|
||
courses[obj.child_value("course_id")] = {
|
||
"clear_type": obj.child_value("clear_type"),
|
||
"clear_rank": obj.child_value("clear_rank"),
|
||
"total_score": obj.child_value("total_score"),
|
||
"count": obj.child_value("update_count"),
|
||
"sheet_num": obj.child_value("sheet_num"),
|
||
}
|
||
|
||
return {
|
||
"items": items,
|
||
"characters": charas,
|
||
"courses": courses,
|
||
"points": {0: {"points": resp.child_value("player24/account/player_point")}},
|
||
}
|
||
else:
|
||
raise Exception(f"Unrecognized message type '{msg_type}'")
|
||
|
||
def verify_player24_read_score(self, ref_id: str) -> Dict[str, Dict[int, Dict[int, int]]]:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
player24 = Node.void("player24")
|
||
call.add_child(player24)
|
||
player24.set_attribute("method", "read_score")
|
||
|
||
player24.add_child(Node.string("ref_id", ref_id))
|
||
player24.add_child(Node.s8("pref", 51))
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
|
||
# Verify defaults
|
||
self.assert_path(resp, "response/player24/@status")
|
||
|
||
# Grab scores
|
||
scores: Dict[int, Dict[int, int]] = {}
|
||
medals: Dict[int, Dict[int, int]] = {}
|
||
ranks: Dict[int, Dict[int, int]] = {}
|
||
for child in resp.child("player24").children:
|
||
if child.name != "music":
|
||
continue
|
||
|
||
musicid = child.child_value("music_num")
|
||
chart = child.child_value("sheet_num")
|
||
score = child.child_value("score")
|
||
medal = child.child_value("clear_type")
|
||
rank = child.child_value("clear_rank")
|
||
|
||
if musicid not in scores:
|
||
scores[musicid] = {}
|
||
if musicid not in medals:
|
||
medals[musicid] = {}
|
||
if musicid not in ranks:
|
||
ranks[musicid] = {}
|
||
|
||
scores[musicid][chart] = score
|
||
medals[musicid][chart] = medal
|
||
ranks[musicid][chart] = rank
|
||
|
||
return {
|
||
"scores": scores,
|
||
"medals": medals,
|
||
"ranks": ranks,
|
||
}
|
||
|
||
def verify_player24_start(self, ref_id: str, loc: str) -> None:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
player24 = Node.void("player24")
|
||
call.add_child(player24)
|
||
player24.set_attribute("loc_id", loc)
|
||
player24.set_attribute("ref_id", ref_id)
|
||
player24.set_attribute("method", "start")
|
||
player24.set_attribute("start_type", "0")
|
||
pcb_card = Node.void("pcb_card")
|
||
player24.add_child(pcb_card)
|
||
pcb_card.add_child(Node.s8("card_enable", 1))
|
||
pcb_card.add_child(Node.s8("card_soldout", 0))
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
|
||
# Verify that response is correct
|
||
self.__verify_common("player24", resp)
|
||
|
||
def verify_player24_update_ranking(self, ref_id: str, loc: str) -> None:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
player24 = Node.void("player24")
|
||
call.add_child(player24)
|
||
player24.set_attribute("method", "update_ranking")
|
||
player24.add_child(Node.s16("pref", 51))
|
||
player24.add_child(Node.string("location_id", loc))
|
||
player24.add_child(Node.string("ref_id", ref_id))
|
||
player24.add_child(Node.string("name", self.NAME))
|
||
player24.add_child(Node.s16("chara_num", 1))
|
||
player24.add_child(Node.s16("course_id", 12345))
|
||
player24.add_child(Node.s32("total_score", 86000))
|
||
player24.add_child(Node.s16("music_num", 1375))
|
||
player24.add_child(Node.u8("sheet_num", 2))
|
||
player24.add_child(Node.u8("clear_type", 7))
|
||
player24.add_child(Node.u8("clear_rank", 5))
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
|
||
# Verify that response is correct
|
||
self.assert_path(resp, "response/player24/all_ranking/name")
|
||
self.assert_path(resp, "response/player24/all_ranking/chara_num")
|
||
self.assert_path(resp, "response/player24/all_ranking/total_score")
|
||
self.assert_path(resp, "response/player24/all_ranking/clear_type")
|
||
self.assert_path(resp, "response/player24/all_ranking/clear_rank")
|
||
self.assert_path(resp, "response/player24/all_ranking/player_count")
|
||
self.assert_path(resp, "response/player24/all_ranking/player_rank")
|
||
|
||
def verify_player24_logout(self, ref_id: str) -> None:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
player24 = Node.void("player24")
|
||
call.add_child(player24)
|
||
player24.set_attribute("ref_id", ref_id)
|
||
player24.set_attribute("method", "logout")
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
|
||
# Verify that response is correct
|
||
self.assert_path(resp, "response/player24/@status")
|
||
|
||
def verify_player24_write(
|
||
self,
|
||
ref_id: str,
|
||
item: Optional[Dict[str, int]] = None,
|
||
character: Optional[Dict[str, int]] = None,
|
||
) -> None:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
player24 = Node.void("player24")
|
||
call.add_child(player24)
|
||
player24.set_attribute("method", "write")
|
||
player24.add_child(Node.string("ref_id", ref_id))
|
||
|
||
# Add required children
|
||
config = Node.void("config")
|
||
player24.add_child(config)
|
||
config.add_child(Node.s16("chara", 1543))
|
||
|
||
if item is not None:
|
||
itemnode = Node.void("item")
|
||
player24.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))
|
||
itemnode.add_child(Node.u64("get_time", 0))
|
||
|
||
if character is not None:
|
||
chara_param = Node.void("chara_param")
|
||
player24.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/player24/@status")
|
||
|
||
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_player24_write_music(self, ref_id: str, score: Dict[str, Any]) -> None:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
player24 = Node.void("player24")
|
||
call.add_child(player24)
|
||
player24.set_attribute("method", "write_music")
|
||
player24.add_child(Node.string("ref_id", ref_id))
|
||
player24.add_child(Node.string("data_id", ref_id))
|
||
player24.add_child(Node.string("name", self.NAME))
|
||
player24.add_child(Node.u8("stage", 0))
|
||
player24.add_child(Node.s16("music_num", score["id"]))
|
||
player24.add_child(Node.u8("sheet_num", score["chart"]))
|
||
player24.add_child(Node.u8("clear_type", score["medal"]))
|
||
player24.add_child(Node.s32("score", score["score"]))
|
||
player24.add_child(Node.s16("combo", 0))
|
||
player24.add_child(Node.s16("cool", 0))
|
||
player24.add_child(Node.s16("great", 0))
|
||
player24.add_child(Node.s16("good", 0))
|
||
player24.add_child(Node.s16("bad", 0))
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
self.assert_path(resp, "response/player24/@status")
|
||
|
||
def verify_player24_new(self, ref_id: str) -> None:
|
||
call = self.call_node()
|
||
|
||
# Construct node
|
||
player24 = Node.void("player24")
|
||
call.add_child(player24)
|
||
player24.set_attribute("method", "new")
|
||
|
||
player24.add_child(Node.string("ref_id", ref_id))
|
||
player24.add_child(Node.string("name", self.NAME))
|
||
player24.add_child(Node.s8("pref", 51))
|
||
|
||
# Swap with server
|
||
resp = self.exchange("", call)
|
||
|
||
# Verify nodes
|
||
self.__verify_profile(resp)
|
||
|
||
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()
|
||
location = self.verify_facility_get()
|
||
self.verify_pcbevent_put()
|
||
self.verify_pcb24_boot(location)
|
||
self.verify_info24_common(location)
|
||
self.verify_lobby24_getlist(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")
|
||
self.verify_player24_read(ref_id, msg_type="new")
|
||
self.verify_player24_new(ref_id)
|
||
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 proper handling of basic stuff
|
||
self.verify_player24_read(ref_id, msg_type="query")
|
||
self.verify_player24_start(ref_id, location)
|
||
self.verify_player24_write(ref_id)
|
||
self.verify_player24_logout(ref_id)
|
||
|
||
if cardid is None:
|
||
# Verify unlocks/story mode work
|
||
unlocks = self.verify_player24_read(ref_id, msg_type="query")
|
||
for item in unlocks["items"]:
|
||
if item in [1592, 1608]:
|
||
# Song unlocks after one play
|
||
continue
|
||
raise Exception("Got nonzero items count on a new card!")
|
||
for _ in unlocks["characters"]:
|
||
raise Exception("Got nonzero characters count on a new card!")
|
||
for _ in unlocks["courses"]:
|
||
raise Exception("Got nonzero course count on a new card!")
|
||
if unlocks["points"][0]["points"] != 300:
|
||
raise Exception("Got wrong default value for points on a new card!")
|
||
|
||
self.verify_player24_write(ref_id, item={"id": 4, "type": 2, "param": 69})
|
||
unlocks = self.verify_player24_read(ref_id, msg_type="query")
|
||
if 4 not in unlocks["items"]:
|
||
raise Exception("Expecting to see item ID 4 in items!")
|
||
if unlocks["items"][4]["type"] != 2:
|
||
raise Exception("Expecting to see item ID 4 to have type 2 in items!")
|
||
if unlocks["items"][4]["param"] != 69:
|
||
raise Exception("Expecting to see item ID 4 to have param 69 in items!")
|
||
|
||
self.verify_player24_write(ref_id, character={"id": 5, "friendship": 420})
|
||
unlocks = self.verify_player24_read(ref_id, msg_type="query")
|
||
if 5 not in unlocks["characters"]:
|
||
raise Exception("Expecting to see chara ID 5 in characters!")
|
||
if unlocks["characters"][5]["friendship"] != 420:
|
||
raise Exception("Expecting to see chara ID 5 to have type 2 in characters!")
|
||
|
||
# Verify purchases work
|
||
self.verify_player24_buy(
|
||
ref_id,
|
||
item={"id": 6, "type": 3, "param": 8, "points": 400, "price": 250},
|
||
)
|
||
unlocks = self.verify_player24_read(ref_id, msg_type="query")
|
||
if 6 not in unlocks["items"]:
|
||
raise Exception("Expecting to see item ID 6 in items!")
|
||
if unlocks["items"][6]["type"] != 3:
|
||
raise Exception("Expecting to see item ID 6 to have type 3 in items!")
|
||
if unlocks["items"][6]["param"] != 8:
|
||
raise Exception("Expecting to see item ID 6 to have param 8 in items!")
|
||
if unlocks["points"][0]["points"] != 150:
|
||
raise Exception(f'Got wrong value for points {unlocks["points"][0]["points"]} after purchase!')
|
||
|
||
# Verify course handling
|
||
self.verify_player24_update_ranking(ref_id, location)
|
||
unlocks = self.verify_player24_read(ref_id, msg_type="query")
|
||
if 12345 not in unlocks["courses"]:
|
||
raise Exception("Expecting to see course ID 12345 in courses!")
|
||
if unlocks["courses"][12345]["clear_type"] != 7:
|
||
raise Exception("Expecting to see item ID 12345 to have clear_type 7 in courses!")
|
||
if unlocks["courses"][12345]["clear_rank"] != 5:
|
||
raise Exception("Expecting to see item ID 12345 to have clear_rank 5 in courses!")
|
||
if unlocks["courses"][12345]["total_score"] != 86000:
|
||
raise Exception("Expecting to see item ID 12345 to have total_score 86000 in courses!")
|
||
if unlocks["courses"][12345]["count"] != 1:
|
||
raise Exception("Expecting to see item ID 12345 to have count 1 in courses!")
|
||
if unlocks["courses"][12345]["sheet_num"] != 2:
|
||
raise Exception("Expecting to see item ID 12345 to have sheet_num 2 in courses!")
|
||
|
||
# Verify score handling
|
||
scores = self.verify_player24_read_score(ref_id)
|
||
for _ in scores["medals"]:
|
||
raise Exception("Got nonzero medals count on a new card!")
|
||
for _ in scores["scores"]:
|
||
raise Exception("Got nonzero scores count on a new card!")
|
||
|
||
for phase in [1, 2]:
|
||
if phase == 1:
|
||
dummyscores = [
|
||
# An okay score on a chart
|
||
{
|
||
"id": 987,
|
||
"chart": 2,
|
||
"medal": 5,
|
||
"score": 76543,
|
||
},
|
||
# A good score on an easier chart of the same song
|
||
{
|
||
"id": 987,
|
||
"chart": 0,
|
||
"medal": 6,
|
||
"score": 99999,
|
||
},
|
||
# A bad score on a hard chart
|
||
{
|
||
"id": 741,
|
||
"chart": 3,
|
||
"medal": 2,
|
||
"score": 45000,
|
||
},
|
||
# A terrible score on an easy chart
|
||
{
|
||
"id": 742,
|
||
"chart": 1,
|
||
"medal": 2,
|
||
"score": 1,
|
||
},
|
||
]
|
||
# Random score to add in
|
||
songid = random.randint(920, 950)
|
||
chartid = random.randint(0, 3)
|
||
score = random.randint(0, 100000)
|
||
medal = random.randint(1, 11)
|
||
dummyscores.append(
|
||
{
|
||
"id": songid,
|
||
"chart": chartid,
|
||
"medal": medal,
|
||
"score": score,
|
||
}
|
||
)
|
||
if phase == 2:
|
||
dummyscores = [
|
||
# A better score on the same chart
|
||
{
|
||
"id": 987,
|
||
"chart": 2,
|
||
"medal": 6,
|
||
"score": 98765,
|
||
},
|
||
# A worse score on another same chart
|
||
{
|
||
"id": 987,
|
||
"chart": 0,
|
||
"medal": 3,
|
||
"score": 12345,
|
||
"expected_score": 99999,
|
||
"expected_medal": 6,
|
||
},
|
||
]
|
||
|
||
for dummyscore in dummyscores:
|
||
self.verify_player24_write_music(ref_id, dummyscore)
|
||
scores = self.verify_player24_read_score(ref_id)
|
||
for expected in dummyscores:
|
||
newscore = scores["scores"][expected["id"]][expected["chart"]]
|
||
newmedal = scores["medals"][expected["id"]][expected["chart"]]
|
||
newrank = scores["ranks"][expected["id"]][expected["chart"]]
|
||
|
||
if "expected_score" in expected:
|
||
expected_score = expected["expected_score"]
|
||
else:
|
||
expected_score = expected["score"]
|
||
if "expected_medal" in expected:
|
||
expected_medal = expected["expected_medal"]
|
||
else:
|
||
expected_medal = expected["medal"]
|
||
|
||
if newscore < 50000:
|
||
expected_rank = 1
|
||
elif newscore < 62000:
|
||
expected_rank = 2
|
||
elif newscore < 72000:
|
||
expected_rank = 3
|
||
elif newscore < 82000:
|
||
expected_rank = 4
|
||
elif newscore < 90000:
|
||
expected_rank = 5
|
||
elif newscore < 95000:
|
||
expected_rank = 6
|
||
elif newscore < 98000:
|
||
expected_rank = 7
|
||
else:
|
||
expected_rank = 8
|
||
|
||
if newscore != expected_score:
|
||
raise Exception(
|
||
f'Expected a score of \'{expected_score}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got score \'{newscore}\''
|
||
)
|
||
if newmedal != expected_medal:
|
||
raise Exception(
|
||
f'Expected a medal of \'{expected_medal}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got medal \'{newmedal}\''
|
||
)
|
||
if newrank != expected_rank:
|
||
raise Exception(
|
||
f'Expected a rank of \'{expected_rank}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got rank \'{newrank}\''
|
||
)
|
||
|
||
# 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 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)
|