From 74a6e16d221b1b4acaf99983d737f759b184c3e5 Mon Sep 17 00:00:00 2001 From: drmext <71258889+drmext@users.noreply.github.com> Date: Sat, 17 Dec 2022 23:09:40 +0000 Subject: [PATCH] Implement GITADORA --- .gitignore | 1 + README.md | 8 + core_common.py | 68 +++- modules/core/cardmng.py | 1 + modules/gitadora/__init__.py | 0 modules/gitadora/cardutil.py | 263 +++++++++++++ modules/gitadora/gameend.py | 341 +++++++++++++++++ modules/gitadora/gameinfo.py | 218 +++++++++++ modules/gitadora/gametop.py | 605 ++++++++++++++++++++++++++++++ modules/gitadora/playablemusic.py | 122 ++++++ modules/gitadora/shopinfo.py | 31 ++ 11 files changed, 1645 insertions(+), 13 deletions(-) create mode 100644 modules/gitadora/__init__.py create mode 100644 modules/gitadora/cardutil.py create mode 100644 modules/gitadora/gameend.py create mode 100644 modules/gitadora/gameinfo.py create mode 100644 modules/gitadora/gametop.py create mode 100644 modules/gitadora/playablemusic.py create mode 100644 modules/gitadora/shopinfo.py diff --git a/.gitignore b/.gitignore index 2651921..b1e2bab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.pyc +mdb*.xml /db*.json /*.db .venv/ diff --git a/README.md b/README.md index 4203fd2..9957e8f 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,17 @@ for experimental local testing and playing - DDR A20 PLUS - DDR A3 + +- GITADORA 5 Matixx +- GITADORA 6 EXCHAIN +- GITADORA 7 NEX+AGE +- GITADORA 8 HIGH-VOLTAGE +- GITADORA 9 FUZZ-UP + - IIDX 18 Resort Anthem - IIDX 19 Lincle - IIDX 20 tricoro - IIDX 29 CastHour - IIDX 30 RESIDENT + - SDVX 6 EXCEED GEAR diff --git a/core_common.py b/core_common.py index 66cd587..dbdb670 100644 --- a/core_common.py +++ b/core_common.py @@ -50,20 +50,62 @@ async def core_get_game_version_from_software_version(software_version): _, model, dest, spec, rev, ext = software_version ext = int(ext) - if model == "LDJ" and ext >= 2022101700: - return 30 - elif model == "LDJ" and ext in range(2021101300, 2022101500): - return 29 - elif model == "JDZ" and ext == 2011071200: + if model == "LDJ": + if ext >= 2022101700: + return 30 + elif ext in range(2021101300, 2022101500): + return 29 + elif ext in range(2020102800, 2021100601): + return 28 + elif ext in range(2019101600, 2020102201): + return 27 + elif ext in range(2018110700, 2019100701): + return 26 + elif ext in range(2017122100, 2018103101): + return 25 + elif ext in range(2016102400, 2017082801): + return 24 + elif ext in range(2015111100, 2016102001): + return 23 + elif ext in range(2014091700, 2015080501): + return 22 + elif ext in range(2013100200, 2014071601): + return 21 + elif ext in range(2012091900, 2013090901): + return 20 + elif model == "KDZ": + return 19 + elif model == "JDZ": return 18 - elif model == "KDZ" and ext == 2012090300: - return 19 - elif model == "LDJ" and ext == 2013090900: - return 20 - elif model == "MDX" and ext >= 2019022600: - return 19 - elif model == "KFC" and ext >= 2020090402: - return 6 + + elif model == "M32": + if ext >= 2022121400: + return 9 + elif ext >= 2021042100: + return 8 + elif ext >= 2019100200: + return 7 + elif ext >= 2018072700: + return 6 + elif ext >= 2017090600: + return 5 + elif ext >= 2017011800: + return 4 + elif ext in range(2015042100, 2016112302): + return 3 + elif ext in range(2014021400, 2015032702): + return 2 + elif ext in range(2013012400, 2014011601): + return 1 + + elif model == "MDX": + if ext >= 2019022600: # ??? + return 19 + + elif model == "KFC": + if ext >= 2020090402: # ??? + return 6 + else: return 0 diff --git a/modules/core/cardmng.py b/modules/core/cardmng.py index 0b0dfce..977011f 100644 --- a/modules/core/cardmng.py +++ b/modules/core/cardmng.py @@ -12,6 +12,7 @@ def get_target_table(game_id): "LDJ": "iidx_profile", "MDX": "ddr_profile", "KFC": "sdvx_profile", + "M32": "gitadora_profile", "JDZ": "iidx_profile", "KDZ": "iidx_profile", } diff --git a/modules/gitadora/__init__.py b/modules/gitadora/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/gitadora/cardutil.py b/modules/gitadora/cardutil.py new file mode 100644 index 0000000..22aca80 --- /dev/null +++ b/modules/gitadora/cardutil.py @@ -0,0 +1,263 @@ +from tinydb import Query, where + +import random + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E +from core_database import get_db + +router = APIRouter(prefix="/local", tags=["local"]) +router.model_whitelist = ["M32"] + + +def get_profile(cid): + return get_db().table("gitadora_profile").get(where("card") == cid) + + +def get_game_profile(cid, game_version): + profile = get_profile(cid) + + return profile["version"].get(str(game_version), None) + + +@router.post("/{gameinfo}/{ver}_cardutil/check") +async def gitadora_cardutil_check(ver: str, request: Request): + request_info = await core_process_request(request) + game_version = request_info["game_version"] + + data = request_info["root"][0].find("player") + + no = int(data.attrib["no"]) + + dataid = data.find("refid").text + + profile = get_game_profile(dataid, game_version) + + if profile is None: + state = 0 + name = "" + did = 0 + else: + state = 2 + name = profile["name"] + did = 1 + + response = E.response( + E( + f"{ver}_cardutil", + E.player( + E.name(name, __type="str"), + E.charaid(0, __type="s32"), + E.did(did, __type="s32"), + E.skilldata( + E.skill(0, __type="s32"), + E.all_skill(0, __type="s32"), + E.old_skill(0, __type="s32"), + E.old_all_skill(0, __type="s32"), + ), + no=1, + state=state, + ), + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post("/{gameinfo}/{ver}_cardutil/regist") +async def gitadora_cardutil_regist(ver: str, request: Request): + request_info = await core_process_request(request) + game_version = request_info["game_version"] + spec = request_info["spec"] + + data = request_info["root"][0].find("player") + + no = int(data.attrib["no"]) + + dataid = data.find("refid").text + + db = get_db().table("gitadora_profile") + all_profiles_for_card = db.get(Query().card == dataid) + + if "gitadora_id" not in all_profiles_for_card: + gitadora_id = random.randint(10000000, 99999999) + all_profiles_for_card["gitadora_id"] = gitadora_id + + all_profiles_for_card["version"][str(game_version)] = { + "game_version": game_version, + "name": "kors k", + "title": "MONKEY BUSINESS", + "charaid": 0, + "stickers": {}, + } + + for game_type in ("drummania", "guitarfreaks"): + all_profiles_for_card["version"][str(game_version)][game_type] = { + "customdata_playstyle": [ + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 20, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 20, + 0, + ], + "customdata_custom": [0] * 50, + "playinfo_cabid": 1, + "playinfo_play": 0, + "playinfo_playtime": 0, + "playinfo_playterm": 0, + "playinfo_session_cnt": 0, + "playinfo_saved_cnt": 0, + "playinfo_matching_num": 0, + "playinfo_extra_stage": 0, + "playinfo_extra_play": 0, + "playinfo_extra_clear": 0, + "playinfo_encore_play": 0, + "playinfo_encore_clear": 0, + "playinfo_pencore_play": 0, + "playinfo_pencore_clear": 0, + "playinfo_max_clear_diff": 0, + "playinfo_max_full_diff": 0, + "playinfo_max_exce_diff": 0, + "playinfo_clear_num": 0, + "playinfo_full_num": 0, + "playinfo_exce_num": 0, + "playinfo_no_num": 0, + "playinfo_e_num": 0, + "playinfo_d_num": 0, + "playinfo_c_num": 0, + "playinfo_b_num": 0, + "playinfo_a_num": 0, + "playinfo_s_num": 0, + "playinfo_ss_num": 0, + "playinfo_last_category": 0, + "playinfo_last_musicid": 0, + "playinfo_last_seq": 0, + "playinfo_disp_level": 0, + "tutorial_progress": 0, + "tutorial_disp_state": 0, + "information": [0] * 50, + "reward": [0] * 50, + "skilldata_skill": 0, + "skilldata_allskill": 0, + "groove_extra_gauge": 0, + "groove_encore_gauge": 0, + "groove_encore_cnt": 0, + "groove_encore_success": 0, + "groove_unlock_point": 0, + "record_max_skill": 0, + "record_max_all_skill": 0, + "record_max_clear_diff": 0, + "record_max_full_diff": 0, + "record_max_exce_diff": 0, + "record_max_clear_music_num": 0, + "record_max_full_music_num": 0, + "record_max_exce_music_num": 0, + "record_max_clear_seq_num": 0, + "record_max_classic_all_skill": 0, + "record_diff_100_nr": 0, + "record_diff_150_nr": 0, + "record_diff_200_nr": 0, + "record_diff_250_nr": 0, + "record_diff_300_nr": 0, + "record_diff_350_nr": 0, + "record_diff_400_nr": 0, + "record_diff_450_nr": 0, + "record_diff_500_nr": 0, + "record_diff_550_nr": 0, + "record_diff_600_nr": 0, + "record_diff_650_nr": 0, + "record_diff_700_nr": 0, + "record_diff_750_nr": 0, + "record_diff_800_nr": 0, + "record_diff_850_nr": 0, + "record_diff_900_nr": 0, + "record_diff_950_nr": 0, + "record_diff_100_clear": [0] * 7, + "record_diff_150_clear": [0] * 7, + "record_diff_200_clear": [0] * 7, + "record_diff_250_clear": [0] * 7, + "record_diff_300_clear": [0] * 7, + "record_diff_350_clear": [0] * 7, + "record_diff_400_clear": [0] * 7, + "record_diff_450_clear": [0] * 7, + "record_diff_500_clear": [0] * 7, + "record_diff_550_clear": [0] * 7, + "record_diff_600_clear": [0] * 7, + "record_diff_650_clear": [0] * 7, + "record_diff_700_clear": [0] * 7, + "record_diff_750_clear": [0] * 7, + "record_diff_800_clear": [0] * 7, + "record_diff_850_clear": [0] * 7, + "record_diff_900_clear": [0] * 7, + "record_diff_950_clear": [0] * 7, + "favorite_music_list_1": [-1] * 100, + "favorite_music_list_2": [-1] * 100, + "favorite_music_list_3": [-1] * 100, + "recommend_musicid_list": [-1] * 5, + "thanks_medal_medal": 0, + "thanks_medal_granted_total_medal": 0, + # "skindata_skin": [0] * 100, + } + + db.upsert(all_profiles_for_card, where("card") == dataid) + + response = E.response( + E( + f"{ver}_cardutil", + E.player( + E.is_succession(0, __type="bool"), + E.did(1, __type="s32"), + no=no, + ), + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/gitadora/gameend.py b/modules/gitadora/gameend.py new file mode 100644 index 0000000..cbd32b7 --- /dev/null +++ b/modules/gitadora/gameend.py @@ -0,0 +1,341 @@ +from tinydb import Query, where + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E +from core_database import get_db + +router = APIRouter(prefix="/local", tags=["local"]) +router.model_whitelist = ["M32"] + + +def get_profile(cid): + return get_db().table("gitadora_profile").get(where("card") == cid) + + +def get_game_profile(cid, game_version): + profile = get_profile(cid) + + return profile["version"].get(str(game_version), None) + + +@router.post("/{gameinfo}/{ver}_gameend/regist") +async def gitadora_gameend_regist(ver: str, request: Request): + request_info = await core_process_request(request) + game_version = request_info["game_version"] + spec = request_info["spec"] + + if spec == "A": + g = "guitarfreaks" + elif spec == "B": + g = "drummania" + + root = request_info["root"][0] + + player = root.find("player") + no = int(player.attrib["no"]) + + if player.attrib["card"] == "use": + dataid = player.find("refid").text + profile = get_profile(dataid) + gitadora_id = profile["gitadora_id"] + game_profile = profile["version"].get(str(game_version), {}) + + game_profile[g]["customdata_playstyle"] = [ + int(x) for x in player.find("customdata/playstyle").text.split(" ") + ] + game_profile[g]["customdata_custom"] = [ + int(x) for x in player.find("customdata/custom").text.split(" ") + ] + + for k in [ + "cabid", + "play", + "playtime", + "playterm", + "session_cnt", + "matching_num", + "extra_stage", + "extra_play", + "extra_clear", + "encore_play", + "encore_clear", + "pencore_play", + "pencore_clear", + "max_clear_diff", + "max_full_diff", + "max_exce_diff", + "clear_num", + "full_num", + "exce_num", + "no_num", + "e_num", + "d_num", + "c_num", + "b_num", + "a_num", + "s_num", + "ss_num", + "last_category", + "last_musicid", + "last_seq", + "disp_level", + ]: + game_profile[g]["playinfo_" + k] = int(player.find(f"playinfo/{k}").text) + + game_profile[g]["tutorial_progress"] = int( + player.find("tutorial/progress").text + ) + game_profile[g]["tutorial_disp_state"] = int( + player.find("tutorial/disp_state").text + ) + + game_profile[g]["information"] = [ + int(x) for x in player.find("information/info").text.split(" ") + ] + game_profile[g]["reward"] = [ + int(x) for x in player.find("reward/status").text.split(" ") + ] + + game_profile[g]["skilldata_skill"] = int(player.find("skilldata/skill").text) + game_profile[g]["skilldata_allskill"] = int( + player.find("skilldata/all_skill").text + ) + + groove = [ + "extra_gauge", + "encore_gauge", + "encore_cnt", + "encore_success", + ] + if game_version > 6: + groove.append("unlock_point") + + for k in groove: + game_profile[g]["groove_" + k] = int(player.find(f"groove/{k}").text) + + record_max = [ + "skill", + "all_skill", + "clear_diff", + "full_diff", + "exce_diff", + "clear_music_num", + "full_music_num", + "exce_music_num", + "clear_seq_num", + ] + if game_version > 6: + record_max.append("classic_all_skill") + + for k in record_max: + game_profile[g]["record_max_" + k] = int( + player.find(f"record/max/{k}").text + ) + + for k in [ + "diff_100_nr", + "diff_150_nr", + "diff_200_nr", + "diff_250_nr", + "diff_300_nr", + "diff_350_nr", + "diff_400_nr", + "diff_450_nr", + "diff_500_nr", + "diff_550_nr", + "diff_600_nr", + "diff_650_nr", + "diff_700_nr", + "diff_750_nr", + "diff_800_nr", + "diff_850_nr", + "diff_900_nr", + "diff_950_nr", + ]: + game_profile[g]["record_" + k] = int(player.find(f"record/diff/{k}").text) + + for k in [ + "diff_100_clear", + "diff_150_clear", + "diff_200_clear", + "diff_250_clear", + "diff_300_clear", + "diff_350_clear", + "diff_400_clear", + "diff_450_clear", + "diff_500_clear", + "diff_550_clear", + "diff_600_clear", + "diff_650_clear", + "diff_700_clear", + "diff_750_clear", + "diff_800_clear", + "diff_850_clear", + "diff_900_clear", + "diff_950_clear", + ]: + game_profile[g]["record_" + k] = [ + int(x) for x in player.find(f"record/diff/{k}").text.split(" ") + ] + + for k in [ + "music_list_1", + "music_list_2", + "music_list_3", + ]: + game_profile[g]["favorite_" + k] = [ + int(x) for x in player.find(f"favoritemusic/{k}").text.split(" ") + ] + + profile["version"][str(game_version)] = game_profile + + get_db().table("gitadora_profile").upsert(profile, where("card") == dataid) + + stage = player.findall("stage") + + for s in stage: + data_version = root.find("data_version").text + timestamp = int(s.find("date_ms").text) + musicid = int(s.find("musicid").text) + seq = int(s.find("seq").text) + skill = int(s.find("skill").text) + new_skill = int(s.find("new_skill").text) + clear = int(s.find("clear").text) + auto_clear = int(s.find("auto_clear").text) + fullcombo = int(s.find("fullcombo").text) + excellent = int(s.find("excellent").text) + medal = int(s.find("medal").text) + perc = int(s.find("perc").text) + new_perc = int(s.find("new_perc").text) + rank = int(s.find("rank").text) + score = int(s.find("score").text) + combo = int(s.find("combo").text) + max_combo_perc = int(s.find("max_combo_perc").text) + flags = int(s.find("flags").text) + phrase_combo_perc = int(s.find("phrase_combo_perc").text) + perfect = int(s.find("perfect").text) + great = int(s.find("great").text) + good = int(s.find("good").text) + ok = int(s.find("ok").text) + miss = int(s.find("miss").text) + perfect_perc = int(s.find("perfect_perc").text) + great_perc = int(s.find("great_perc").text) + good_perc = int(s.find("good_perc").text) + ok_perc = int(s.find("ok_perc").text) + miss_perc = int(s.find("miss_perc").text) + meter = int(s.find("meter").text) + meter_prog = int(s.find("meter_prog").text) + before_meter = int(s.find("before_meter").text) + before_meter_prog = int(s.find("before_meter_prog").text) + is_new_meter = int(s.find("is_new_meter").text) + phrase_data_num = int(s.find("phrase_data_num").text) + phrase_addr = [int(x) for x in s.find("phrase_addr").text.split(" ")] + phrase_type = [int(x) for x in s.find("phrase_type").text.split(" ")] + phrase_status = [int(x) for x in s.find("phrase_status").text.split(" ")] + phrase_end_addr = int(s.find("phrase_end_addr").text) + + get_db().table(f"{g}_scores").insert( + { + "timestamp": timestamp, + "game_version": game_version, + "gitadora_id": gitadora_id, + "data_version": data_version, + "musicid": musicid, + "seq": seq, + "skill": skill, + "new_skill": new_skill, + "clear": clear, + "auto_clear": auto_clear, + "fullcombo": fullcombo, + "excellent": excellent, + "medal": medal, + "perc": perc, + "new_perc": new_perc, + "rank": rank, + "score": score, + "combo": combo, + "max_combo_perc": max_combo_perc, + "flags": flags, + "phrase_combo_perc": phrase_combo_perc, + "perfect": perfect, + "great": great, + "good": good, + "ok": ok, + "miss": miss, + "perfect_perc": perfect_perc, + "great_perc": great_perc, + "good_perc": good_perc, + "ok_perc": ok_perc, + "miss_perc": miss_perc, + "meter": meter, + "meter_prog": meter_prog, + "before_meter": before_meter, + "before_meter_prog": before_meter_prog, + "is_new_meter": is_new_meter, + "phrase_data_num": phrase_data_num, + "phrase_addr": phrase_addr, + "phrase_type": phrase_type, + "phrase_status": phrase_status, + "phrase_end_addr": phrase_end_addr, + }, + ) + + best_score = ( + get_db() + .table(f"{g}_scores_best") + .get( + (where("gitadora_id") == gitadora_id) + & (where("musicid") == musicid) + & (where("seq") == seq) + ) + ) + best_score = {} if best_score is None else best_score + + best_ex_score = best_score.get("score", score) + best_score_data = { + "gitadora_id": gitadora_id, + "musicid": musicid, + "seq": seq, + "skill": max(skill, best_score.get("skill", skill)), + "clear": max(clear, best_score.get("clear", clear)), + "fullcombo": max(fullcombo, best_score.get("fullcombo", fullcombo)), + "excellent": max(excellent, best_score.get("excellent", excellent)), + "perc": max(perc, best_score.get("perc", perc)), + "rank": max(rank, best_score.get("rank", rank)), + "meter": meter + if score >= best_ex_score + else best_score.get("meter", meter), + "meter_prog": meter_prog + if score >= best_ex_score + else best_score.get("meter_prog", meter_prog), + } + + get_db().table(f"{g}_scores_best").upsert( + best_score_data, + (where("gitadora_id") == gitadora_id) + & (where("musicid") == musicid) + & (where("seq") == seq), + ) + + response = E.response( + E( + f"{ver}_gameend", + E.gamemode(mode="game_mode"), + E.player( + E.skill( + E.rank(1, __type="s32"), + E.total_nr(1, __type="s32"), + ), + E.all_skill( + E.rank(1, __type="s32"), + E.total_nr(1, __type="s32"), + ), + no=no, + state=0, + ), + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/gitadora/gameinfo.py b/modules/gitadora/gameinfo.py new file mode 100644 index 0000000..43b387f --- /dev/null +++ b/modules/gitadora/gameinfo.py @@ -0,0 +1,218 @@ +import time + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E + +router = APIRouter(prefix="/local", tags=["local"]) +router.model_whitelist = ["M32"] + + +@router.post("/{gameinfo}/{ver}_gameinfo/get") +async def gitadora_gameinfo_get(ver: str, request: Request): + request_info = await core_process_request(request) + game_version = request_info["game_version"] + + response = E.response( + E( + f"{ver}_gameinfo", + E.now_date(round(time.time()), __type="u64"), + E.extra( + E.extra_lv(0, __type="u8"), + E.extramusic( + E.music( + E.musicid(0, __type="s32"), + E.get_border(0, __type="u8"), + ), + ), + ), + E.general_term( + *[ + E.termdata( + E.type(f"general_{s}", __type="str"), + E.term(1, __type="u8"), + E.start_date_ms(0, __type="u64"), + E.end_date_ms(0, __type="u64"), + ) + for s in [ + "ultimate_mobile_2019_info", + "50th_konami_logo", + "cardconnect_champ", + "otobear_birthday", + "kac_9th_info", + "floor_break_info", + ] + ], + ), + *[ + E( + x, + E.term(1, __type="u8"), + E.start_date_ms(0, __type="u64"), + E.end_date_ms(0, __type="u64"), + ) + for x in [ + "phrase_combo_challenge", + "sdvx_stamprally3", + "chronicle_1", + "paseli_point_lottery", + ] + ], + *[ + E( + f"phrase_combo_challenge_{x}", + E.term(1, __type="u8"), + E.start_date_ms(0, __type="u64"), + E.end_date_ms(0, __type="u64"), + ) + for x in range(2, 21) + ], + E.long_otobear_fes_1( + E.term(1, __type="u8"), + E.start_date_ms(0, __type="u64"), + E.end_date_ms(0, __type="u64"), + E.bonus_musicid(), + ), + E.monstar_subjugation( + E.bonus_musicid(0, __type="s32"), + *[ + E( + f"monstar_subjugation_{x}", + E.term(1, __type="u8"), + E.start_date_ms(0, __type="u64"), + E.end_date_ms(0, __type="u64"), + ) + for x in range(1, 5) + ], + ), + E.bear_fes( + *[ + E( + f"bear_fes_{x}", + E.term(1, __type="u8"), + E.start_date_ms(0, __type="u64"), + E.end_date_ms(0, __type="u64"), + ) + for x in range(1, 5) + ], + ), + *[ + E( + f"kouyou_challenge_{x}", + E.term(0, __type="u8"), + E.bonus_musicid(0, __type="s32"), + ) + for x in range(1, 4) + ], + *[ + E( + x, + E.term(1, __type="u8"), + E.start_date_ms(0, __type="u64"), + E.end_date_ms(0, __type="u64"), + E.box_term( + E.state(0, __type="u8"), + ), + ) + for x in ["thanksgiving", "lotterybox"] + ], + E.sticker_campaign( + E.term(0, __type="u8"), + E.sticker_list(), + ), + E.infect_music( + E.term(1, __type="u8"), + ), + E.unlock_challenge( + E.term(0, __type="u8"), + ), + E.battle( + E.term(1, __type="u8"), + ), + E.battle_chara( + E.term(1, __type="u8"), + ), + E.data_ver_limit( + E.term(0, __type="s32" if game_version >= 9 else "u8"), + ), + E.ea_pass_propel( + E.term(0, __type="u8"), + ), + E.monthly_skill( + E.term(0, __type="u8"), + E.target_music( + E.music( + E.musicid(0, __type="s32"), + ), + ), + ), + E.update_prog( + E.term(0, __type="u8"), + ), + E.rockwave(E.event_list()), + E.general_term(), + E.jubeat_omiyage_challenge(), + E.kac2017(), + E.nostalgia_concert(), + E.trbitemdata(), + E.ctrl_movie(), + E.ng_jacket(), + E.ng_recommend_music(), + E.ranking( + E.skill_0_999(), + E.skill_1000_1499(), + E.skill_1500_1999(), + E.skill_2000_2499(), + E.skill_2500_2999(), + E.skill_3000_3499(), + E.skill_3500_3999(), + E.skill_4000_4499(), + E.skill_4500_4999(), + E.skill_5000_5499(), + E.skill_5500_5999(), + E.skill_6000_6499(), + E.skill_6500_6999(), + E.skill_7000_7499(), + E.skill_7500_7999(), + E.skill_8000_8499(), + E.skill_8500_9999(), + E.total(), + E.original(), + E.bemani(), + E.famous(), + E.anime(), + E.band(), + E.western(), + ), + E.processing_report_state(0, __type="u8"), + E.assert_report_state(0, __type="u8"), + E.recommendmusic( + E.music( + E.musicid(0, __type="s32"), + ), + nr=1, + ), + E.demomusic(nr=0), + E.event_skill(), + E.temperature( + E.is_send(0, __type="bool"), + ), + E.bemani_summer_2018( + E.is_open(0, __type="bool"), + ), + E.kac2018( + E.event( + E.term(0, __type="s32"), + E.since(0, __type="u64"), + E.till(0, __type="u64"), + E.is_open(0, __type="bool"), + E.target_music( + E.music_id([0] * 6, __type="s32"), + ), + ), + ), + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/gitadora/gametop.py b/modules/gitadora/gametop.py new file mode 100644 index 0000000..fb489f6 --- /dev/null +++ b/modules/gitadora/gametop.py @@ -0,0 +1,605 @@ +from tinydb import Query, where + +import time + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E +from core_database import get_db + + +router = APIRouter(prefix="/local", tags=["local"]) +router.model_whitelist = ["M32"] + + +def get_profile(cid): + return get_db().table("gitadora_profile").get(where("card") == cid) + + +def get_game_profile(cid, game_version): + profile = get_profile(cid) + + return profile["version"].get(str(game_version), None) + + +@router.post("/{gameinfo}/{ver}_gametop/get") +async def gitadora_gametop_get(ver: str, request: Request): + request_info = await core_process_request(request) + game_version = request_info["game_version"] + spec = request_info["spec"] + + if spec == "A": + g = "guitarfreaks" + elif spec == "B": + g = "drummania" + + data = request_info["root"][0].find("player") + no = int(data.attrib["no"]) + dataid = data.find("refid").text + profile = get_game_profile(dataid, game_version) + gitadora_id = get_profile(dataid)["gitadora_id"] + + records = {} + + for record in ( + get_db().table(f"{g}_scores_best").search(where("gitadora_id") == gitadora_id) + ): + s = { + "musicid": record["musicid"], + "seq": record["seq"], + "skill": record["skill"], + "clear": record["clear"], + "fullcombo": record["fullcombo"], + "excellent": record["excellent"], + "perc": record["perc"], + "rank": record["rank"], + "meter": record["meter"], + "meter_prog": record["meter_prog"], + "sdata": 0, + } + + if record["musicid"] not in records: + records[record["musicid"]] = {"order": len(records.keys()), "seq": {}} + + records[record["musicid"]]["seq"][record["seq"]] = s + + mlist = {} + + for musicid in records: + data = { + "musicid": musicid, + "mdata": [-1] * 20, + "flag": [0] * 5, + "sdata": [-1] * 2, + "meter": [0] * 8, + "meter_prog": [-1] * 8, + } + + for seq in records[musicid]["seq"]: + seqidx = int(seq) + data["mdata"][seqidx] = records[musicid]["seq"][seq]["perc"] + data["mdata"][8 + seqidx] = ( + records[musicid]["seq"][seq]["rank"] + if records[musicid]["seq"][seq]["clear"] != 0 + else -1 + ) + + if records[musicid]["seq"][seq]["fullcombo"] != 0: + data["flag"][0] |= 1 << seqidx + + if records[musicid]["seq"][seq]["excellent"] != 0: + data["flag"][1] |= 1 << seqidx + + data["flag"][2] |= ( + records[musicid]["seq"][seq]["clear"] << seqidx + ) # Clear flag/count score towards profile stats + + data["meter"][seqidx - 1] = records[musicid]["seq"][seq]["meter"] + data["meter_prog"][seqidx - 1] = records[musicid]["seq"][seq]["meter_prog"] + + mlist[records[musicid]["order"]] = data + + mlist = [mlist[x] for x in sorted(mlist.keys(), key=lambda x: int(x))] + + if len(mlist) == 0: + mlist = [ + { + "musicid": -1, + "mdata": [-1] * 20, + "flag": [0] * 5, + "sdata": [-1] * 2, + "meter": [0] * 8, + "meter_prog": [-1] * 8, + } + ] + + response = E.response( + E( + f"{ver}_gametop", + E.player( + E.now_date(round(time.time()), __type="u64"), + E.musiclist( + *[ + E.musicdata( + E.mdata(m["mdata"], __type="s16"), + E.flag(m["flag"], __type="u16"), + E.sdata(m["sdata"], __type="s16"), + E.meter(m["meter"], __type="u64"), + E.meter_prog(m["meter_prog"], __type="s16"), + musicid=m["musicid"], + ) + for m in mlist + ], + nr=len(mlist), + ), + E.secretmusic( + E.music( + E.musicid(1, __type="s32"), + E.seq(1, __type="u16"), + E.kind(1, __type="s32"), + ) + ), + E.chara_list(), + E.title_parts(), + E.information( + E.info(profile[g]["information"], __type="u32"), + ), + E.reward( + E.status(profile[g]["reward"], __type="u32"), + ), + E.rivaldata(), + E.frienddata(E.friend()), + E.thanks_medal( + E.medal(profile[g]["thanks_medal_medal"], __type="s32"), + E.grant_medal(0, __type="s32"), + E.grant_total_medal( + profile[g]["thanks_medal_granted_total_medal"], __type="s32" + ), + ), + E.skindata( + E.skin([0xFFFFFFFF] * 100, __type="u32"), + ), + E.battledata( + E.info( + E.orb(0, __type="s32"), + E.get_gb_point(0, __type="s32"), + E.send_gb_point(0, __type="s32"), + ), + E.greeting( + E.greeting_1("", __type="str"), + E.greeting_2("", __type="str"), + E.greeting_3("", __type="str"), + E.greeting_4("", __type="str"), + E.greeting_5("", __type="str"), + E.greeting_6("", __type="str"), + E.greeting_7("", __type="str"), + E.greeting_8("", __type="str"), + E.greeting_9("", __type="str"), + ), + E.setting( + E.matching(0, __type="s32"), + E.info_level(0, __type="s32"), + ), + E.score( + E.battle_class(0, __type="s32"), + E.max_battle_class(0, __type="s32"), + E.battle_point(0, __type="s32"), + E.win(0, __type="s32"), + E.lose(0, __type="s32"), + E.draw(0, __type="s32"), + E.consecutive_win(0, __type="s32"), + E.max_consecutive_win(0, __type="s32"), + E.glorious_win(0, __type="s32"), + E.max_defeat_skill(0, __type="s32"), + E.latest_result(0, __type="s32"), + ), + E.history(), + ), + E.is_free_ok(0, __type="bool"), + E.ranking( + E.skill( + E.rank(1, __type="s32"), + E.total_nr(1, __type="s32"), + ), + E.all_skill( + E.rank(1, __type="s32"), + E.total_nr(1, __type="s32"), + ), + ), + E.stage_result(), + E.monthly_skill(), + E.event_skill( + E.skill(1, __type="s32"), + E.ranking( + E.rank(1, __type="s32"), + E.total_nr(1, __type="s32"), + ), + E.eventlist(), + ), + E.event_score(E.event_list()), + E.rockwave(E.score_list()), + E.jubeat_omiyage_challenge(), + E.light_mode_reward_item( + E.itemid(-1, __type="s32"), + E.rarity(0, __type="s32"), + ), + E.standard_mode_reward_item( + E.itemid(-1, __type="s32"), + E.rarity(0, __type="s32"), + ), + E.delux_mode_reward_item( + E.itemid(-1, __type="s32"), + E.rarity(0, __type="s32"), + ), + E.kac2018( + E.entry_status(0, __type="s32"), + E.data( + E.term(0, __type="s32"), + E.total_score(0, __type="s32"), + E.score([0] * 6, __type="s32"), + E.music_type([0] * 6, __type="s32"), + E.play_count([0] * 6, __type="s32"), + ), + ), + E.sticker_campaign(), + E.kac2017( + E.entry_status(0, __type="s32"), + ), + E.nostalgia_concert(), + E.bemani_summer_2018( + E.linkage_id(-1, __type="s32"), + E.is_entry(0, __type="bool"), + E.target_music_idx(-1, __type="s32"), + E.point_1(0, __type="s32"), + E.point_2(0, __type="s32"), + E.point_3(0, __type="s32"), + E.point_4(0, __type="s32"), + E.point_5(0, __type="s32"), + E.point_6(0, __type="s32"), + E.point_7(0, __type="s32"), + E.reward_1(0, __type="bool"), + E.reward_2(0, __type="bool"), + E.reward_3(0, __type="bool"), + E.reward_4(0, __type="bool"), + E.reward_5(0, __type="bool"), + E.reward_6(0, __type="bool"), + E.reward_7(0, __type="bool"), + E.unlock_status_1(0, __type="s32"), + E.unlock_status_2(0, __type="s32"), + E.unlock_status_3(0, __type="s32"), + E.unlock_status_4(0, __type="s32"), + E.unlock_status_5(0, __type="s32"), + E.unlock_status_6(0, __type="s32"), + E.unlock_status_7(0, __type="s32"), + ), + E.thanksgiving( + E.term(0, __type="u8"), + E.score( + E.one_day_play_cnt(0, __type="s32"), + E.one_day_lottery_cnt(0, __type="s32"), + E.lucky_star(0, __type="s32"), + E.bear_mark(0, __type="s32"), + E.play_date_ms(0, __type="u64"), + ), + E.lottery_result( + E.unlock_bit(0, __type="u64"), + ), + ), + E.lotterybox(), + E.long_otobear_fes_1( + E.point(0, __type="s32"), + ), + E.phrase_combo_challenge( + E.point(0, __type="s32"), + ), + *[ + E(f"phrase_combo_challenge_{x}", E.point(0, __type="s32")) + for x in range(2, 21) + ], + E.bear_fes( + *[ + E( + f"bear_fes_{x}", + E.stage(0, __type="s32"), + E.point([0] * 8, __type="s32"), + ) + for x in range(1, 5) + ], + ), + E.monstar_subjugation( + *[ + E( + f"monstar_subjugation_{x}", + E.stage(0, __type="s32"), + E.point_1(0, __type="s32"), + E.point_2(0, __type="s32"), + E.point_3(0, __type="s32"), + ) + for x in range(1, 4) + ], + ), + *[ + E(f"kouyou_challenge_{x}", E.point(0, __type="s32")) + for x in range(1, 4) + ], + E.sdvx_stamprally3( + E.point(0, __type="s32"), + ), + E.chronicle_1( + E.point(0, __type="s32"), + ), + E.playerboard( + E.index(1, __type="s32"), + E.is_active(1, __type="bool"), + E.sticker( + E.id(479, __type="s32"), + E.pos_x(160, __type="float"), + E.pos_y(235, __type="float"), + E.scale_x(1, __type="float"), + E.scale_y(1, __type="float"), + E.rotate(0, __type="float"), + ), + E.sticker( + E.id(172, __type="s32"), + E.pos_x(160, __type="float"), + E.pos_y(235, __type="float"), + E.scale_x(1, __type="float"), + E.scale_y(1, __type="float"), + E.rotate(0, __type="float"), + ), + E.sticker( + E.id(379, __type="s32"), + E.pos_x(175, __type="float"), + E.pos_y(175, __type="float"), + E.scale_x(0.4, __type="float"), + E.scale_y(0.4, __type="float"), + E.rotate(5, __type="float"), + ), + E.sticker( + E.id(172, __type="s32"), + E.pos_x(175, __type="float"), + E.pos_y(265, __type="float"), + E.scale_x(1, __type="float"), + E.scale_y(1, __type="float"), + E.rotate(0, __type="float"), + ), + E.sticker( + E.id(179, __type="s32"), + E.pos_x(69, __type="float"), + E.pos_y(420, __type="float"), + E.scale_x(1, __type="float"), + E.scale_y(1, __type="float"), + E.rotate(0, __type="float"), + ), + ), + E.player_info( + E.player_type(1, __type="s8"), + E.did(1, __type="s32"), + E.name(profile["name"], __type="str"), + E.title(profile["title"], __type="str"), + E.charaid(profile["charaid"], __type="s32"), + ), + E.customdata( + E.playstyle(profile[g]["customdata_playstyle"], __type="s32"), + E.custom(profile[g]["customdata_custom"], __type="s32"), + ), + E.playinfo( + E.cabid(profile[g]["playinfo_cabid"], __type="s32"), + E.play(profile[g]["playinfo_play"], __type="s32"), + E.playtime(profile[g]["playinfo_playtime"], __type="s32"), + E.playterm(profile[g]["playinfo_playterm"], __type="s32"), + E.session_cnt(profile[g]["playinfo_session_cnt"], __type="s32"), + E.matching_num(profile[g]["playinfo_matching_num"], __type="s32"), + E.extra_stage(profile[g]["playinfo_extra_stage"], __type="s32"), + E.extra_play(profile[g]["playinfo_extra_play"], __type="s32"), + E.extra_clear(profile[g]["playinfo_extra_clear"], __type="s32"), + E.encore_play(profile[g]["playinfo_encore_play"], __type="s32"), + E.encore_clear(profile[g]["playinfo_encore_clear"], __type="s32"), + E.pencore_play(profile[g]["playinfo_pencore_play"], __type="s32"), + E.pencore_clear(profile[g]["playinfo_pencore_clear"], __type="s32"), + E.max_clear_diff( + profile[g]["playinfo_max_clear_diff"], __type="s32" + ), + E.max_full_diff(profile[g]["playinfo_max_full_diff"], __type="s32"), + E.max_exce_diff(profile[g]["playinfo_max_exce_diff"], __type="s32"), + E.clear_num(profile[g]["playinfo_clear_num"], __type="s32"), + E.full_num(profile[g]["playinfo_full_num"], __type="s32"), + E.exce_num(profile[g]["playinfo_exce_num"], __type="s32"), + E.no_num(profile[g]["playinfo_no_num"], __type="s32"), + E.e_num(profile[g]["playinfo_e_num"], __type="s32"), + E.d_num(profile[g]["playinfo_d_num"], __type="s32"), + E.c_num(profile[g]["playinfo_c_num"], __type="s32"), + E.b_num(profile[g]["playinfo_b_num"], __type="s32"), + E.a_num(profile[g]["playinfo_a_num"], __type="s32"), + E.s_num(profile[g]["playinfo_s_num"], __type="s32"), + E.ss_num(profile[g]["playinfo_ss_num"], __type="s32"), + E.last_category(profile[g]["playinfo_last_category"], __type="s32"), + E.last_musicid(profile[g]["playinfo_last_musicid"], __type="s32"), + E.last_seq(profile[g]["playinfo_last_seq"], __type="s32"), + E.disp_level(profile[g]["playinfo_disp_level"], __type="s32"), + ), + E.tutorial( + E.progress(profile[g]["tutorial_progress"], __type="s32"), + E.disp_state(profile[g]["tutorial_disp_state"], __type="u32"), + ), + E.skilldata( + E.skill(profile[g]["skilldata_skill"], __type="s32"), + E.all_skill(profile[g]["skilldata_allskill"], __type="s32"), + E.old_skill(profile[g]["skilldata_skill"], __type="s32"), + E.old_all_skill(profile[g]["skilldata_allskill"], __type="s32"), + ), + E.favoritemusic( + E.list_1(profile[g]["favorite_music_list_1"], __type="s32"), + E.list_2(profile[g]["favorite_music_list_2"], __type="s32"), + E.list_3(profile[g]["favorite_music_list_3"], __type="s32"), + ), + E.recommend_musicid_list( + profile[g]["recommend_musicid_list"], __type="s32" + ), + E.record( + *[ + E( + "gf" if g == "guitarfreaks" else "dm", + E.max_record( + E.skill(profile[g]["record_max_skill"], __type="s32"), + E.all_skill( + profile[g]["record_max_all_skill"], __type="s32" + ), + E.clear_diff( + profile[g]["record_max_clear_diff"], __type="s32" + ), + E.full_diff( + profile[g]["record_max_full_diff"], __type="s32" + ), + E.exce_diff( + profile[g]["record_max_exce_diff"], __type="s32" + ), + E.clear_music_num( + profile[g]["record_max_clear_music_num"], + __type="s32", + ), + E.full_music_num( + profile[g]["record_max_full_music_num"], + __type="s32", + ), + E.exce_music_num( + profile[g]["record_max_exce_music_num"], + __type="s32", + ), + E.clear_seq_num( + profile[g]["record_max_clear_seq_num"], __type="s32" + ), + E.classic_all_skill( + profile[g]["record_max_classic_all_skill"], + __type="s32", + ), + ), + E.diff_record( + E.diff_100_nr( + profile[g]["record_diff_100_nr"], __type="s32" + ), + E.diff_150_nr( + profile[g]["record_diff_150_nr"], __type="s32" + ), + E.diff_200_nr( + profile[g]["record_diff_200_nr"], __type="s32" + ), + E.diff_250_nr( + profile[g]["record_diff_250_nr"], __type="s32" + ), + E.diff_300_nr( + profile[g]["record_diff_300_nr"], __type="s32" + ), + E.diff_350_nr( + profile[g]["record_diff_350_nr"], __type="s32" + ), + E.diff_400_nr( + profile[g]["record_diff_400_nr"], __type="s32" + ), + E.diff_450_nr( + profile[g]["record_diff_450_nr"], __type="s32" + ), + E.diff_500_nr( + profile[g]["record_diff_500_nr"], __type="s32" + ), + E.diff_550_nr( + profile[g]["record_diff_550_nr"], __type="s32" + ), + E.diff_600_nr( + profile[g]["record_diff_600_nr"], __type="s32" + ), + E.diff_650_nr( + profile[g]["record_diff_650_nr"], __type="s32" + ), + E.diff_700_nr( + profile[g]["record_diff_700_nr"], __type="s32" + ), + E.diff_750_nr( + profile[g]["record_diff_750_nr"], __type="s32" + ), + E.diff_800_nr( + profile[g]["record_diff_800_nr"], __type="s32" + ), + E.diff_850_nr( + profile[g]["record_diff_850_nr"], __type="s32" + ), + E.diff_900_nr( + profile[g]["record_diff_900_nr"], __type="s32" + ), + E.diff_950_nr( + profile[g]["record_diff_950_nr"], __type="s32" + ), + E.diff_100_clear( + profile[g]["record_diff_100_clear"], __type="s32" + ), + E.diff_150_clear( + profile[g]["record_diff_150_clear"], __type="s32" + ), + E.diff_200_clear( + profile[g]["record_diff_200_clear"], __type="s32" + ), + E.diff_250_clear( + profile[g]["record_diff_250_clear"], __type="s32" + ), + E.diff_300_clear( + profile[g]["record_diff_300_clear"], __type="s32" + ), + E.diff_350_clear( + profile[g]["record_diff_350_clear"], __type="s32" + ), + E.diff_400_clear( + profile[g]["record_diff_400_clear"], __type="s32" + ), + E.diff_450_clear( + profile[g]["record_diff_450_clear"], __type="s32" + ), + E.diff_500_clear( + profile[g]["record_diff_500_clear"], __type="s32" + ), + E.diff_550_clear( + profile[g]["record_diff_550_clear"], __type="s32" + ), + E.diff_600_clear( + profile[g]["record_diff_600_clear"], __type="s32" + ), + E.diff_650_clear( + profile[g]["record_diff_650_clear"], __type="s32" + ), + E.diff_700_clear( + profile[g]["record_diff_700_clear"], __type="s32" + ), + E.diff_750_clear( + profile[g]["record_diff_750_clear"], __type="s32" + ), + E.diff_800_clear( + profile[g]["record_diff_800_clear"], __type="s32" + ), + E.diff_850_clear( + profile[g]["record_diff_850_clear"], __type="s32" + ), + E.diff_900_clear( + profile[g]["record_diff_900_clear"], __type="s32" + ), + E.diff_950_clear( + profile[g]["record_diff_950_clear"], __type="s32" + ), + ), + ) + for g in ["guitarfreaks", "drummania"] + ], + ), + E.groove( + E.extra_gauge(profile[g]["groove_extra_gauge"], __type="s32"), + E.encore_gauge(profile[g]["groove_encore_gauge"], __type="s32"), + E.encore_cnt(profile[g]["groove_encore_cnt"], __type="s32"), + E.encore_success(profile[g]["groove_encore_success"], __type="s32"), + E.unlock_point(profile[g]["groove_unlock_point"], __type="s32"), + ), + E.finish(1, __type="bool"), + no=no, + ), + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/gitadora/playablemusic.py b/modules/gitadora/playablemusic.py new file mode 100644 index 0000000..4b974f1 --- /dev/null +++ b/modules/gitadora/playablemusic.py @@ -0,0 +1,122 @@ +import lxml.etree as ET +from os import path + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E + +router = APIRouter(prefix="/local", tags=["local"]) +router.model_whitelist = ["M32"] + + +@router.post("/{gameinfo}/{ver}_playablemusic/get") +async def gitadora_playablemusic_get(ver: str, request: Request): + request_info = await core_process_request(request) + + # the game freezes if response has no songs + # so make sure there is at least one + # in case mdb isn't supplied + songs = { + 0: { + "xg_diff_list": [ + "0", + "100", + "295", + "395", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "160", + "490", + "585", + "0", + ], + "contain_stat": ["2", "2"], + "data_ver": 115, + } + } + + if ver == "fuzzup": + short_ver = "fz" + elif ver == "highvoltage": + short_ver = "hv" + elif ver == "nextage": + short_ver = "nt" + elif ver == "exchain": + short_ver = "ex" + elif ver == "matixx": + short_ver = "mt" + + if not short_ver: + short_ver = "MISSING_FALLBACK" + + for f in ( + path.join("modules", "gitadora", f"mdb_{short_ver}.xml"), + path.join(f"mdb_{short_ver}.xml"), + ): + if path.exists(f): + with open(f, "r", encoding="utf-8") as fp: + + tree = ET.parse(fp, ET.XMLParser()) + root = tree.getroot() + + for entry in root: + if entry.tag == "mdb_data": + lvl = entry.find("xg_diff_list").text.split(" ") + if short_ver in ("fz", "hv", "nt", "ex"): + d_ver = int(entry.find("data_ver").text) + else: + d_ver = 115 + + mid = entry.find("music_id").text + songs[mid] = {} + songs[mid]["xg_diff_list"] = lvl[:5] + lvl[10:] + lvl[5:10] + songs[mid]["contain_stat"] = entry.find( + "contain_stat" + ).text.split(" ") + songs[mid]["data_ver"] = d_ver + break + + response = E.response( + E( + f"{ver}_playablemusic", + E.hot( + E.major(-1, __type="s32"), + E.minor(-1, __type="s32"), + ), + E.musicinfo( + *[ + E.music( + E.id(s, __type="s32"), + E.cont_gf( + 1 if int(songs[s]["contain_stat"][0]) != 0 else 0, + __type="bool", + ), + E.cont_dm( + 1 if int(songs[s]["contain_stat"][1]) != 0 else 0, + __type="bool", + ), + E.is_secret(0, __type="bool"), + E.is_hot( + 1 + if (int(songs[s]["contain_stat"][0]) & 1) + or (int(songs[s]["contain_stat"][1]) & 1) + else 0, + __type="bool", + ), + E.data_ver(songs[s]["data_ver"], __type="s32"), + E.diff(songs[s]["xg_diff_list"], __type="u16"), + ) + for s in songs + ], + nr=len(songs), + ), + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/gitadora/shopinfo.py b/modules/gitadora/shopinfo.py new file mode 100644 index 0000000..0e41687 --- /dev/null +++ b/modules/gitadora/shopinfo.py @@ -0,0 +1,31 @@ +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E + +router = APIRouter(prefix="/local", tags=["local"]) +router.model_whitelist = ["M32"] + + +@router.post("/{gameinfo}/{ver}_shopinfo/regist") +async def gitadora_shopinfo_regist(ver: str, request: Request): + request_info = await core_process_request(request) + + response = E.response( + E( + f"{ver}_shopinfo", + E.data( + E.cabid(1, __type="u32"), + E.locationid("EA000001", __type="str"), + E.is_send(0, __type="u8"), + ), + E.temperature( + E.is_send(0, __type="bool"), + ), + E.tax( + E.tax_phase(1, __type="s32"), + ), + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers)