diff --git a/titles/diva/base.py b/titles/diva/base.py index 447dd15..120165d 100644 --- a/titles/diva/base.py +++ b/titles/diva/base.py @@ -399,27 +399,6 @@ class DivaBase: if profile is None: return f"&ps_result=-3" - else: - response = "&ps_result=1" - response += "&accept_idx=100" - response += "&nblss_ltt_stts=-1" - response += "&nblss_ltt_tckt=-1" - response += "&nblss_ltt_is_opn=-1" - response += f"&pd_id={data['aime_id']}" - response += f"&player_name={profile['player_name']}" - response += f"&sort_kind={profile['player_name']}" - response += f"&lv_efct_id={profile['lv_efct_id']}" - response += f"&lv_plt_id={profile['lv_plt_id']}" - response += f"&lv_str={profile['lv_str']}" - response += f"&lv_num={profile['lv_num']}" - response += f"&lv_pnt={profile['lv_pnt']}" - response += f"&vcld_pts={profile['vcld_pts']}" - response += f"&skn_eqp={profile['use_pv_skn_eqp']}" - response += f"&btn_se_eqp={profile['btn_se_eqp']}" - response += f"&sld_se_eqp={profile['sld_se_eqp']}" - response += f"&chn_sld_se_eqp={profile['chn_sld_se_eqp']}" - response += f"&sldr_tch_se_eqp={profile['sldr_tch_se_eqp']}" - response += f"&passwd_stat={profile['passwd_stat']}" profile_dict = profile._asdict() profile_dict.pop("id") @@ -436,10 +415,13 @@ class DivaBase: return resp.make() def handle_registration_request(self, data: bytes) -> str: - self.data.profile.create_profile( - self.version, data["aime_id"], data["player_name"] + req = RegisterRequest(data) + pd_id = self.data.profile.create_profile( + self.version, req.aime_id, req.player_name ) - return f"&cd_adm_result=1&pd_id={data['aime_id']}" + if pd_id is None: + return "&cd_adm_result=-1" + return RegisterResponse(req.cmd, req.req_id, req.aime_id).make() def handle_start_request(self, data: bytes) -> str: req = StartRequest(data) @@ -453,41 +435,49 @@ class DivaBase: # generate the mdl_have string if "unlock_all_modules" is disabled if not self.game_config.mods.unlock_all_modules: resp.mdl_have = self.data.module.get_modules_have_string( - data["pd_id"], self.version + req.pd_id, self.version ) # generate the cstmz_itm_have string if "unlock_all_items" is disabled if not self.game_config.mods.unlock_all_items: resp.cstmz_itm_have = self.data.customize.get_customize_items_have_string( - data["pd_id"], self.version + req.pd_id, self.version ) + """ + resp.hp_vol = profile['hp_vol'] + resp.btn_se_vol = profile['btn_se_vol'] + resp.btn_se_vol2 = profile['btn_se_vol2'] + resp.sldr_se_vol2 = profile['sldr_se_vol2'] + resp.sort_kind = profile['sort_kind'] + resp.lv_num = profile['lv_num'] + resp.lv_pnt = profile['lv_pnt'] + resp.lv_efct_id = profile['lv_efct_id'] + resp.lv_plt_id = profile['lv_plt_id'] + resp.use_pv_mdl_eqp = int(profile['use_pv_mdl_eqp']) + resp.use_mdl_pri = int(profile['use_mdl_pri']) + resp.use_pv_skn_eqp = int(profile['use_pv_skn_eqp']) + resp.use_pv_btn_se_eqp = int(profile['use_pv_btn_se_eqp']) + resp.use_pv_sld_se_eqp = int(profile['use_pv_sld_se_eqp']) + resp.use_pv_chn_sld_se_eqp = int(profile['use_pv_chn_sld_se_eqp']) + resp.use_pv_sldr_tch_se_eqp = int(profile['use_pv_sldr_tch_se_eqp']) + resp.vcld_pts = profile['lv_efct_id'] + resp.nxt_pv_id = profile['nxt_pv_id'] + resp.nxt_dffclty = profile['nxt_dffclty'] + resp.nxt_edtn = profile['nxt_edtn'] + resp.dsp_clr_brdr = profile['dsp_clr_brdr'] + resp.dsp_intrm_rnk = profile['dsp_intrm_rnk'] + resp.dsp_clr_sts = profile['dsp_clr_sts'] + resp.rgo_sts = profile['rgo_sts'] + """ + profile_dict = profile._asdict() + profile_dict.pop("id") + profile_dict.pop("user") + profile_dict.pop("version") - resp.pd_id = data['pd_id'] - resp.hp_vol = {profile['hp_vol']} - resp.btn_se_vol = {profile['btn_se_vol']} - resp.btn_se_vol2 = {profile['btn_se_vol2']} - resp.sldr_se_vol2 = {profile['sldr_se_vol2']} - resp.sort_kind = {profile['sort_kind']} - resp.player_name = {profile['player_name']} - resp.lv_num = {profile['lv_num']} - resp.lv_pnt = {profile['lv_pnt']} - resp.lv_efct_id = {profile['lv_efct_id']} - resp.lv_plt_id = {profile['lv_plt_id']} - resp.use_pv_mdl_eqp = {int(profile['use_pv_mdl_eqp'])} - resp.use_mdl_pri = {int(profile['use_mdl_pri'])} - resp.use_pv_skn_eqp = {int(profile['use_pv_skn_eqp'])} - resp.use_pv_btn_se_eqp = {int(profile['use_pv_btn_se_eqp'])} - resp.use_pv_sld_se_eqp = {int(profile['use_pv_sld_se_eqp'])} - resp.use_pv_chn_sld_se_eqp = {int(profile['use_pv_chn_sld_se_eqp'])} - resp.use_pv_sldr_tch_se_eqp = {int(profile['use_pv_sldr_tch_se_eqp'])} - resp.vcld_pts = {profile['lv_efct_id']} - resp.nxt_pv_id = {profile['nxt_pv_id']} - resp.nxt_dffclty = {profile['nxt_dffclty']} - resp.nxt_edtn = {profile['nxt_edtn']} - resp.dsp_clr_brdr = {profile['dsp_clr_brdr']} - resp.dsp_intrm_rnk = {profile['dsp_intrm_rnk']} - resp.dsp_clr_sts = {profile['dsp_clr_sts']} - resp.rgo_sts = {profile['rgo_sts']} + for k, v in profile_dict.items(): + # if hasattr(resp, k): + setattr(resp, k, v) + response = "&ps_result=1" # Contest progress response += f"&cv_cid=-1,-1,-1,-1" @@ -506,8 +496,8 @@ class DivaBase: # To be fully fixed if "my_qst_id" in profile: - resp.my_qst_id = {profile['my_qst_id']} - resp.my_qst_sts = {profile['my_qst_sts']} + resp.my_qst_id = profile['my_qst_id'] + resp.my_qst_sts = profile['my_qst_sts'] response += f"&my_qst_prgrs=0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" response += f"&my_qst_et=2022-06-19%2010%3A28%3A52.0,2022-06-19%2010%3A28%3A52.0,2022-06-19%2010%3A28%3A52.0,2100-01-01%2008%3A59%3A59.0,2100-01-01%2008%3A59%3A59.0,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx" @@ -531,7 +521,7 @@ class DivaBase: } # get clear status from user scores - pv_records = self.data.score.get_best_scores(data["pd_id"]) + pv_records = self.data.score.get_best_scores(req.pd_id) clear_status = "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" if pv_records is not None: @@ -568,6 +558,7 @@ class DivaBase: clear_status = ",".join(map(str, clear_list)) response += f"&clr_sts={clear_status}" + resp.clr_sts = clear_status # Store stuff to add to rework response += f"&mdl_eqp_tm={self.time_lut}" diff --git a/titles/diva/handlers/base.py b/titles/diva/handlers/base.py index 0843c88..c974615 100644 --- a/titles/diva/handlers/base.py +++ b/titles/diva/handlers/base.py @@ -2,6 +2,16 @@ from urllib import parse from datetime import datetime from typing import Union, Dict +def lazy_http_form_parse(src: Union[str, bytes]) -> Dict[bytes, bytes]: + out = {} + if type(src) == str: + src = src.encode() + for param in src.split(b"&"): + kvp = param.split(b"=") + out[parse.unquote(kvp[0])] = parse.unquote(kvp[1]) + + return out + class DivaRequestParseException(Exception): """ @@ -30,7 +40,7 @@ class BaseBinaryRequest: f"req_id not in request data {self.raw_dict}" ) - for k, v in self.raw_dict: + for k, v in self.raw_dict.items(): setattr(self, k, v) @@ -45,53 +55,56 @@ class BaseRequest: def __init__(self, raw: Union[str, bytes]) -> None: self.raw = raw - self.raw_dict: Dict[bytes, bytes] = dict(parse.parse_qsl(raw)) + try: + self.raw_dict: Dict[str, str] = lazy_http_form_parse(raw) + except UnicodeDecodeError as e: + raise DivaRequestParseException(f"Could not decode data {raw} - {e}") - if b"cmd" not in self.raw_dict: + if "cmd" not in self.raw_dict: raise DivaRequestParseException(f"cmd not in request data {self.raw_dict}") - if b"req_id" not in self.raw_dict: + if "req_id" not in self.raw_dict: raise DivaRequestParseException( f"req_id not in request data {self.raw_dict}" ) - if b"place_id" not in self.raw_dict: + if "place_id" not in self.raw_dict: raise DivaRequestParseException( f"place_id not in request data {self.raw_dict}" ) - if b"start_up_mode" not in self.raw_dict: + if "start_up_mode" not in self.raw_dict: raise DivaRequestParseException( f"start_up_mode not in request data {self.raw_dict}" ) - if b"cmm_dly_mod" not in self.raw_dict: + if "cmm_dly_mod" not in self.raw_dict: raise DivaRequestParseException( f"cmm_dly_mod not in request data {self.raw_dict}" ) - if b"cmm_dly_sec" not in self.raw_dict: + if "cmm_dly_sec" not in self.raw_dict: raise DivaRequestParseException( f"cmm_dly_sec not in request data {self.raw_dict}" ) - if b"cmm_err_mod" not in self.raw_dict: + if "cmm_err_mod" not in self.raw_dict: raise DivaRequestParseException( f"cmm_err_mod not in request data {self.raw_dict}" ) - if b"region_code" not in self.raw_dict: + if "region_code" not in self.raw_dict: raise DivaRequestParseException( f"region_code not in request data {self.raw_dict}" ) - if b"time_stamp" not in self.raw_dict: + if "time_stamp" not in self.raw_dict: raise DivaRequestParseException( f"time_stamp not in request data {self.raw_dict}" ) for k, v in self.raw_dict.items(): - setattr(self, k.decode(), v.decode()) + setattr(self, k, v) self.place_id = int(self.place_id) self.start_up_mode = int(self.start_up_mode) @@ -110,7 +123,13 @@ class BaseResponse: self.stat = "ok" def make(self) -> str: - return f"cmd={self.cmd}&req_id={self.req_id}&stat={self.stat}" + ret = "" + for k, v in vars(self).items(): + ret += f"{k}={v}&" + + if ret[-1] == "&": + ret = ret[:-1] + return ret class GameInitRequest(BaseRequest): def __init__(self, raw: Union[str, bytes]) -> None: diff --git a/titles/diva/handlers/user.py b/titles/diva/handlers/user.py index 737aff2..12a0763 100644 --- a/titles/diva/handlers/user.py +++ b/titles/diva/handlers/user.py @@ -27,21 +27,7 @@ class PreStartRequest(BaseRequest): class PreStartResponse(BaseResponse): - player_name: str - sort_kind: str - lv_efct_id: str - lv_plt_id: str - lv_str: str - lv_num: str - lv_pnt: str - vcld_pts: str - skn_eqp: str - btn_se_eqp: str - sld_se_eqp: str - chn_sld_se_eqp: str - sldr_tch_se_eqp: str - passwd_stat: str - mdl_eqp_tm: str + def __init__(self, cmd_id: str, req_id: int, pd_id: int) -> None: super().__init__(cmd_id, req_id) @@ -51,6 +37,21 @@ class PreStartResponse(BaseResponse): self.nblss_ltt_stts = -1 self.nblss_ltt_tckt = -1 self.nblss_ltt_is_opn = -1 + self.player_name: str = "" + self.sort_kind: str = "" + self.lv_efct_id: str = "" + self.lv_plt_id: str = "" + self.lv_str: str = "" + self.lv_num: str = "" + self.lv_pnt: str = "" + self.vcld_pts: str = "" + self.skn_eqp: str = "" + self.btn_se_eqp: str = "" + self.sld_se_eqp: str = "" + self.chn_sld_se_eqp: str = "" + self.sldr_tch_se_eqp: str = "" + self.passwd_stat: str = "" + self.mdl_eqp_tm: str = "" # Ideally this would be a real array that would get converted later # But this is how it's stored in the db, so w/e for now self.mdl_eqp_ary = "-999,-999,-999" @@ -100,6 +101,11 @@ class StartResponse(BaseResponse): self.dsp_intrm_rnk: int = 0 self.dsp_clr_sts: int = 0 self.rgo_sts: int = 0 + self.cv_cid: str = "-1,-1,-1,-1" + self.cv_sc: str = "-1,-1,-1,-1" + #self.cv_bv: str = "-1,-1,-1,-1" + self.cv_bv: str = "-1,-1,-1,-1" + self.cv_bf: str = "-1,-1,-1,-1" self.my_qst_id: str = ",".join(["-1"] * 25) self.my_qst_sts: str = ",".join("0" * 5) + "," + ",".join(["-1"] * 20) self.my_qst_prgrs: str = ",".join("0" * 5) + "," + ",".join(["-1"] * 20) @@ -109,3 +115,28 @@ class StartResponse(BaseResponse): self.mdl_eqp_ary = ",".join(["-999"] * 3) self.c_itm_eqp_ary = ",".join(["-999"] * 12) self.ms_itm_flg_ary = ",".join(["1"] * 12) + +class RegisterRequest(BaseRequest): + pmm: str + idm: str + mmgameid: str + mmuid: str + a_code: str + aime_a_code: str + player_name: str + passwd: str + + def __init__(self, raw: str) -> None: + super().__init__(raw) + try: + self.aime_id = int(self.aime_id) + self.key_obj_type = int(self.key_obj_type) + + except AttributeError as e: + raise DivaRequestParseException(f"RegisterRequest: {e}") + +class RegisterResponse(BaseResponse): + def __init__(self, cmd_id: str, req_id: int, pv_id: int) -> None: + super().__init__(cmd_id, req_id) + self.cd_adm_result: int = 1 + self.pd_id: int = pv_id diff --git a/titles/diva/index.py b/titles/diva/index.py index c5feaa3..50279e6 100644 --- a/titles/diva/index.py +++ b/titles/diva/index.py @@ -79,7 +79,7 @@ class DivaServlet: if "THIS_STRING_SEPARATES" in str(url_header): binary_request = req_raw.splitlines() binary_cmd_decoded = binary_request[3].decode("utf-8") - + url_data = binary_cmd_decoded # for logging req_cls = BaseBinaryRequest(binary_cmd_decoded) else: