From ff13f9c22d9b7ad690f4491afb2e9ae0784e7e58 Mon Sep 17 00:00:00 2001 From: drmext <71258889+drmext@users.noreply.github.com> Date: Fri, 21 Oct 2022 01:23:54 +0000 Subject: [PATCH] Implement IIDX 30 RESIDENT --- README.md | 1 + core_common.py | 4 +- modules/iidx/iidx29gamesystem.py | 1 + modules/iidx/iidx30gamesystem.py | 77 +++ modules/iidx/iidx30grade.py | 122 ++++ modules/iidx/iidx30lobby.py | 75 +++ modules/iidx/iidx30music.py | 458 +++++++++++++ modules/iidx/iidx30pc.py | 1066 ++++++++++++++++++++++++++++++ modules/iidx/iidx30ranking.py | 20 + modules/iidx/iidx30shop.py | 69 ++ 10 files changed, 1892 insertions(+), 1 deletion(-) create mode 100644 modules/iidx/iidx30gamesystem.py create mode 100644 modules/iidx/iidx30grade.py create mode 100644 modules/iidx/iidx30lobby.py create mode 100644 modules/iidx/iidx30music.py create mode 100644 modules/iidx/iidx30pc.py create mode 100644 modules/iidx/iidx30ranking.py create mode 100644 modules/iidx/iidx30shop.py diff --git a/README.md b/README.md index db49e35..81d1d3e 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,5 @@ Edit services url and enable url_slash - 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 3fdc52f..552aa75 100644 --- a/core_common.py +++ b/core_common.py @@ -50,7 +50,9 @@ 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 >= 2021101300: + 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: return 18 diff --git a/modules/iidx/iidx29gamesystem.py b/modules/iidx/iidx29gamesystem.py index be517fe..e710839 100644 --- a/modules/iidx/iidx29gamesystem.py +++ b/modules/iidx/iidx29gamesystem.py @@ -29,6 +29,7 @@ async def iidx29gamesystem_systeminfo(request: Request): E.gradeOpenPhase(val=2), E.isEiseiOpenFlg(val=1), E.WorldTourismOpenList(val=1), + E.BPLBattleOpenPhase(val=2), *[E.music_open( E.music_id(s, __type="s32"), E.kind(0, __type="s32"), diff --git a/modules/iidx/iidx30gamesystem.py b/modules/iidx/iidx30gamesystem.py new file mode 100644 index 0000000..94896ef --- /dev/null +++ b/modules/iidx/iidx30gamesystem.py @@ -0,0 +1,77 @@ +import config + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E + +router = APIRouter(prefix="/local2", tags=["local2"]) +router.model_whitelist = ["LDJ"] + + +@router.post('/{gameinfo}/IIDX30gameSystem/systemInfo') +async def iidx30gamesystem_systeminfo(request: Request): + request_info = await core_process_request(request) + + unlock = () #(28008, 28065, 28073, 28088, 28089, 29027, 29094, 29095) + sp_dp = (0, 1) + + response = E.response( + E.IIDX30gameSystem( + E.arena_schedule( + E.phase(2, __type="u8"), + E.start(1605784800, __type="u32"), + E.end(1605871200, __type="u32"), + ), + E.CommonBossPhase(val=0), + E.Event1InternalPhase(val=0), + E.ExtraBossEventPhase(val=0), + E.isNewSongAnother12OpenFlg(val=1), + E.gradeOpenPhase(val=2), + E.isEiseiOpenFlg(val=1), + E.WorldTourismOpenList(val=1), + E.BPLBattleOpenPhase(val=2), + *[E.music_open( + E.music_id(s, __type="s32"), + E.kind(0, __type="s32"), + ) for s in unlock], + *[E.arena_reward( + E.index(unlock.index(s), __type="s32"), + E.cube_num((unlock.index(s) + 1) * 50, __type="s32"), + E.kind(0, __type="s32"), + E.value(s, __type="str"), + ) for s in unlock], + *[E.arena_music_difficult( + E.play_style(s, __type="s32"), + E.arena_class(-1, __type="s32"), + E.low_difficult(1, __type="s32"), + E.high_difficult(12, __type="s32"), + E.is_leggendaria(1, __type="bool"), + E.force_music_list_id(0, __type="s32"), + ) for s in sp_dp], + *[E.arena_cpu_define( + E.play_style(s, __type="s32"), + E.arena_class(-1, __type="s32"), + E.grade_id(18, __type="s32"), + E.low_music_difficult(8, __type="s32"), + E.high_music_difficult(12, __type="s32"), + E.is_leggendaria(0, __type="bool"), + ) for s in sp_dp], + *[E.maching_class_range( + E.play_style(s[0], __type="s32"), + E.matching_class(s[1], __type="s32"), + E.low_arena_class(0, __type="s32"), + E.high_arena_class(19, __type="s32"), + ) for s in ((0, 2), (0, 1), (1, 2), (1, 1))], + *[E.arena_force_music( + E.play_style(s, __type="s32"), + E.force_music_list_id(0, __type="s32"), + E.index(0, __type="s32"), + E.music_id(1000, __type="s32"), + E.note_grade(0, __type="s32"), + E.is_active(s, __type="bool"), + ) for s in sp_dp], + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/iidx/iidx30grade.py b/modules/iidx/iidx30grade.py new file mode 100644 index 0000000..4ce76bb --- /dev/null +++ b/modules/iidx/iidx30grade.py @@ -0,0 +1,122 @@ +import time + +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="/local2", tags=["local2"]) +router.model_whitelist = ["LDJ"] + +def get_profile(iidx_id): + return get_db().table('iidx_profile').get( + where('iidx_id') == iidx_id + ) + +@router.post('/{gameinfo}/IIDX30grade/raised') +async def iidx30grade_raised(request: Request): + request_info = await core_process_request(request) + game_version = request_info['game_version'] + + timestamp = time.time() + + iidx_id = int(request_info['root'][0].attrib['iidxid']) + achi = int(request_info['root'][0].attrib['achi']) + cstage = int(request_info['root'][0].attrib['cstage']) + gid = int(request_info['root'][0].attrib['gid']) + gtype = int(request_info['root'][0].attrib['gtype']) + is_ex = int(request_info['root'][0].attrib['is_ex']) + is_mirror = int(request_info['root'][0].attrib['is_mirror']) + + db = get_db() + db.table('iidx_class').insert( + { + 'timestamp': timestamp, + 'game_version': game_version, + 'iidx_id': iidx_id, + 'achi': achi, + 'cstage': cstage, + 'gid': gid, + 'gtype': gtype, + 'is_ex': is_ex, + 'is_mirror': is_mirror, + }, + ) + + profile = get_profile(iidx_id) + game_profile = profile['version'].get(str(game_version), {}) + + best_class = db.table('iidx_class_best').get( + (where('iidx_id') == iidx_id) + & (where('game_version') == game_version) + & (where('gid') == gid) + & (where('gtype') == gtype) + ) + + best_class = {} if best_class is None else best_class + + best_class_data = { + 'game_version': game_version, + 'iidx_id': iidx_id, + 'achi': max(achi, best_class.get('achi', achi)), + 'cstage': max(cstage, best_class.get('cstage', cstage)), + 'gid': gid, + 'gtype': gtype, + 'is_ex': is_ex, + 'is_mirror': is_mirror, + } + + db.table('iidx_class_best').upsert( + best_class_data, + (where('iidx_id') == iidx_id) + & (where('game_version') == game_version) + & (where('gid') == gid) + & (where('gtype') == gtype) + ) + + best_class_plays = db.table('iidx_class_best').search( + (where('game_version') == game_version) + & (where('iidx_id') == iidx_id) + ) + + grades = [] + for record in best_class_plays: + grades.append([ + record['gtype'], + record['gid'], + record['cstage'], + record['achi'] + ]) + + game_profile['grade_values'] = grades + + grade_sp = db.table('iidx_class_best').search( + (where('iidx_id') == iidx_id) + & (where('gtype') == 0) + & (where('cstage') == 4) + ) + + game_profile['grade_single'] = max([x['gid'] for x in grade_sp], default=-1) + + grade_dp = db.table('iidx_class_best').search( + (where('iidx_id') == iidx_id) + & (where('gtype') == 1) + & (where('cstage') == 4) + ) + + game_profile['grade_double'] = max([x['gid'] for x in grade_dp], default=-1) + + profile['version'][str(game_version)] = game_profile + + db.table('iidx_profile').upsert(profile, where('game_version') == game_version) + + response = E.response( + E.IIDX30grade( + pnum=1 + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/iidx/iidx30lobby.py b/modules/iidx/iidx30lobby.py new file mode 100644 index 0000000..9cbf609 --- /dev/null +++ b/modules/iidx/iidx30lobby.py @@ -0,0 +1,75 @@ +import config + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E + +router = APIRouter(prefix="/local2", tags=["local2"]) +router.model_whitelist = ["LDJ"] + + +@router.post('/{gameinfo}/IIDX30lobby/entry') +async def iidx30lobby_entry(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30lobby() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + +@router.post('/{gameinfo}/IIDX30lobby/update') +async def iidx30lobby_update(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30lobby() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + +@router.post('/{gameinfo}/IIDX30lobby/delete') +async def iidx30lobby_delete(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30lobby() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + +@router.post('/{gameinfo}/IIDX30lobby/bplbattle_entry') +async def iidx30lobby_bplbattle_entry(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30lobby() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + +@router.post('/{gameinfo}/IIDX30lobby/bplbattle_update') +async def iidx30lobby_bplbattle_update(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30lobby() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + +@router.post('/{gameinfo}/IIDX30lobby/bplbattle_delete') +async def iidx30lobby_bplbattle_delete(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30lobby() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/iidx/iidx30music.py b/modules/iidx/iidx30music.py new file mode 100644 index 0000000..7767158 --- /dev/null +++ b/modules/iidx/iidx30music.py @@ -0,0 +1,458 @@ +import time +from enum import IntEnum + +from fastapi import APIRouter, Request, Response +from tinydb import where + +from core_common import core_process_request, core_prepare_response, E +from core_database import get_db + +import config + +router = APIRouter(prefix='/local2', tags=['local2']) +router.model_whitelist = ['LDJ'] + + +class ClearFlags(IntEnum): + NO_PLAY = 0 + FAILED = 1 + ASSIST_CLEAR = 2 + EASY_CLEAR = 3 + CLEAR = 4 + HARD_CLEAR = 5 + EX_HARD_CLEAR = 6 + FULL_COMBO = 7 + + +@router.post('/{gameinfo}/IIDX30music/getrank') +async def iidx30music_getrank(request: Request): + request_info = await core_process_request(request) + game_version = request_info['game_version'] + + iidxid = int(request_info['root'][0].attrib['iidxid']) + play_style = int(request_info['root'][0].attrib['cltype']) + + all_scores = {} + db = get_db() + + profile = db.table('iidx_profile').get(where('iidx_id') == iidxid)['version'][str(game_version)] + + if play_style == 0: + rivals = [ + profile.get("sp_rival_1_iidx_id", 0), + profile.get("sp_rival_2_iidx_id", 0), + profile.get("sp_rival_3_iidx_id", 0), + profile.get("sp_rival_4_iidx_id", 0), + profile.get("sp_rival_5_iidx_id", 0), + ] + elif play_style == 1: + rivals = [ + profile.get("dp_rival_1_iidx_id", 0), + profile.get("dp_rival_2_iidx_id", 0), + profile.get("dp_rival_3_iidx_id", 0), + profile.get("dp_rival_4_iidx_id", 0), + profile.get("dp_rival_5_iidx_id", 0), + ] + + for record in db.table('iidx_scores_best').search( + (where('music_id') < (game_version + 1) * 1000) + & (where('play_style') == play_style) + ): + if record['iidx_id'] == iidxid: + rival_idx = -1 + elif record['iidx_id'] in rivals: + rival_idx = rivals.index(record['iidx_id']) + else: + continue + music_id = record['music_id'] + clear_flg = record['clear_flg'] + ex_score = record['ex_score'] + miss_count = record['miss_count'] + chart_id = record['chart_id'] + + if (rival_idx, music_id) not in all_scores: + all_scores[rival_idx, music_id] = { + 0: {'clear_flg': -1, 'ex_score': -1, 'miss_count': -1}, + 1: {'clear_flg': -1, 'ex_score': -1, 'miss_count': -1}, + 2: {'clear_flg': -1, 'ex_score': -1, 'miss_count': -1}, + 3: {'clear_flg': -1, 'ex_score': -1, 'miss_count': -1}, + 4: {'clear_flg': -1, 'ex_score': -1, 'miss_count': -1}, + } + + all_scores[rival_idx, music_id][chart_id]['clear_flg'] = clear_flg + all_scores[rival_idx, music_id][chart_id]['ex_score'] = ex_score + all_scores[rival_idx, music_id][chart_id]['miss_count'] = miss_count + + top_scores = {} + for record in db.table('iidx_scores_best').search( + (where('music_id') < (game_version + 1) * 1000) + & (where('play_style') == play_style) + ): + music_id = record['music_id'] + ex_score = record['ex_score'] + chart_id = record['chart_id'] + iidx_id = record['iidx_id'] + + if music_id not in top_scores: + top_scores[music_id] = { + 0: {'djname': "", 'clear_flg': -1, 'ex_score': -1}, + 1: {'djname': "", 'clear_flg': -1, 'ex_score': -1}, + 2: {'djname': "", 'clear_flg': -1, 'ex_score': -1}, + 3: {'djname': "", 'clear_flg': -1, 'ex_score': -1}, + 4: {'djname': "", 'clear_flg': -1, 'ex_score': -1}, + } + + if ex_score > top_scores[music_id][chart_id]['ex_score']: + top_name = db.table('iidx_profile').get(where('iidx_id') == iidx_id)['version'][str(game_version)]['djname'] + top_scores[music_id][chart_id]['djname'] = top_name + top_scores[music_id][chart_id]['clear_flg'] = 1 + top_scores[music_id][chart_id]['ex_score'] = ex_score + + response = E.response( + E.IIDX30music( + E.style(type=play_style), + *[E.m([ + i, + k, + *[all_scores[i, k][d]['clear_flg'] for d in range(5)], + *[all_scores[i, k][d]['ex_score'] for d in range(5)], + *[all_scores[i, k][d]['miss_count'] for d in range(5)], + ], __type='s16') for i, k in all_scores], + *[E.top( + E.detail([ + k, + *[top_scores[k][d]['clear_flg'] for d in range(5)], + *[top_scores[k][d]['ex_score'] for d in range(5)], + ], __type='s16'), + name0=top_scores[k][0]['djname'], + name1=top_scores[k][1]['djname'], + name2=top_scores[k][2]['djname'], + name3=top_scores[k][3]['djname'], + name4=top_scores[k][4]['djname'] + ) for k in top_scores] + ) + ) + + assert (response is not None) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30music/crate') +async def iidx30music_crate(request: Request): + request_info = await core_process_request(request) + game_version = request_info['game_version'] + + db = get_db() + all_score_stats = db.table('iidx_score_stats').search( + (where('music_id') < (game_version + 1) * 1000) + ) + + crate = {} + fcrate = {} + for stat in all_score_stats: + if stat['music_id'] not in crate: + crate[stat['music_id']] = [1001] * 10 + if stat['music_id'] not in fcrate: + fcrate[stat['music_id']] = [1001] * 10 + + if stat['play_style'] == 1: + dp_idx = 5 + else: + dp_idx = 0 + + crate[stat['music_id']][stat['chart_id'] + dp_idx] = int(stat['clear_rate']) + fcrate[stat['music_id']][stat['chart_id'] + dp_idx] = int(stat['fc_rate']) + + response = E.response( + E.IIDX30music( + *[E.c(crate[k] + fcrate[k], mid=k, __type="s32") for k in crate] + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30music/reg') +async def iidx30music_reg(request: Request): + request_info = await core_process_request(request) + game_version = request_info['game_version'] + + timestamp = time.time() + + log = request_info['root'][0].find('music_play_log') + + clear_flg = int(request_info['root'][0].attrib['cflg']) + clid = int(request_info['root'][0].attrib['clid']) + is_death = int(request_info['root'][0].attrib['is_death']) + pid = int(request_info['root'][0].attrib['pid']) + + play_style = int(log.attrib['play_style']) + ex_score = int(log.attrib['ex_score']) + folder_type = int(log.attrib['folder_type']) + gauge_type = int(log.attrib['gauge_type']) + graph_type = int(log.attrib['graph_type']) + great_num = int(log.attrib['great_num']) + iidx_id = int(log.attrib['iidx_id']) + miss_num = int(log.attrib['miss_num']) + mode_type = int(log.attrib['mode_type']) + music_id = int(log.attrib['music_id']) + note_id = int(log.attrib['note_id']) + option1 = int(log.attrib['option1']) + option2 = int(log.attrib['option2']) + pgreat_num = int(log.attrib['pgreat_num']) + + ghost = log.find("ghost").text + ghost_gauge = log.find("ghost_gauge").text + + db = get_db() + db.table('iidx_scores').insert( + { + 'timestamp': timestamp, + 'game_version': game_version, + 'iidx_id': iidx_id, + 'pid': pid, + 'clear_flg': clear_flg, + 'is_death': is_death, + 'music_id': music_id, + 'play_style': play_style, + 'chart_id': note_id, + 'pgreat_num': pgreat_num, + 'great_num': great_num, + 'ex_score': ex_score, + 'miss_count': miss_num, + 'folder_type': folder_type, + 'gauge_type': gauge_type, + 'graph_type': graph_type, + 'mode_type': mode_type, + 'option1': option1, + 'option2': option2, + 'ghost': ghost, + 'ghost_gauge': ghost_gauge, + }, + ) + + best_score = db.table('iidx_scores_best').get( + (where('iidx_id') == iidx_id) + & (where('play_style') == play_style) + & (where('music_id') == music_id) + & (where('chart_id') == note_id) + ) + best_score = {} if best_score is None else best_score + + if clear_flg < ClearFlags.EASY_CLEAR: + miss_num = -1 + best_miss_count = best_score.get('miss_count', miss_num) + if best_miss_count == -1: + miss_count = max(miss_num, best_miss_count) + elif clear_flg > ClearFlags.ASSIST_CLEAR: + miss_count = min(miss_num, best_miss_count) + else: + miss_count = best_miss_count + best_ex_score = best_score.get('ex_score', ex_score) + best_score_data = { + 'game_version': game_version, + 'iidx_id': iidx_id, + 'pid': pid, + 'play_style': play_style, + 'music_id': music_id, + 'chart_id': note_id, + 'miss_count': miss_count, + 'ex_score': max(ex_score, best_ex_score), + 'ghost': ghost if ex_score >= best_ex_score else best_score.get('ghost', ghost), + 'ghost_gauge': ghost_gauge if ex_score >= best_ex_score else best_score.get('ghost_gauge', ghost_gauge), + 'clear_flg': max(clear_flg, best_score.get('clear_flg', clear_flg)), + 'gauge_type': gauge_type if ex_score >= best_ex_score else best_score.get('gauge_type', gauge_type), + } + + db.table('iidx_scores_best').upsert( + best_score_data, + (where('iidx_id') == iidx_id) + & (where('play_style') == play_style) + & (where('music_id') == music_id) + & (where('chart_id') == note_id) + ) + + score_stats = db.table('iidx_score_stats').get( + (where('music_id') == music_id) + & (where('play_style') == play_style) + & (where('chart_id') == note_id) + ) + score_stats = {} if score_stats is None else score_stats + + score_stats['game_version'] = game_version + score_stats['play_style'] = play_style + score_stats['music_id'] = music_id + score_stats['chart_id'] = note_id + score_stats['play_count'] = score_stats.get('play_count', 0) + 1 + score_stats['fc_count'] = score_stats.get('fc_count', 0) + (1 if clear_flg == ClearFlags.FULL_COMBO else 0) + score_stats['clear_count'] = score_stats.get('clear_count', 0) + (1 if clear_flg >= ClearFlags.EASY_CLEAR else 0) + score_stats['fc_rate'] = int((score_stats['fc_count'] / score_stats['play_count']) * 1000) + score_stats['clear_rate'] = int((score_stats['clear_count'] / score_stats['play_count']) * 1000) + + db.table('iidx_score_stats').upsert( + score_stats, + (where('music_id') == music_id) + & (where('play_style') == play_style) + & (where('chart_id') == note_id) + ) + + ranklist_data = [] + ranklist_scores = db.table('iidx_scores_best').search( + (where('play_style') == play_style) + & (where('music_id') == music_id) + & (where('chart_id') == note_id) + ) + ranklist_scores = [] if ranklist_scores is None else ranklist_scores + + ranklist_scores_ranked = [] + + for score in ranklist_scores: + profile = db.table('iidx_profile').get(where('iidx_id') == score['iidx_id']) + + if profile is None or str(game_version) not in profile['version']: + continue + + game_profile = profile['version'][str(game_version)] + + ranklist_scores_ranked.append({ + 'opname': config.arcade, + 'name': game_profile['djname'], + 'pid': game_profile['region'], + 'body': game_profile['body'], + 'face': game_profile['face'], + 'hair': game_profile['hair'], + 'hand': game_profile['hand'], + 'head': game_profile['head'], + 'dgrade': game_profile['grade_double'], + 'sgrade': game_profile['grade_single'], + 'score': score['ex_score'], + 'iidx_id': score['iidx_id'], + 'clflg': score['clear_flg'], + 'myFlg': score['iidx_id'] == iidx_id + }) + + ranklist_scores_ranked = sorted(ranklist_scores_ranked, key=lambda x: (x['clflg'], x['score']), reverse=True) + + myRank = 0 + for rnum, score in enumerate(ranklist_scores_ranked): + r = E.data( + rnum=rnum + 1, + opname=score['opname'], + name=score['name'], + pid=score['pid'], + body=score['body'], + face=score['face'], + hair=score['hair'], + hand=score['hand'], + head=score['head'], + dgrade=score['dgrade'], + sgrade=score['sgrade'], + score=score['score'], + iidx_id=score['iidx_id'], + clflg=score['clflg'], + myFlg=score['myFlg'], + achieve=0, + ) + ranklist_data.append(r) + + if score['myFlg']: + myRank = rnum + 1 + + response = E.response( + E.IIDX30music( + E.ranklist( + *ranklist_data, + total_user_num=len(ranklist_data) + ), + E.shopdata( + rank=myRank + ), + clid=clid, + crate=score_stats['clear_rate'], + frate=score_stats['fc_rate'], + mid=music_id, + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30music/appoint') +async def iidx30music_appoint(request: Request): + request_info = await core_process_request(request) + + root = request_info['root'][0] + + iidxid = int(root.attrib['iidxid']) + music_id = int(root.attrib['mid']) + chart_id = int(root.attrib['clid']) + ctype = int(root.attrib['ctype']) + subtype = root.attrib['subtype'] + + + db = get_db() + record = db.table('iidx_scores_best').get( + (where('iidx_id') == iidxid) + & (where('music_id') == music_id) + & (where('chart_id') == chart_id) + ) + + vals = [] + if record is not None: + vals.append(E.mydata( + record['ghost'], + score=record['ex_score'], + __type="bin", + __size=len(record['ghost']) // 2, + )) + + if ctype == 1: + sdata = db.table('iidx_scores_best').get( + (where('iidx_id') == int(subtype)) + & (where('music_id') == music_id) + & (where('chart_id') == chart_id) + ) + elif ctype in (2, 4, 10): + sdata = { + 'game_version': 29, + 'ghost': "", + 'ex_score': 0, + 'iidx_id': 0, + 'name': "", + 'pid': 13 + } + + for record in db.table('iidx_scores_best').search( + (where('music_id') == music_id) + & (where('chart_id') == chart_id) + ): + if record['ex_score'] > sdata['ex_score']: + sdata['game_version'] = record['game_version'] + sdata['ghost'] = record['ghost'] + sdata['ex_score'] = record['ex_score'] + sdata['iidx_id'] = record['iidx_id'] + sdata['pid'] = record['pid'] + + if ctype in (1, 2, 4, 10) and sdata['ex_score'] != 0: + vals.append(E.sdata( + sdata['ghost'], + score=sdata['ex_score'], + name=db.table('iidx_profile').get(where('iidx_id') == sdata['iidx_id'])['version'][str(sdata['game_version'])]['djname'], + pid=sdata['pid'], + __type="bin", + __size=len(sdata['ghost']) // 2, + )) + + + response = E.response( + E.IIDX30music( + *vals + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/iidx/iidx30pc.py b/modules/iidx/iidx30pc.py new file mode 100644 index 0000000..daad647 --- /dev/null +++ b/modules/iidx/iidx30pc.py @@ -0,0 +1,1066 @@ +from tinydb import Query, where + +import config +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="/local2", tags=["local2"]) +router.model_whitelist = ["LDJ"] + + +def get_profile(cid): + return get_db().table('iidx_profile').get( + where('card') == cid + ) + + +def get_profile_by_id(iidx_id): + return get_db().table('iidx_profile').get( + where('iidx_id') == iidx_id + ) + + +def get_game_profile(cid, game_version): + profile = get_profile(cid) + + return profile['version'].get(str(game_version), None) + + +def get_game_profile_by_id(iidx_id, game_version): + profile = get_profile_by_id(iidx_id) + + return profile['version'].get(str(game_version), None) + + +def get_id_from_profile(cid): + profile = get_db().table('iidx_profile').get( + where('card') == cid + ) + + djid = "%08d" % profile['iidx_id'] + djid_split = '-'.join([djid[:4], djid[4:]]) + + return profile['iidx_id'], djid_split + + +def calculate_folder_mask(profile): + return profile.get('_show_category_grade', 0) << 0 \ + | (profile.get('_show_category_status', 0) << 1) \ + | (profile.get('_show_category_difficulty', 0) << 2) \ + | (profile.get('_show_category_alphabet', 0) << 3) \ + | (profile.get('_show_category_rival_play', 0) << 4) \ + | (profile.get('_show_category_rival_winlose', 0) << 6) \ + | (profile.get('_show_rival_shop_info', 0) << 7) \ + | (profile.get('_hide_play_count', 0) << 8) \ + | (profile.get('_show_score_graph_cutin', 0) << 9) \ + | (profile.get('_classic_hispeed', 0) << 10) \ + | (profile.get('_hide_iidx_id', 0) << 12) + + +@router.post('/{gameinfo}/IIDX30pc/get') +async def iidx30pc_get(request: Request): + request_info = await core_process_request(request) + game_version = request_info['game_version'] + + cid = request_info['root'][0].attrib['cid'] + profile = get_game_profile(cid, game_version) + djid, djid_split = get_id_from_profile(cid) + + rival_ids = [ + profile.get("sp_rival_1_iidx_id", 0), + profile.get("sp_rival_2_iidx_id", 0), + profile.get("sp_rival_3_iidx_id", 0), + profile.get("sp_rival_4_iidx_id", 0), + profile.get("sp_rival_5_iidx_id", 0), + profile.get("dp_rival_1_iidx_id", 0), + profile.get("dp_rival_2_iidx_id", 0), + profile.get("dp_rival_3_iidx_id", 0), + profile.get("dp_rival_4_iidx_id", 0), + profile.get("dp_rival_5_iidx_id", 0), + ] + rivals = {} + for idx, r in enumerate(rival_ids): + if r == 0: + continue + rivals[idx] = {} + rivals[idx]['spdp'] = 1 if idx < 5 else 2 + + rival_profile = get_game_profile_by_id(r, game_version) + rdjid = "%08d" % r + rdjid_split = '-'.join([rdjid[:4], rdjid[4:]]) + + rivals[idx]['djid'] = rdjid + rivals[idx]['djid_split'] = rdjid_split + rivals[idx]['djname'] = rival_profile['djname'] + rivals[idx]['region'] = rival_profile['region'] + rivals[idx]['sa'] = rival_profile['sach'] + rivals[idx]['sg'] = rival_profile['grade_single'] + rivals[idx]['da'] = rival_profile['dach'] + rivals[idx]['dg'] = rival_profile['grade_double'] + rivals[idx]['body'] = rival_profile['body'] + rivals[idx]['face'] = rival_profile['face'] + rivals[idx]['hair'] = rival_profile['hair'] + rivals[idx]['hand'] = rival_profile['hand'] + rivals[idx]['head'] = rival_profile['head'] + + + response = E.response( + E.IIDX30pc( + E.pcdata( + d_auto_adjust=profile['d_auto_adjust'], + d_auto_scrach=profile['d_auto_scrach'], + d_camera_layout=profile['d_camera_layout'], + d_disp_judge=profile['d_disp_judge'], + d_exscore=profile['d_exscore'], + d_gauge_disp=profile['d_gauge_disp'], + d_ghost_score=profile['d_ghost_score'], + d_gno=profile['d_gno'], + d_graph_score=profile['d_graph_score'], + d_gtype=profile['d_gtype'], + d_hispeed=profile['d_hispeed'], + d_judge=profile['d_judge'], + d_judgeAdj=profile['d_judgeAdj'], + d_lane_brignt=profile['d_lane_brignt'], + d_liflen=profile['d_liflen'], + d_notes=profile['d_notes'], + d_opstyle=profile['d_opstyle'], + d_pace=profile['d_pace'], + d_sdlen=profile['d_sdlen'], + d_sdtype=profile['d_sdtype'], + d_sorttype=profile['d_sorttype'], + d_sub_gno=profile['d_sub_gno'], + d_timing=profile['d_timing'], + d_timing_split=profile['d_timing_split'], + d_tsujigiri_disp=profile['d_tsujigiri_disp'], + d_tune=profile['d_tune'], + d_visualization=profile['d_visualization'], + dach=profile['dach'], + dp_opt=profile['dp_opt'], + dp_opt2=profile['dp_opt2'], + dpnum=profile["dpnum"], + gpos=profile['gpos'], + id=djid, + idstr=djid_split, + mode=profile['mode'], + name=profile['djname'], + ngrade=profile['ngrade'], + pid=profile['region'], + pmode=profile['pmode'], + rtype=profile['rtype'], + s_auto_adjust=profile['s_auto_adjust'], + s_auto_scrach=profile['s_auto_scrach'], + s_camera_layout=profile['s_camera_layout'], + s_disp_judge=profile['s_disp_judge'], + s_exscore=profile['s_exscore'], + s_gauge_disp=profile['s_gauge_disp'], + s_ghost_score=profile['s_ghost_score'], + s_gno=profile['s_gno'], + s_graph_score=profile['s_graph_score'], + s_gtype=profile['s_gtype'], + s_hispeed=profile['s_hispeed'], + s_judge=profile['s_judge'], + s_judgeAdj=profile['s_judgeAdj'], + s_lane_brignt=profile['s_lane_brignt'], + s_liflen=profile['s_liflen'], + s_notes=profile['s_notes'], + s_opstyle=profile['s_opstyle'], + s_pace=profile['s_pace'], + s_sdlen=profile['s_sdlen'], + s_sdtype=profile['s_sdtype'], + s_sorttype=profile['s_sorttype'], + s_sub_gno=profile['s_sub_gno'], + s_timing=profile['s_timing'], + s_timing_split=profile['s_timing_split'], + s_tsujigiri_disp=profile['s_tsujigiri_disp'], + s_tune=profile['s_tune'], + s_visualization=profile['s_visualization'], + sach=profile['sach'], + sp_opt=profile['sp_opt'], + spnum=profile['spnum'], + ), + E.qprodata([profile["head"], profile["hair"], profile["face"], profile["hand"], profile["body"]], + __type="u32", __size=5 * 4), + E.skin( + [ + profile["frame"], + profile["turntable"], + profile["explosion"], + profile["bgm"], + calculate_folder_mask(profile), + profile["sudden"], + profile["judge_pos"], + profile["categoryvoice"], + profile["note"], + profile["fullcombo"], + profile["keybeam"], + profile["judgestring"], + -1, + profile["soundpreview"], + profile["grapharea"], + profile["effector_lock"], + profile["effector_type"], + profile["explosion_size"], + profile["alternate_hcn"], + profile["kokokara_start"], + ], + __type="s16"), + E.rlist( + *[E.rival( + E.is_robo(0, __type="bool"), + E.shop(name=config.arcade), + E.qprodata( + body=rivals[r]['body'], + face=rivals[r]['face'], + hair=rivals[r]['hair'], + hand=rivals[r]['hand'], + head=rivals[r]['head'], + ), + da=rivals[r]['da'], + dg=rivals[r]['dg'], + djname=rivals[r]['djname'], + id=rivals[r]['djid'], + id_str=rivals[r]['djid_split'], + pid=rivals[r]['region'], + sa=rivals[r]['sa'], + sg=rivals[r]['sg'], + spdp=rivals[r]['spdp'], + )for r in rivals], + ), + E.ir_data(), + E.secret_course_data(), + E.deller(deller=profile['deller'], rate=0), + E.secret( + E.flg1(profile.get('secret_flg1', [-1, -1, -1]), __type="s64"), + E.flg2(profile.get('secret_flg2', [-1, -1, -1]), __type="s64"), + E.flg3(profile.get('secret_flg3', [-1, -1, -1]), __type="s64"), + E.flg4(profile.get('secret_flg4', [-1, -1, -1]), __type="s64"), + ), + E.join_shop(join_cflg=1, join_id=10, join_name=config.arcade, joinflg=1), + E.leggendaria(E.flg1(profile.get('leggendaria_flg1', [-1, -1, -1]), __type="s64")), + E.grade( + *[E.g(x, __type="u8") for x in profile['grade_values']], + dgid=profile['grade_double'], + sgid=profile['grade_single'], + ), + E.world_tourism_secret_flg( + E.flg1(profile.get('wt_flg1', [-1, -1, -1]), __type="s64"), + E.flg2(profile.get('wt_flg2', [-1, -1, -1]), __type="s64"), + ), + E.lightning_setting( + E.slider(profile.get('lightning_setting_slider', [0] * 7), __type="s32"), + E.light(profile.get('lightning_setting_light', [1] * 10), __type="bool"), + E.concentration(profile.get('lightning_setting_concentration', 0), __type="bool"), + headphone_vol=profile.get('lightning_setting_headphone_vol', 0), + resistance_sp_left=profile.get('lightning_setting_resistance_sp_left', 0), + resistance_sp_right=profile.get('lightning_setting_resistance_sp_right', 0), + resistance_dp_left=profile.get('lightning_setting_resistance_dp_left', 0), + resistance_dp_right=profile.get('lightning_setting_resistance_dp_right', 0), + skin_0=profile.get('lightning_setting_skin_0', 0), + flg_skin_0=profile.get('lightning_setting_flg_skin_0', 0), + ), + E.arena_data( + E.achieve_data( + arena_class=-1, + counterattack_num=0, + best_top_class_continuing=0, + now_top_class_continuing=0, + play_style=0, + rating_value=90, + ), + E.achieve_data( + arena_class=-1, + counterattack_num=0, + best_top_class_continuing=0, + now_top_class_continuing=0, + play_style=1, + rating_value=90, + ), + E.cube_data( + cube=200, + season_id=0, + ), + play_num=6, + play_num_dp=3, + play_num_sp=3, + prev_best_class_sp=18, + prev_best_class_dp=18, + ), + E.follow_data(), + E.classic_course_data(), + E.bind_eaappli(), + E.ea_premium_course(), + E.enable_qr_reward(), + E.nostalgia_open(), + E.event_1( + story_prog=profile.get('event_1_story_prog', 0), + last_select_area=profile.get('event_1_last_select_area', 0), + failed_num=profile.get('event_1_failed_num', 0), + event_play_num=profile.get('event_1_event_play_num', 0), + last_select_area_id=profile.get('event_1_last_select_area_id', 0), + last_select_platform_type=profile.get('event_1_last_select_platform_type', 0), + last_select_platform_id=profile.get('event_1_last_select_platform_id', 0), + ), + E.language_setting(language=profile['language_setting']), + E.movie_agreement(agreement_version=profile['movie_agreement']), + E.bpl_virtual(), + E.lightning_play_data(spnum=profile['lightning_play_data_spnum'], + dpnum=profile['lightning_play_data_dpnum']), + E.weekly( + mid=-1, + wid=1, + ), + E.packinfo( + music_0=-1, + music_1=-1, + music_2=-1, + pack_id=1, + ), + E.kac_entry_info( + E.enable_kac_deller(), + E.disp_kac_mark(), + E.open_kac_common_music(), + E.open_kac_new_a12_music(), + E.is_kac_entry(), + E.is_kac_evnet_entry(), + ), + E.orb_data(rest_orb=100, present_orb=100), + E.visitor(anum=1, pnum=2, snum=1, vs_flg=1), + E.tonjyutsu(black_pass=-1, platinum_pass=-1), + E.pay_per_use(item_num=99), + E.old_linkage_secret_flg( + floor_infection4=-1, + bemani_janken=-1, + ichika_rush=-1, + nono_rush=-1, + song_battle=-1, + ), + E.floor_infection4(music_list=-1), + E.bemani_vote(music_list=-1), + E.bemani_janken_meeting(music_list=-1), + E.bemani_rush(music_list_ichika=-1, music_list_nono=-1), + E.ultimate_mobile_link(music_list=-1), + E.bemani_musiq_fes(music_list=-1), + E.busou_linkage(music_list=-1), + E.busou_linkage_2(music_list=-1), + E.valkyrie_linkage_data(progress=-1), + E.valkyrie_linkage_2_data(progress=-1), + E.achievements( + E.trophy( + profile.get('achievements_trophy', [])[:10], + __type="s64" + ), + pack=profile.get('achievements_pack_id', 0), + pack_comp=profile.get('achievements_pack_comp', 0), + last_weekly=profile.get('achievements_last_weekly', 0), + weekly_num=profile.get('achievements_weekly_num', 0), + visit_flg=profile.get('achievements_visit_flg', 0), + rival_crush=0, + ), + E.notes_radar( + E.radar_score( + profile['notes_radar_single'], + __type="s32", + ), + style=0, + ), + E.notes_radar( + E.radar_score( + profile['notes_radar_double'], + __type="s32", + ), + style=1, + ), + E.dj_rank( + E.rank( + profile['dj_rank_single_rank'], + __type="s32", + ), + E.point( + profile['dj_rank_single_point'], + __type="s32", + ), + style=0, + ), + E.dj_rank( + E.rank( + profile['dj_rank_double_rank'], + __type="s32", + ), + E.point( + profile['dj_rank_double_point'], + __type="s32", + ), + style=1, + ), + E.step( + E.is_track_ticket( + profile['stepup_is_track_ticket'], + __type="bool", + ), + dp_fluctuation=profile['stepup_dp_fluctuation'], + dp_level=profile['stepup_dp_level'], + dp_mplay=profile['stepup_dp_mplay'], + enemy_damage=profile['stepup_enemy_damage'], + enemy_defeat_flg=profile['stepup_enemy_defeat_flg'], + mission_clear_num=profile['stepup_mission_clear_num'], + progress=profile['stepup_progress'], + sp_fluctuation=profile['stepup_sp_fluctuation'], + sp_level=profile['stepup_sp_level'], + sp_mplay=profile['stepup_sp_mplay'], + tips_read_list=profile['stepup_tips_read_list'], + total_point=profile['stepup_total_point'], + ), + E.skin_customize_flg( + skin_frame_flg=profile['skin_customize_flag_frame'], + skin_bgm_flg=profile['skin_customize_flag_bgm'], + skin_lane_flg3=profile['skin_customize_flag_lane'], + ), + E.badge( + E.badge_data( + category_id=0, + badge_flg_id=0, + badge_flg=0, + ), + E.badge_equip( + E.equip_flg(0, __type="bool"), + category_id=0, + badge_flg_id=0, + index=0, + slot=0, + ) + ) + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30pc/common') +async def iidx30pc_common(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30pc( + E.monthly_mranking( + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + __type="u16"), + E.total_mranking( + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + __type="u16"), + # E.internet_ranking(), + # E.secret_ex_course(), + E.kac_mid([-1, -1, -1, -1, -1], __type="s32"), + E.kac_clid([2, 2, 2, 2, 2], __type="s32"), + E.ir(beat=3), + E.cm(compo='cm_ultimate', folder='cm_ultimate', id=0), + E.tdj_cm( + E.cm(filename='cm_bn_001', id=0), + E.cm(filename='cm_bn_002', id=1), + E.cm(filename='event_bn_001', id=2), + E.cm(filename='event_bn_004', id=3), + E.cm(filename='event_bn_006', id=4), + E.cm(filename='fipb_001', id=5), + E.cm(filename='year_bn_004', id=6), + E.cm(filename='year_bn_005', id=7), + E.cm(filename='year_bn_006_2', id=8), + E.cm(filename='year_bn_007', id=9), + ), + # E.playvideo_disable_music(E.music(musicid=-1)), + # E.music_movie_suspend(E.music(music_id=-1, kind=0, name='')), + # E.bpl_virtual(), + E.movie_agreement(version=1), + E.license('None', __type="str"), + E.file_recovery(url=str(config.ip)), + E.movie_upload(url=str(config.ip)), + # E.button_release_frame(frame=''), + # E.trigger_logic_type(type=''), + # E.cm_movie_info(type=''), + E.escape_package_info(), + # E.expert(phase=1), + # E.expert_random_secret(phase=1), + E.boss(phase=0), # disable event + E.vip_pass_black(), + E.eisei(open=1), + E.deller_bonus(open=1), + E.newsong_another(open=1), + # E.pcb_check(flg=0) + E.expert_secret_full_open(), + E.eaorder_phase(phase=-1), + E.common_evnet(flg=-1), + E.system_voice_phase(phase=random.randint(1, 10)), # TODO: Figure out range + E.extra_boss_event(phase=6), + E.event1_phase(phase=4), + E.premium_area_news(open=1), + E.premium_area_qpro(open=1), + # E.disable_same_triger(frame=-1), + E.play_video(), + E.world_tourism(open_list=1), + E.bpl_battle(phase=1), + E.display_asio_logo(), + # E.force_rom_check(), + E.lane_gacha(), + # E.fps_fix(), + # E.save_unsync_log(), + expire=600 + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30pc/save') +async def iidx30pc_save(request: Request): + request_info = await core_process_request(request) + game_version = request_info['game_version'] + + xid = int(request_info['root'][0].attrib['iidxid']) + cid = request_info['root'][0].attrib['cid'] + clt = int(request_info['root'][0].attrib['cltype']) + + profile = get_profile(cid) + game_profile = profile['version'].get(str(game_version), {}) + + for k in [ + 'd_auto_adjust', + 'd_auto_scrach', + 'd_camera_layout', + 'd_disp_judge', + 'd_gauge_disp', + 'd_ghost_score', + 'd_gno', + 'd_graph_score', + 'd_gtype', + 'd_hispeed', + 'd_judge', + 'd_judgeAdj', + 'd_lane_brignt', + 'd_notes', + 'd_opstyle', + 'd_pace', + 'd_sdlen', + 'd_sdtype', + 'd_sorttype', + 'd_sub_gno', + 'd_timing', + 'd_timing_split', + 'd_tsujigiri_disp', + 'dp_opt', + 'dp_opt2', + 'gpos', + 'mode', + 'ngrade', + 'pmode', + 'rtype', + 's_auto_adjust', + 's_auto_scrach', + 's_camera_layout', + 's_disp_judge', + 's_gauge_disp', + 's_ghost_score', + 's_gno', + 's_graph_score', + 's_gtype', + 's_hispeed', + 's_judge', + 's_judgeAdj', + 's_lane_brignt', + 's_notes', + 's_opstyle', + 's_pace', + 's_sdlen', + 's_sdtype', + 's_sorttype', + 's_sub_gno', + 's_timing', + 's_tsujigiri_disp', + 'sp_opt', + ]: + if k in request_info['root'][0].attrib: + game_profile[k] = request_info['root'][0].attrib[k] + + for k in [ + ('d_liflen', 'd_lift'), + ('dach', 'd_achi'), + ('s_liflen', 's_lift'), + ('sach', 's_achi'), + ]: + if k[1] in request_info['root'][0].attrib: + game_profile[k[0]] = request_info['root'][0].attrib[k[1]] + + lightning_setting = request_info['root'][0].find('lightning_setting') + if lightning_setting is not None: + for k in [ + 'headphone_vol', + 'resistance_dp_left', + 'resistance_dp_right', + 'resistance_sp_left', + 'resistance_sp_right', + ]: + game_profile['lightning_setting_' + k] = int(lightning_setting.attrib[k]) + + slider = lightning_setting.find('slider') + if slider is not None: + game_profile['lightning_setting_slider'] = [int(x) for x in slider.text.split(' ')] + + light = lightning_setting.find('light') + if light is not None: + game_profile['lightning_setting_light'] = [int(x) for x in light.text.split(' ')] + + concentration = lightning_setting.find('concentration') + if concentration is not None: + game_profile['lightning_setting_concentration'] = int(concentration.text) + + lightning_customize_flg = request_info['root'][0].find('lightning_customize_flg') + if lightning_customize_flg is not None: + for k in [ + 'flg_skin_0', + ]: + game_profile['lightning_setting_' + k] = int(lightning_customize_flg.attrib[k]) + + secret = request_info['root'][0].find('secret') + if secret is not None: + for k in ['flg1', 'flg2', 'flg3', 'flg4']: + flg = secret.find(k) + if flg is not None: + game_profile['secret_' + k] = [int(x) for x in flg.text.split(' ')] + + leggendaria = request_info['root'][0].find('leggendaria') + if leggendaria is not None: + for k in ['flg1']: + flg = leggendaria.find(k) + if flg is not None: + game_profile['leggendaria_' + k] = [int(x) for x in flg.text.split(' ')] + + step = request_info['root'][0].find('step') + if step is not None: + for k in [ + 'dp_fluctuation', + 'dp_level', + 'dp_mplay', + 'enemy_damage', + 'enemy_defeat_flg', + 'mission_clear_num', + 'progress', + 'sp_fluctuation', + 'sp_level', + 'sp_mplay', + 'tips_read_list', + 'total_point', + ]: + game_profile['stepup_' + k] = int(step.attrib[k]) + + is_track_ticket = step.find('is_track_ticket') + if is_track_ticket is not None: + game_profile['stepup_is_track_ticket'] = int(is_track_ticket.text) + + dj_ranks = request_info['root'][0].findall('dj_rank') + dj_ranks = [] if dj_ranks is None else dj_ranks + for dj_rank in dj_ranks: + style = int(dj_rank.attrib['style']) + + rank = dj_rank.find('rank') + game_profile['dj_rank_' + ['single', 'double'][style] + '_rank'] = [int(x) for x in rank.text.split(' ')] + + point = dj_rank.find('point') + game_profile['dj_rank_' + ['single', 'double'][style] + '_point'] = [int(x) for x in point.text.split(' ')] + + notes_radars = request_info['root'][0].findall('notes_radar') + notes_radars = [] if notes_radars is None else notes_radars + for notes_radar in notes_radars: + style = int(notes_radar.attrib['style']) + score = notes_radar.find('radar_score') + game_profile['notes_radar_' + ['single', 'double'][style]] = [int(x) for x in score.text.split(' ')] + + achievements = request_info['root'][0].find('achievements') + if achievements is not None: + for k in [ + 'last_weekly', + 'pack_comp', + 'pack_flg', + 'pack_id', + 'play_pack', + 'visit_flg', + 'weekly_num', + ]: + game_profile['achievements_' + k] = int(achievements.attrib[k]) + + trophy = achievements.find('trophy') + if trophy is not None: + game_profile['achievements_trophy'] = [int(x) for x in trophy.text.split(' ')] + + grade = request_info['root'][0].find('grade') + if grade is not None: + grade_values = [] + for g in grade.findall('g'): + grade_values.append([int(x) for x in g.text.split(' ')]) + + profile['grade_single'] = int(grade.attrib['sgid']) + profile['grade_double'] = int(grade.attrib['dgid']) + profile['grade_values'] = grade_values + + deller_amount = game_profile.get('deller', 0) + deller = request_info['root'][0].find('deller') + if deller is not None: + deller_amount = int(deller.attrib['deller']) + game_profile['deller'] = deller_amount + + language = request_info['root'][0].find('language_setting') + if language is not None: + language_value = int(language.attrib['language']) + game_profile['language_setting'] = language_value + + game_profile['spnum'] = game_profile.get('spnum', 0) + (1 if clt == 0 else 0) + game_profile['dpnum'] = game_profile.get('dpnum', 0) + (1 if clt == 1 else 0) + + if request_info['model'] == "TDJ": + game_profile['lightning_play_data_spnum'] = game_profile.get('lightning_play_data_spnum', 0) + (1 if clt == 0 else 0) + game_profile['lightning_play_data_dpnum'] = game_profile.get('lightning_play_data_dpnum', 0) + (1 if clt == 1 else 0) + + profile['version'][str(game_version)] = game_profile + + get_db().table('iidx_profile').upsert(profile, where('card') == cid) + + response = E.response( + E.IIDX30pc( + iidxid=xid, + cltype=clt + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30pc/visit') +async def iidx30pc_visit(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30pc( + aflg=1, + anum=1, + pflg=1, + pnum=1, + sflg=1, + snum=1, + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30pc/reg') +async def iidx30pc_reg(request: Request): + request_info = await core_process_request(request) + game_version = request_info['game_version'] + + cid = request_info['root'][0].attrib['cid'] + name = request_info['root'][0].attrib['name'] + pid = request_info['root'][0].attrib['pid'] + + db = get_db().table('iidx_profile') + all_profiles_for_card = db.get(Query().card == cid) + + if all_profiles_for_card is None: + all_profiles_for_card = { + 'card': cid, + 'version': {} + } + + if 'iidx_id' not in all_profiles_for_card: + iidx_id = random.randint(10000000, 99999999) + all_profiles_for_card['iidx_id'] = iidx_id + + all_profiles_for_card['version'][str(game_version)] = { + 'game_version': game_version, + 'djname': name, + 'region': int(pid), + 'head': 0, + 'hair': 0, + 'face': 0, + 'hand': 0, + 'body': 0, + 'frame': 0, + 'turntable': 0, + 'explosion': 0, + 'bgm': 0, + 'folder_mask': 0, + 'sudden': 0, + 'judge_pos': 0, + 'categoryvoice': 0, + 'note': 0, + 'fullcombo': 0, + 'keybeam': 0, + 'judgestring': 0, + 'soundpreview': 0, + 'grapharea': 0, + 'effector_lock': 0, + 'effector_type': 0, + 'explosion_size': 0, + 'alternate_hcn': 0, + 'kokokara_start': 0, + 'd_auto_adjust': 0, + 'd_auto_scrach': 0, + 'd_camera_layout': 0, + 'd_disp_judge': 0, + 'd_exscore': 0, + 'd_gauge_disp': 0, + 'd_ghost_score': 0, + 'd_gno': 0, + 'd_graph_score': 0, + 'd_gtype': 0, + 'd_hispeed': 0.000000, + 'd_judge': 0, + 'd_judgeAdj': 0, + 'd_lane_brignt': 0, + 'd_liflen': 0, + 'd_notes': 0.000000, + 'd_opstyle': 0, + 'd_pace': 0, + 'd_sdlen': 0, + 'd_sdtype': 0, + 'd_sorttype': 0, + 'd_sub_gno': 0, + 'd_timing': 0, + 'd_timing_split': 0, + 'd_tsujigiri_disp': 0, + 'd_tune': 0, + 'd_visualization': 0, + 'dach': 0, + 'dp_opt': 0, + 'dp_opt2': 0, + 'dpnum': 0, + 'gpos': 0, + 'mode': 0, + 'ngrade': 0, + 'pmode': 0, + 'rtype': 0, + 's_auto_adjust': 0, + 's_auto_scrach': 0, + 's_camera_layout': 0, + 's_disp_judge': 0, + 's_exscore': 0, + 's_gauge_disp': 0, + 's_ghost_score': 0, + 's_gno': 0, + 's_graph_score': 0, + 's_gtype': 0, + 's_hispeed': 0.000000, + 's_judge': 0, + 's_judgeAdj': 0, + 's_lane_brignt': 0, + 's_liflen': 0, + 's_notes': 0.000000, + 's_opstyle': 0, + 's_pace': 0, + 's_sdlen': 0, + 's_sdtype': 0, + 's_sorttype': 0, + 's_sub_gno': 0, + 's_timing': 0, + 's_timing_split': 0, + 's_tsujigiri_disp': 0, + 's_tune': 0, + 's_visualization': 0, + 'sach': 0, + 'sp_opt': 0, + 'spnum': 0, + 'deller': 0, + + # Step up mode + 'stepup_dp_fluctuation': 0, + 'stepup_dp_level': 0, + 'stepup_dp_mplay': 0, + 'stepup_enemy_damage': 0, + 'stepup_enemy_defeat_flg': 0, + 'stepup_mission_clear_num': 0, + 'stepup_progress': 0, + 'stepup_sp_fluctuation': 0, + 'stepup_sp_level': 0, + 'stepup_sp_mplay': 0, + 'stepup_tips_read_list': 0, + 'stepup_total_point': 0, + 'stepup_is_track_ticket': 0, + + # DJ Rank + 'dj_rank_single_rank': [0] * 15, + 'dj_rank_double_rank': [0] * 15, + 'dj_rank_single_point': [0] * 15, + 'dj_rank_double_point': [0] * 15, + + # Notes Radar + 'notes_radar_single': [0] * 6, + 'notes_radar_double': [0] * 6, + + # Grades + 'grade_single': -1, + 'grade_double': -1, + 'grade_values': [], + + # Achievements + 'achievements_trophy': [0] * 160, + 'achievements_last_weekly': 0, + 'achievements_pack_comp': 0, + 'achievements_pack_flg': 0, + 'achievements_pack_id': 0, + 'achievements_play_pack': 0, + 'achievements_visit_flg': 0, + 'achievements_weekly_num': 0, + + # Other + 'language_setting': 0, + 'movie_agreement': 0, + 'lightning_play_data_spnum': 0, + 'lightning_play_data_dpnum': 0, + + # Lightning model settings + 'lightning_setting_slider': [0] * 7, + 'lightning_setting_light': [1] * 10, + 'lightning_setting_concentration': 0, + 'lightning_setting_headphone_vol': 0, + 'lightning_setting_resistance_sp_left': 0, + 'lightning_setting_resistance_sp_right': 0, + 'lightning_setting_resistance_dp_left': 0, + 'lightning_setting_resistance_dp_right': 0, + 'lightning_setting_skin_0': 0, + 'lightning_setting_flg_skin_0': 0, + + # Event_1 settings + 'event_1_story_prog': 0, + 'event_1_last_select_area': 0, + 'event_1_failed_num': 0, + 'event_1_event_play_num': 0, + 'event_1_last_select_area_id': 0, + 'event_1_last_select_platform_type': 0, + 'event_1_last_select_platform_id': 0, + + # Web UI/Other options + '_show_category_grade': 0, + '_show_category_status': 1, + '_show_category_difficulty': 1, + '_show_category_alphabet': 1, + '_show_category_rival_play': 0, + '_show_category_rival_winlose': 1, + '_show_category_all_rival_play': 0, + '_show_category_arena_winlose': 1, + '_show_rival_shop_info': 1, + '_hide_play_count': 0, + '_show_score_graph_cutin': 1, + '_hide_iidx_id': 0, + '_classic_hispeed': 0, + '_beginner_option_swap': 1, + '_show_lamps_as_no_play_in_arena': 0, + + 'skin_customize_flag_frame': 0, + 'skin_customize_flag_bgm': 0, + 'skin_customize_flag_lane': 0, + + # Rivals + 'sp_rival_1_iidx_id': 0, + 'sp_rival_2_iidx_id': 0, + 'sp_rival_3_iidx_id': 0, + 'sp_rival_4_iidx_id': 0, + 'sp_rival_5_iidx_id': 0, + + 'dp_rival_1_iidx_id': 0, + 'dp_rival_2_iidx_id': 0, + 'dp_rival_3_iidx_id': 0, + 'dp_rival_4_iidx_id': 0, + 'dp_rival_5_iidx_id': 0 + } + db.upsert(all_profiles_for_card, where('card') == cid) + + card, card_split = get_id_from_profile(cid) + + response = E.response( + E.IIDX30pc( + id=card, + id_str=card_split + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30pc/getLaneGachaTicket') +async def iidx30pc_getlanegachaticket(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30pc( + E.ticket( + ticket_id=0, + arrange_id=0, + expire_date=0, + ), + E.setting( + sp=0, + dp_left=0, + dp_right=0, + ), + E.info( + last_page=0, + ), + E.free( + num=10, + ), + E.favorite( + arrange=0, + ), + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30pc/drawLaneGacha') +async def iidx30pc_drawlanegacha(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30pc( + E.ticket( + ticket_id=0, + arrange_id=0, + expire_date=0, + ), + E.session( + session_id=0 + ), + status=0 + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + +@router.post('/{gameinfo}/IIDX30pc/eaappliresult') +async def iidx30pc_eaappliresult(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30pc() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + +@router.post('/{gameinfo}/IIDX30pc/logout') +async def iidx30pc_logout(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30pc() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/iidx/iidx30ranking.py b/modules/iidx/iidx30ranking.py new file mode 100644 index 0000000..31c5290 --- /dev/null +++ b/modules/iidx/iidx30ranking.py @@ -0,0 +1,20 @@ +import config + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E + +router = APIRouter(prefix="/local2", tags=["local2"]) +router.model_whitelist = ["LDJ"] + + +@router.post('/{gameinfo}/IIDX30ranking/getranker') +async def iidx30ranking_getranker(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30ranking() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) diff --git a/modules/iidx/iidx30shop.py b/modules/iidx/iidx30shop.py new file mode 100644 index 0000000..fdf8d45 --- /dev/null +++ b/modules/iidx/iidx30shop.py @@ -0,0 +1,69 @@ +import config + +from fastapi import APIRouter, Request, Response + +from core_common import core_process_request, core_prepare_response, E + +router = APIRouter(prefix="/local2", tags=["local2"]) +router.model_whitelist = ["LDJ"] + + +@router.post('/{gameinfo}/IIDX30shop/getname') +async def iidx30shop_getname(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30shop( + cls_opt=0, + opname=config.arcade, + pid=13, + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30shop/getconvention') +async def iidx30shop_getconvention(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30shop( + E.valid(1, __type="bool"), + music_0=-1, + music_1=-1, + music_2=-1, + music_3=-1, + start_time=0, + end_time=0, + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + + +@router.post('/{gameinfo}/IIDX30shop/sentinfo') +async def iidx30shop_sentinfo(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30shop() + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers) + +@router.post('/{gameinfo}/IIDX30shop/sendescapepackageinfo') +async def iidx30shop_sendescapepackageinfo(request: Request): + request_info = await core_process_request(request) + + response = E.response( + E.IIDX30shop( + expire=1200 + ) + ) + + response_body, response_headers = await core_prepare_response(request, response) + return Response(content=response_body, headers=response_headers)