add back games, conform them to new title dispatch
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
from titles.diva.index import DivaServlet
|
||||
from titles.diva.const import DivaConstants
|
||||
from titles.diva.database import DivaData
|
||||
from titles.diva.read import DivaReader
|
||||
|
||||
index = DivaServlet
|
||||
database = DivaData
|
||||
reader = DivaReader
|
||||
|
||||
use_default_title = True
|
||||
include_protocol = True
|
||||
title_secure = False
|
||||
game_codes = [DivaConstants.GAME_CODE]
|
||||
trailing_slash = True
|
||||
use_default_host = False
|
||||
host = ""
|
||||
|
||||
current_schema_version = 1
|
||||
@@ -0,0 +1,506 @@
|
||||
import datetime
|
||||
from typing import Any, List, Dict
|
||||
import logging
|
||||
import json
|
||||
import urllib
|
||||
|
||||
from core.config import CoreConfig
|
||||
from titles.diva.config import DivaConfig
|
||||
from titles.diva.const import DivaConstants
|
||||
from titles.diva.database import DivaData
|
||||
|
||||
class DivaBase():
|
||||
def __init__(self, cfg: CoreConfig, game_cfg: DivaConfig) -> None:
|
||||
self.core_cfg = cfg # Config file
|
||||
self.game_config = game_cfg
|
||||
self.data = DivaData(cfg) # Database
|
||||
self.date_time_format = "%Y-%m-%d %H:%M:%S"
|
||||
self.logger = logging.getLogger("diva")
|
||||
self.game = DivaConstants.GAME_CODE
|
||||
self.version = DivaConstants.VER_PROJECT_DIVA_ARCADE_FUTURE_TONE
|
||||
|
||||
dt = datetime.datetime.now()
|
||||
self.time_lut=urllib.parse.quote(dt.strftime("%Y-%m-%d %H:%M:%S:16.0"))
|
||||
|
||||
def handle_test_request(self, data: Dict) -> Dict:
|
||||
return ""
|
||||
|
||||
def handle_game_init_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_attend_request(self, data: Dict) -> Dict:
|
||||
encoded = "&"
|
||||
params = {
|
||||
'atnd_prm1': '0,1,1,0,0,0,1,0,100,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1',
|
||||
'atnd_prm2': '30,10,100,4,1,50,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1',
|
||||
'atnd_prm3': '100,0,1,1,1,1,1,1,1,1,2,3,4,1,1,1,3,4,5,1,1,1,4,5,6,1,1,1,5,6,7,4,4,4,9,10,14,5,10,10,25,20,50,30,90,5,10,10,25,20,50,30,90,5,10,10,25,20,50,30,90,5,10,10,25,20,50,30,90,5,10,10,25,20,50,30,90,10,30,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0',
|
||||
'atnd_lut': f'{self.time_lut}',
|
||||
}
|
||||
|
||||
encoded += urllib.parse.urlencode(params)
|
||||
encoded = encoded.replace("%2C", ",")
|
||||
|
||||
return encoded
|
||||
|
||||
def handle_ping_request(self, data: Dict) -> Dict:
|
||||
encoded = "&"
|
||||
params = {
|
||||
'ping_b_msg': f'Welcome to {self.core_cfg.server.name} network!',
|
||||
'ping_m_msg': 'xxx',
|
||||
'atnd_lut': f'{self.time_lut}',
|
||||
'fi_lut': f'{self.time_lut}',
|
||||
'ci_lut': f'{self.time_lut}',
|
||||
'qi_lut': f'{self.time_lut}',
|
||||
'pvl_lut': '2021-05-22 12:08:16.0',
|
||||
'shp_ctlg_lut': '2020-06-10 19:44:16.0',
|
||||
'cstmz_itm_ctlg_lut': '2019-10-08 20:23:12.0',
|
||||
'ngwl_lut': '2019-10-08 20:23:12.0',
|
||||
'rnk_nv_lut': '2020-06-10 19:51:30.0',
|
||||
'rnk_ps_lut': f'{self.time_lut}',
|
||||
'bi_lut': '2020-09-18 10:00:00.0',
|
||||
'cpi_lut': '2020-10-25 09:25:10.0',
|
||||
'bdlol_lut': '2020-09-18 10:00:00.0',
|
||||
'p_std_hc_lut': '2019-08-01 04:00:36.0',
|
||||
'p_std_i_n_lut': '2019-08-01 04:00:36.0',
|
||||
'pdcl_lut': '2019-08-01 04:00:36.0',
|
||||
'pnml_lut': '2019-08-01 04:00:36.0',
|
||||
'cinml_lut': '2019-08-01 04:00:36.0',
|
||||
'rwl_lut': '2019-08-01 04:00:36.0',
|
||||
'req_inv_cmd_num': '-1,-1,-1,-1,-1,-1,-1,-1,-1,-1',
|
||||
'req_inv_cmd_prm1': '-1,-1,-1,-1,-1,-1,-1,-1,-1,-1',
|
||||
'req_inv_cmd_prm2': '-1,-1,-1,-1,-1,-1,-1,-1,-1,-1',
|
||||
'req_inv_cmd_prm3': '-1,-1,-1,-1,-1,-1,-1,-1,-1,-1',
|
||||
'req_inv_cmd_prm4': '-1,-1,-1,-1,-1,-1,-1,-1,-1,-1',
|
||||
'pow_save_flg': 0,
|
||||
'nblss_dnt_p': 100,
|
||||
'nblss_ltt_rl_vp': 1500,
|
||||
'nblss_ex_ltt_flg': 1,
|
||||
'nblss_dnt_st_tm': "2019-07-15 12:00:00.0",
|
||||
'nblss_dnt_ed_tm': "2019-09-17 12:00:00.0",
|
||||
'nblss_ltt_st_tm': "2019-09-18 12:00:00.0",
|
||||
'nblss_ltt_ed_tm': "2019-09-22 12:00:00.0",
|
||||
}
|
||||
|
||||
encoded += urllib.parse.urlencode(params)
|
||||
encoded = encoded.replace("+", "%20")
|
||||
encoded = encoded.replace("%2C", ",")
|
||||
|
||||
return encoded
|
||||
|
||||
def handle_pv_list_request(self, data: Dict) -> Dict:
|
||||
pvlist = ""
|
||||
with open(r"titles/diva/data/PvList0.dat", encoding="utf-8") as shop:
|
||||
lines = shop.readlines()
|
||||
for line in lines:
|
||||
pvlist += f"{line}"
|
||||
pvlist += ","
|
||||
|
||||
with open(r"titles/diva/data/PvList1.dat", encoding="utf-8") as shop:
|
||||
lines = shop.readlines()
|
||||
for line in lines:
|
||||
pvlist += f"{line}"
|
||||
pvlist += ","
|
||||
|
||||
with open(r"titles/diva/data/PvList2.dat", encoding="utf-8") as shop:
|
||||
lines = shop.readlines()
|
||||
for line in lines:
|
||||
pvlist += f"{line}"
|
||||
pvlist += ","
|
||||
|
||||
with open(r"titles/diva/data/PvList3.dat", encoding="utf-8") as shop:
|
||||
lines = shop.readlines()
|
||||
for line in lines:
|
||||
pvlist += f"{line}"
|
||||
pvlist += ","
|
||||
|
||||
with open(r"titles/diva/data/PvList4.dat", encoding="utf-8") as shop:
|
||||
lines = shop.readlines()
|
||||
for line in lines:
|
||||
pvlist += f"{line}"
|
||||
|
||||
response = ""
|
||||
response += f"&pvl_lut={self.time_lut}"
|
||||
response += f"&pv_lst={pvlist}"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_shop_catalog_request(self, data: Dict) -> Dict:
|
||||
catalog = ""
|
||||
|
||||
shopList = self.data.static.get_enabled_shop(self.version)
|
||||
if not shopList:
|
||||
with open(r"titles/diva/data/ShopCatalog.dat", encoding="utf-8") as shop:
|
||||
lines = shop.readlines()
|
||||
for line in lines:
|
||||
line = urllib.parse.quote(line) + ","
|
||||
catalog += f"{urllib.parse.quote(line)}"
|
||||
catalog = catalog.replace("+", "%20")
|
||||
|
||||
response = ""
|
||||
response += f"&shp_ctlg_lut={self.time_lut}"
|
||||
response += f"&shp_ctlg={catalog[:-3]}"
|
||||
else:
|
||||
for shop in shopList:
|
||||
line = str(shop["shopId"]) + "," + str(shop['unknown_0']) + "," + shop['name'] + "," + str(shop['points']) + "," + shop['start_date'] + "," + shop['end_date'] + "," + str(shop["type"])
|
||||
line = urllib.parse.quote(line) + ","
|
||||
catalog += f"{urllib.parse.quote(line)}"
|
||||
|
||||
catalog = catalog.replace("+", "%20")
|
||||
|
||||
response = ""
|
||||
response += f"&shp_ctlg_lut={self.time_lut}"
|
||||
response += f"&shp_ctlg={catalog[:-3]}"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_cstmz_itm_ctlg_request(self, data: Dict) -> Dict:
|
||||
catalog = ""
|
||||
|
||||
itemList = self.data.static.get_enabled_items(self.version)
|
||||
if not itemList:
|
||||
with open(r"titles/diva/data/ItemCatalog.dat", encoding="utf-8") as item:
|
||||
lines = item.readlines()
|
||||
for line in lines:
|
||||
line = urllib.parse.quote(line) + ","
|
||||
catalog += f"{urllib.parse.quote(line)}"
|
||||
catalog = catalog.replace("+", "%20")
|
||||
|
||||
response = ""
|
||||
response += f"&cstmz_itm_ctlg_lut={self.time_lut}"
|
||||
response += f"&cstmz_itm_ctlg={catalog[:-3]}"
|
||||
else:
|
||||
for item in itemList:
|
||||
line = str(item["itemId"]) + "," + str(item['unknown_0']) + "," + item['name'] + "," + str(item['points']) + "," + item['start_date'] + "," + item['end_date'] + "," + str(item["type"])
|
||||
line = urllib.parse.quote(line) + ","
|
||||
catalog += f"{urllib.parse.quote(line)}"
|
||||
|
||||
catalog = catalog.replace("+", "%20")
|
||||
|
||||
response = ""
|
||||
response += f"&cstmz_itm_ctlg_lut={self.time_lut}"
|
||||
response += f"&cstmz_itm_ctlg={catalog[:-3]}"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_festa_info_request(self, data: Dict) -> Dict:
|
||||
encoded = "&"
|
||||
params = {
|
||||
'fi_id': '1,-1',
|
||||
'fi_name': f'{self.core_cfg.server.name} Opening,xxx',
|
||||
'fi_kind': '0,0',
|
||||
'fi_difficulty': '-1,-1',
|
||||
'fi_pv_id_lst': 'ALL,ALL',
|
||||
'fi_attr': '7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
|
||||
'fi_add_vp': '10,0',
|
||||
'fi_mul_vp': '1,1',
|
||||
'fi_st': '2022-06-17 17:00:00.0,2014-07-08 18:10:11.0',
|
||||
'fi_et': '2029-01-01 10:00:00.0,2014-07-08 18:10:11.0',
|
||||
'fi_lut': '{self.time_lut}',
|
||||
}
|
||||
|
||||
encoded += urllib.parse.urlencode(params)
|
||||
encoded = encoded.replace("+", "%20")
|
||||
encoded = encoded.replace("%2C", ",")
|
||||
|
||||
return encoded
|
||||
|
||||
def handle_contest_info_request(self, data: Dict) -> Dict:
|
||||
response = ""
|
||||
|
||||
response += f"&ci_lut={self.time_lut}"
|
||||
response += "&ci_str=%2A%2A%2A,%2A%2A%2A,%2A%2A%2A,%2A%2A%2A,%2A%2A%2A,%2A%2A%2A,%2A%2A%2A,%2A%2A%2A"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_qst_inf_request(self, data: Dict) -> Dict:
|
||||
quest = ""
|
||||
|
||||
questList = self.data.static.get_enabled_quests(self.version)
|
||||
if not questList:
|
||||
with open(r"titles/diva/data/QuestInfo.dat", encoding="utf-8") as shop:
|
||||
lines = shop.readlines()
|
||||
for line in lines:
|
||||
quest += f"{urllib.parse.quote(line)},"
|
||||
|
||||
response = ""
|
||||
response += f"&qi_lut={self.time_lut}"
|
||||
response += f"&qhi_str={quest[:-1]}"
|
||||
else:
|
||||
for quests in questList:
|
||||
line = str(quests["questId"]) + "," + str(quests['quest_order']) + "," + str(quests['kind']) + "," + str(quests['unknown_0']) + "," + quests['start_datetime'] + "," + quests['end_datetime'] + "," + quests["name"] + "," + str(quests["unknown_1"]) + "," + str(quests["unknown_2"]) + "," + str(quests["quest_enable"])
|
||||
quest += f"{urllib.parse.quote(line)}%0A,"
|
||||
|
||||
responseline = f"{quest[:-1]},"
|
||||
for i in range(len(questList),59):
|
||||
responseline += "%2A%2A%2A%0A,"
|
||||
|
||||
response = ""
|
||||
response += f"&qi_lut={self.time_lut}"
|
||||
response += f"&qhi_str={responseline}%2A%2A%2A"
|
||||
|
||||
response += "&qrai_str=%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1,%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1,%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1%2C%2D1"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_nv_ranking_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_ps_ranking_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_ng_word_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_rmt_wp_list_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_pv_def_chr_list_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_pv_ng_mdl_list_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_cstmz_itm_ng_mdl_lst_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_banner_info_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_banner_data_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_cm_ply_info_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_pstd_h_ctrl_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_pstd_item_ng_lst_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_pre_start_request(self, data: Dict) -> Dict:
|
||||
profile = self.data.profile.get_profile(data["aime_id"], self.version)
|
||||
profile_shop = self.data.item.get_shop(data["aime_id"], self.version)
|
||||
if profile is None:
|
||||
return ( f"&ps_result=-3")
|
||||
else:
|
||||
response = ""
|
||||
response += "&ps_result=1"
|
||||
response += f"&pd_id={data['aime_id']}"
|
||||
response += "&nblss_ltt_stts=-1"
|
||||
response += "&nblss_ltt_tckt=-1"
|
||||
response += "&nblss_ltt_is_opn=-1"
|
||||
response += f"&vcld_pts={profile['vcld_pts']}"
|
||||
response += f"&player_name={profile['player_name']}"
|
||||
response += f"&lv_efct_id={profile['lv_efct_id']}"
|
||||
response += f"&lv_plt_id={profile['lv_plt_id']}"
|
||||
response += f"&lv_str={profile['lv_str']}"
|
||||
response += f"&lv_num={profile['lv_num']}"
|
||||
response += f"&lv_pnt={profile['lv_pnt']}"
|
||||
|
||||
#Store stuff to add to rework
|
||||
response += f"&mdl_eqp_tm={self.time_lut}"
|
||||
|
||||
if profile_shop:
|
||||
response += f"&mdl_eqp_ary={profile_shop['mdl_eqp_ary']}"
|
||||
|
||||
response += f"&c_itm_eqp_ary=-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999"
|
||||
response += f"&ms_itm_flg_ary=1,1,1,1,1,1,1,1,1,1,1,1"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_registration_request(self, data: Dict) -> Dict: #DONE
|
||||
self.data.profile.create_profile(self.version, data["aime_id"], data["player_name"])
|
||||
return ( f"&cd_adm_result=1&pd_id={data['aime_id']}")
|
||||
|
||||
def handle_start_request(self, data: Dict) -> Dict:
|
||||
profile = self.data.profile.get_profile(data["pd_id"], self.version)
|
||||
profile_shop = self.data.item.get_shop(data["pd_id"], self.version)
|
||||
if profile is None: return
|
||||
|
||||
response = ""
|
||||
response += f"&pd_id={data['pd_id']}"
|
||||
response += "&start_result=1"
|
||||
|
||||
response += "&accept_idx=100"
|
||||
response += f"&hp_vol={profile['hp_vol']}"
|
||||
response += f"&btn_se_vol={profile['btn_se_vol']}"
|
||||
response += f"&btn_se_vol2={profile['btn_se_vol2']}"
|
||||
response += f"&sldr_se_vol2={profile['sldr_se_vol2']}"
|
||||
response += f"&sort_kind={profile['sort_kind']}"
|
||||
response += f"&player_name={profile['player_name']}"
|
||||
response += f"&lv_num={profile['lv_num']}"
|
||||
response += f"&lv_pnt={profile['lv_pnt']}"
|
||||
response += f"&lv_efct_id={profile['lv_efct_id']}"
|
||||
response += f"&lv_plt_id={profile['lv_plt_id']}"
|
||||
response += "&mdl_have=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
response += "&cstmz_itm_have=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
response += f"&use_pv_mdl_eqp={profile['use_pv_mdl_eqp']}"
|
||||
response += f"&use_pv_btn_se_eqp={profile['use_pv_btn_se_eqp']}"
|
||||
response += f"&use_pv_sld_se_eqp={profile['use_pv_sld_se_eqp']}"
|
||||
response += f"&use_pv_chn_sld_se_eqp={profile['use_pv_chn_sld_se_eqp']}"
|
||||
response += f"&use_pv_sldr_tch_se_eqp={profile['use_pv_sldr_tch_se_eqp']}"
|
||||
response += f"&vcld_pts={profile['lv_efct_id']}"
|
||||
response += f"&nxt_pv_id={profile['nxt_pv_id']}"
|
||||
response += f"&nxt_dffclty={profile['nxt_dffclty']}"
|
||||
response += f"&nxt_edtn={profile['nxt_edtn']}"
|
||||
response += f"&dsp_clr_brdr={profile['dsp_clr_brdr']}"
|
||||
response += f"&dsp_intrm_rnk={profile['dsp_intrm_rnk']}"
|
||||
response += f"&dsp_clr_sts={profile['dsp_clr_sts']}"
|
||||
response += f"&rgo_sts={profile['rgo_sts']}"
|
||||
|
||||
#To be fully fixed
|
||||
if "my_qst_id" not in profile:
|
||||
response += f"&my_qst_id=-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
response += f"&my_qst_sts=0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
else:
|
||||
response += f"&my_qst_id={profile['my_qst_id']}"
|
||||
response += f"&my_qst_sts={profile['my_qst_sts']}"
|
||||
|
||||
response += f"&my_qst_prgrs=0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
response += f"&my_qst_et=2022-06-19%2010%3A28%3A52.0,2022-06-19%2010%3A28%3A52.0,2022-06-19%2010%3A28%3A52.0,2100-01-01%2008%3A59%3A59.0,2100-01-01%2008%3A59%3A59.0,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx"
|
||||
response += f"&clr_sts=0,0,0,0,0,0,0,0,56,52,35,6,6,3,1,0,0,0,0,0"
|
||||
|
||||
#Store stuff to add to rework
|
||||
response += f"&mdl_eqp_tm={self.time_lut}"
|
||||
|
||||
if profile_shop:
|
||||
response += f"&mdl_eqp_ary={profile_shop['mdl_eqp_ary']}"
|
||||
|
||||
response += f"&c_itm_eqp_ary=-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999"
|
||||
response += f"&ms_itm_flg_ary=1,1,1,1,1,1,1,1,1,1,1,1"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_pd_unlock_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_spend_credit_request(self, data: Dict) -> Dict:
|
||||
profile = self.data.profile.get_profile(data["pd_id"], self.version)
|
||||
if profile is None: return
|
||||
|
||||
response = ""
|
||||
|
||||
response += "&cmpgn_rslt=-1,-1,x,-1,-1,x,x,-1,x,-1,-1,x,-1,-1,x,x,-1,x,-1,-1,x,-1,-1,x,x,-1,x,-1,-1,x,-1,-1,x,x,-1,x,-1,-1,x,-1,-1,x,x,-1,x,-1,-1,x,-1,-1,x,x,-1,x"
|
||||
response += "&cmpgn_rslt_num=0"
|
||||
response += f"&vcld_pts={profile['vcld_pts']}"
|
||||
response += f"&lv_str={profile['lv_str']}"
|
||||
response += f"&lv_efct_id={profile['lv_efct_id']}"
|
||||
response += f"&lv_plt_id={profile['lv_plt_id']}"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_get_pv_pd_request(self, data: Dict) -> Dict:
|
||||
song_id = data["pd_pv_id_lst"].split(",")
|
||||
pv = ""
|
||||
|
||||
for song in song_id:
|
||||
if int(song) > 0:
|
||||
pd_db_song = self.data.score.get_best_score(data["pd_id"], int(song), data["difficulty"])
|
||||
if pd_db_song is not None:
|
||||
|
||||
pv += urllib.parse.quote(f"{song},0,{pd_db_song['clr_kind']},{pd_db_song['score']},{pd_db_song['atn_pnt']},{pd_db_song['sort_kind']},-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,1,1,1,1,1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1337,1,1,1,0,0,0")
|
||||
|
||||
else:
|
||||
#self.logger.debug(f"No score saved for ID: {song}!")
|
||||
pv += urllib.parse.quote(f"{song},0,-1,-1,-1,0,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,1,1,1,1,1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,0,0,0")
|
||||
|
||||
#pv_no, edition, rslt, max_score, max_atn_pnt, challenge_kind, module_eqp[-999,-999,-999], customize_eqp[-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999,-999], customize_flag[1,1,1,1,1,1,1,1,1,1,1,1], skin, btn_se, sld_se, chsld_se, sldtch_se, rvl_pd_id, rvl_score, rvl_attn_pnt, countrywide_ranking, rgo_hispeed, rgo_hidden, rgo_sudden, rgo_hispeed_cleared, rgo_hidden_cleared, rgo_sudden_cleared, chain_challenge_num, chain_challenge_max, chain_challenge_open, version
|
||||
else:
|
||||
pv += urllib.parse.quote(f"{song}***")
|
||||
pv += ","
|
||||
|
||||
response = ""
|
||||
response += f"&pd_by_pv_id={pv[:-1]}"
|
||||
response += "&pdddt_flg=0"
|
||||
response += f"&pdddt_tm={self.time_lut}"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_stage_start_request(self, data: Dict) -> Dict:
|
||||
return ( f'' )
|
||||
|
||||
def handle_stage_result_request(self, data: Dict) -> Dict:
|
||||
|
||||
profile = self.data.profile.get_profile(data["pd_id"], self.version)
|
||||
|
||||
pd_song_list = data["stg_ply_pv_id"].split(",")
|
||||
pd_song_difficulty = data["stg_difficulty"].split(",")
|
||||
pd_song_max_score = data["stg_score"].split(",")
|
||||
pd_song_max_atn_pnt = data["stg_atn_pnt"].split(",")
|
||||
pd_song_ranking = data["stg_clr_kind"].split(",")
|
||||
pd_song_sort_kind = data["sort_kind"]
|
||||
pd_song_cool_cnt = data["stg_cool_cnt"].split(",")
|
||||
pd_song_fine_cnt = data["stg_fine_cnt"].split(",")
|
||||
pd_song_safe_cnt = data["stg_safe_cnt"].split(",")
|
||||
pd_song_sad_cnt = data["stg_sad_cnt"].split(",")
|
||||
pd_song_worst_cnt = data["stg_wt_wg_cnt"].split(",")
|
||||
pd_song_max_combo = data["stg_max_cmb"].split(",")
|
||||
|
||||
for index, value in enumerate(pd_song_list):
|
||||
if "-1" not in pd_song_list[index]:
|
||||
profile_pd_db_song = self.data.score.get_best_score(data["pd_id"], pd_song_list[index], pd_song_difficulty[index])
|
||||
if profile_pd_db_song is None:
|
||||
self.data.score.put_best_score(data["pd_id"], self.version, pd_song_list[index], pd_song_difficulty[index], pd_song_max_score[index], pd_song_max_atn_pnt[index], pd_song_ranking[index], pd_song_sort_kind, pd_song_cool_cnt[index], pd_song_fine_cnt[index], pd_song_safe_cnt[index], pd_song_sad_cnt[index], pd_song_worst_cnt[index], pd_song_max_combo[index])
|
||||
self.data.score.put_playlog(data["pd_id"], self.version, pd_song_list[index], pd_song_difficulty[index], pd_song_max_score[index], pd_song_max_atn_pnt[index], pd_song_ranking[index], pd_song_sort_kind, pd_song_cool_cnt[index], pd_song_fine_cnt[index], pd_song_safe_cnt[index], pd_song_sad_cnt[index], pd_song_worst_cnt[index], pd_song_max_combo[index])
|
||||
elif int(pd_song_max_score[index]) >= int(profile_pd_db_song["score"]):
|
||||
self.data.score.put_best_score(data["pd_id"], self.version, pd_song_list[index], pd_song_difficulty[index], pd_song_max_score[index], pd_song_max_atn_pnt[index], pd_song_ranking[index], pd_song_sort_kind, pd_song_cool_cnt[index], pd_song_fine_cnt[index], pd_song_safe_cnt[index], pd_song_sad_cnt[index], pd_song_worst_cnt[index], pd_song_max_combo[index])
|
||||
self.data.score.put_playlog(data["pd_id"], self.version, pd_song_list[index], pd_song_difficulty[index], pd_song_max_score[index], pd_song_max_atn_pnt[index], pd_song_ranking[index], pd_song_sort_kind, pd_song_cool_cnt[index], pd_song_fine_cnt[index], pd_song_safe_cnt[index], pd_song_sad_cnt[index], pd_song_worst_cnt[index], pd_song_max_combo[index])
|
||||
elif int(pd_song_max_score[index]) != int(profile_pd_db_song["score"]):
|
||||
self.data.score.put_playlog(data["pd_id"], self.version, pd_song_list[index], pd_song_difficulty[index], pd_song_max_score[index], pd_song_max_atn_pnt[index], pd_song_ranking[index], pd_song_sort_kind, pd_song_cool_cnt[index], pd_song_fine_cnt[index], pd_song_safe_cnt[index], pd_song_sad_cnt[index], pd_song_worst_cnt[index], pd_song_max_combo[index])
|
||||
|
||||
# Profile saving based on registration list
|
||||
|
||||
old_level = int(profile['lv_num'])
|
||||
new_level = (int(data["ttl_vp_add"]) + int(profile["lv_pnt"])) / 12
|
||||
|
||||
self.data.profile.update_profile(data["pd_id"], int(new_level), int(profile["lv_pnt"]) + int(data["ttl_vp_add"]), int(data["vcld_pts"]), int(data["hp_vol"]), int(data["btn_se_vol"]), int(data["btn_se_vol2"]), int(data["sldr_se_vol2"]), int(data["sort_kind"]), int(data["use_pv_mdl_eqp"]), profile["use_pv_btn_se_eqp"], profile["use_pv_sld_se_eqp"], profile["use_pv_chn_sld_se_eqp"], profile["use_pv_sldr_tch_se_eqp"], int(data["ply_pv_id"]), int(data["nxt_dffclty"]), int(data["nxt_edtn"]), profile["dsp_clr_brdr"], profile["dsp_intrm_rnk"], profile["dsp_clr_sts"], profile["rgo_sts"], profile["lv_efct_id"], profile["lv_plt_id"], data["my_qst_id"], data["my_qst_sts"])
|
||||
|
||||
response = ""
|
||||
|
||||
response += "&chllng_kind=-1"
|
||||
response += f"&lv_num_old={int(old_level)}"
|
||||
response += f"&lv_pnt_old={int(profile['lv_pnt'])}"
|
||||
response += f"&lv_num={int(profile['lv_num'])}"
|
||||
response += f"&lv_str={profile['lv_str']}"
|
||||
response += f"&lv_pnt={int(profile['lv_pnt']) + int(data['ttl_vp_add'])}"
|
||||
response += f"&lv_efct_id={int(profile['lv_efct_id'])}"
|
||||
response += f"&lv_plt_id={int(profile['lv_plt_id'])}"
|
||||
response += f"&vcld_pts={int(data['vcld_pts'])}"
|
||||
response += f"&prsnt_vcld_pts={int(profile['vcld_pts'])}"
|
||||
response += "&cerwd_kind=-1"
|
||||
response += "&cerwd_value=-1"
|
||||
response += "&cerwd_str_0=***"
|
||||
response += "&cerwd_str_1=***"
|
||||
response += "&ttl_str_ary=xxx,xxx,xxx,xxx,xxx"
|
||||
response += "&ttl_plt_id_ary=-1,-1,-1,-1,-1"
|
||||
response += "&ttl_desc_ary=xxx,xxx,xxx,xxx,xxx"
|
||||
response += "&skin_id_ary=xxx,xxx,xxx,xxx,xxx"
|
||||
response += "&skin_name_ary=xxx,xxx,xxx,xxx,xxx"
|
||||
response += "&skin_illust_ary=xxx,xxx,xxx,xxx,xxx"
|
||||
response += "&skin_desc_ary=xxx,xxx,xxx,xxx,xxx"
|
||||
if "my_qst_id" not in profile:
|
||||
response += f"&my_qst_id=-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
else:
|
||||
response += f"&my_qst_id={profile['my_qst_id']}"
|
||||
response += "&my_qst_r_qid=-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
response += "&my_qst_r_knd=-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
response += "&my_qst_r_vl=-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
response += "&my_qst_r_nflg=-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
response += "&my_ccd_r_qid=-1,-1,-1,-1,-1"
|
||||
response += "&my_ccd_r_hnd=-1,-1,-1,-1,-1"
|
||||
response += "&my_ccd_r_vp=-1,-1,-1,-1,-1"
|
||||
|
||||
return ( response )
|
||||
|
||||
def handle_end_request(self, data: Dict) -> Dict:
|
||||
profile = self.data.profile.get_profile(data["pd_id"], self.version)
|
||||
self.data.profile.update_profile(data["pd_id"], profile["lv_num"], profile["lv_pnt"], profile["vcld_pts"], profile["hp_vol"], profile["btn_se_vol"], profile["btn_se_vol2"], profile["sldr_se_vol2"], profile["sort_kind"], profile["use_pv_mdl_eqp"], profile["use_pv_btn_se_eqp"], profile["use_pv_sld_se_eqp"], profile["use_pv_chn_sld_se_eqp"], profile["use_pv_sldr_tch_se_eqp"], profile["nxt_pv_id"], profile["nxt_dffclty"], profile["nxt_edtn"], profile["dsp_clr_brdr"], profile["dsp_intrm_rnk"], profile["dsp_clr_sts"], profile["rgo_sts"], profile["lv_efct_id"], profile["lv_plt_id"], data["my_qst_id"], data["my_qst_sts"])
|
||||
return ( f'' )
|
||||
|
||||
def handle_shop_exit_request(self, data: Dict) -> Dict:
|
||||
self.data.item.put_shop(data["pd_id"], self.version, data["mdl_eqp_cmn_ary"])
|
||||
|
||||
response = ""
|
||||
response += "&shp_rslt=1"
|
||||
return ( response )
|
||||
@@ -0,0 +1,17 @@
|
||||
from core.config import CoreConfig
|
||||
|
||||
class DivaServerConfig():
|
||||
def __init__(self, parent_config: "DivaConfig") -> None:
|
||||
self.__config = parent_config
|
||||
|
||||
@property
|
||||
def enable(self) -> bool:
|
||||
return CoreConfig.get_config_field(self.__config, 'diva', 'server', 'enable', default=True)
|
||||
|
||||
@property
|
||||
def loglevel(self) -> int:
|
||||
return CoreConfig.str_to_loglevel(CoreConfig.get_config_field(self.__config, 'diva', 'server', 'loglevel', default="info"))
|
||||
|
||||
class DivaConfig(dict):
|
||||
def __init__(self) -> None:
|
||||
self.server = DivaServerConfig(self)
|
||||
@@ -0,0 +1,11 @@
|
||||
class DivaConstants():
|
||||
GAME_CODE = "SBZV"
|
||||
|
||||
VER_PROJECT_DIVA_ARCADE = 0
|
||||
VER_PROJECT_DIVA_ARCADE_FUTURE_TONE = 1
|
||||
|
||||
VERSION_NAMES = ("Project Diva Arcade", "Project Diva Arcade Future Tone")
|
||||
|
||||
@classmethod
|
||||
def game_ver_to_string(cls, ver: int):
|
||||
return cls.VERSION_NAMES[ver]
|
||||
@@ -0,0 +1,204 @@
|
||||
0,0,縁なしメガネ(銀),50,2013-09-13,2029-01-01,0
|
||||
1,0,縁なしメガネ(赤),50,2013-09-13,2029-01-01,1
|
||||
2,0,ナイロールメガネ(銀),100,2013-09-13,2029-01-01,2
|
||||
3,0,ナイロールメガネ(茶),100,2014-03-18,2029-01-01,3
|
||||
4,0,フルフレームメガネ(橙),100,2014-03-18,2029-01-01,4
|
||||
5,0,フルフレームメガネ(黒),100,2013-09-13,2029-01-01,5
|
||||
6,0,アンダーリムメガネ(青),50,2014-02-12,2029-01-01,8
|
||||
7,0,アンダーリムメガネ(ピンク),50,2014-05-15,2029-01-01,9
|
||||
8,0,ぐるぐるメガネ,150,2014-09-26,2029-01-01,15
|
||||
9,0,三角メガネ(黒),100,2013-12-25,2029-01-01,10
|
||||
10,0,三角メガネ(赤),100,2014-03-18,2029-01-01,11
|
||||
11,0,サングラス,150,2015-01-09,2029-01-01,16
|
||||
12,0,ゴーグル,150,2014-12-02,2029-01-01,17
|
||||
13,0,電脳バイザー,150,2015-01-09,2029-01-01,18
|
||||
14,0,片眼鏡,150,2015-04-01,2029-01-01,14
|
||||
15,0,アイマスク,150,2014-10-23,2029-01-01,19
|
||||
16,0,キラ目マスク,200,2015-05-20,2029-01-01,20
|
||||
17,0,眼帯(黒),150,2013-09-13,2029-01-01,23
|
||||
18,0,眼帯(緑),150,2013-12-25,2029-01-01,24
|
||||
19,0,眼帯(黄),150,2014-02-12,2029-01-01,25
|
||||
20,0,眼帯(オレンジ),150,2014-05-15,2029-01-01,26
|
||||
21,0,眼帯(ピンク),150,2014-05-15,2029-01-01,27
|
||||
22,0,眼帯(青),150,2013-09-13,2029-01-01,28
|
||||
23,0,眼帯(赤),150,2013-09-13,2029-01-01,29
|
||||
24,0,眼帯(白),150,2015-07-22,2029-01-01,22
|
||||
25,0,京劇仮面(青),200,2016-01-08,2029-01-01,33
|
||||
26,0,京劇仮面(赤),200,2016-01-08,2029-01-01,34
|
||||
27,0,バタフライマスク,200,2015-07-22,2029-01-01,30
|
||||
28,0,マスカレードマスク,200,2014-07-24,2029-01-01,31
|
||||
30,0,ガスマスク,200,2015-07-22,2029-01-01,39
|
||||
31,0,能面(般若),200,2015-07-22,2029-01-01,40
|
||||
32,0,能面(女),200,2015-05-20,2029-01-01,41
|
||||
33,0,能面(翁),200,2015-05-20,2029-01-01,42
|
||||
34,0,白マスク,150,2014-07-24,2029-01-01,35
|
||||
35,0,白マスク(ペロ舌),200,2014-09-26,2029-01-01,36
|
||||
36,0,白マスク(ω),200,2014-12-02,2029-01-01,37
|
||||
37,0,白マスク(ε),200,2015-05-20,2029-01-01,38
|
||||
38,0,ネコひげ,50,2015-04-01,2029-01-01,43
|
||||
39,0,天使の輪,200,2015-07-22,2029-01-01,10
|
||||
40,0,ひよこ,200,2014-07-24,2029-01-01,11
|
||||
41,0,ナースキャップ,100,2013-09-13,2029-01-01,0
|
||||
42,0,メイドカチューシャ,100,2013-12-25,2029-01-01,1
|
||||
43,0,ネコミミ(黒),200,2013-09-13,2029-01-01,2
|
||||
44,0,ネコミミ(白),200,2013-12-25,2029-01-01,3
|
||||
45,0,ネコミミ(トラ),200,2014-03-18,2029-01-01,4
|
||||
46,0,ウサミミ(黒),200,2014-02-12,2029-01-01,5
|
||||
47,0,ウサミミ(白),200,2013-09-13,2029-01-01,6
|
||||
48,0,ウサミミ(ピンク),200,2014-09-26,2029-01-01,7
|
||||
49,0,一本角,150,2014-03-18,2029-01-01,8
|
||||
50,0,悪魔の角,200,2015-05-20,2029-01-01,9
|
||||
51,0,クセ毛 A(緑),150,2014-05-15,2029-01-01,12
|
||||
52,0,クセ毛 B(黄),150,2014-07-24,2029-01-01,22
|
||||
53,0,クセ毛 C(黄),150,2014-09-26,2029-01-01,31
|
||||
54,0,クセ毛 D(ピンク),150,2014-10-23,2029-01-01,41
|
||||
55,0,クセ毛 E(青),150,2014-12-02,2029-01-01,51
|
||||
56,0,クセ毛 F(こげ茶),150,2015-01-09,2029-01-01,61
|
||||
57,0,蝶ネクタイ(金),100,2013-12-25,2029-01-01,0
|
||||
58,0,蝶ネクタイ(黒),100,2013-09-13,2029-01-01,1
|
||||
59,0,蝶ネクタイ(赤),100,2013-09-13,2029-01-01,2
|
||||
60,0,リボン(青),150,2014-02-12,2029-01-01,3
|
||||
61,0,リボン(黄),150,2013-09-13,2029-01-01,4
|
||||
62,0,リボン(ピンク),150,2013-09-13,2029-01-01,5
|
||||
67,0,鈴(金),150,2014-10-23,2029-01-01,6
|
||||
68,0,鈴(銀),150,2014-10-23,2029-01-01,7
|
||||
69,0,光の翼,200,2014-12-02,2029-01-01,1
|
||||
70,0,天使の翼,200,2015-07-22,2029-01-01,0
|
||||
71,0,蝶の羽根,200,2015-04-01,2029-01-01,3
|
||||
72,0,悪魔の翼,200,2015-05-20,2029-01-01,2
|
||||
73,0,ぬいぐるみ,200,2013-09-13,2029-01-01,8
|
||||
74,0,リュックサック,150,2013-09-13,2029-01-01,4
|
||||
75,0,ナップサック,100,2013-12-25,2029-01-01,5
|
||||
76,0,ランドセル(黒),150,2014-02-12,2029-01-01,6
|
||||
77,0,ランドセル(赤),150,2014-02-12,2029-01-01,7
|
||||
78,0,ロケット,150,2014-07-24,2029-01-01,9
|
||||
79,0,ネコしっぽ(黒),200,2013-09-13,2029-01-01,11
|
||||
80,0,ネコしっぽ(白),200,2013-12-25,2029-01-01,12
|
||||
81,0,ネコしっぽ(トラ),200,2014-03-18,2029-01-01,13
|
||||
82,0,ウサしっぽ(黒),200,2014-02-12,2029-01-01,14
|
||||
83,0,ウサしっぽ(白),200,2013-09-13,2029-01-01,15
|
||||
84,0,ウサしっぽ(ピンク),200,2014-09-26,2029-01-01,16
|
||||
85,0,狐しっぽ,350,2014-05-15,2029-01-01,17
|
||||
86,0,悪魔の尾,200,2015-01-09,2029-01-01,18
|
||||
87,0,赤ぷよぼう,400,2016-09-21,2029-01-01,66
|
||||
88,0,緑ぷよのかみどめ,400,2016-09-21,2029-01-01,67
|
||||
89,0,ゼンマイ,150,2015-07-22,2029-01-01,10
|
||||
97,0,ゴールドクラウン,350,2016-01-08,2029-01-01,70
|
||||
98,0,プラチナクラウン,350,2016-01-08,2029-01-01,71
|
||||
99,0,シャープメガネ(藍),100,2014-09-26,2029-01-01,6
|
||||
100,0,シャープメガネ(紫),100,2013-12-25,2029-01-01,7
|
||||
101,0,丸メガネ(銀),150,2013-12-25,2029-01-01,12
|
||||
102,0,丸メガネ(べっ甲),150,2014-03-18,2029-01-01,13
|
||||
103,0,たこルカ,400,2016-05-18,2029-01-01,68
|
||||
104,0,シテヤンヨ,400,2016-03-17,2029-01-01,69
|
||||
105,0,はちゅねミク,400,2014-12-02,2029-01-01,19
|
||||
106,0,リンの幼虫,400,2016-01-08,2029-01-01,20
|
||||
107,0,劇画マスク,200,2016-01-08,2029-01-01,21
|
||||
115,0,シャープサングラス,150,2014-07-24,2029-01-01,45
|
||||
116,0,水中メガネ,200,2014-12-02,2029-01-01,44
|
||||
117,0,パーティー眼鏡,100,2015-04-01,2029-01-01,48
|
||||
118,0,ピエロ鼻,50,2015-05-20,2029-01-01,46
|
||||
119,0,キツネ面,200,2016-03-17,2029-01-01,47
|
||||
120,0,ミニシルクハット,350,2014-05-15,2029-01-01,74
|
||||
121,0,コック帽,50,2013-09-13,2029-01-01,73
|
||||
122,0,烏帽子,50,2015-04-01,2029-01-01,72
|
||||
123,0,ミクダヨー,1500,2015-04-01,2029-01-01,76
|
||||
124,0,記章,100,2014-10-23,2029-01-01,8
|
||||
131,0,ポスター付リュックサック,150,2014-03-18,2029-01-01,21
|
||||
132,0,リコーダー付ランドセル(黒),150,2015-01-09,2029-01-01,22
|
||||
133,0,リコーダー付ランドセル(赤),150,2015-01-09,2029-01-01,23
|
||||
134,0,ミクダヨー(ミニ),500,2014-10-23,2029-01-01,75
|
||||
135,0,クセ毛 A(黄),150,2014-05-15,2029-01-01,13
|
||||
136,0,クセ毛 A(ピンク),150,2014-05-15,2029-01-01,14
|
||||
137,0,クセ毛 A(青),150,2014-05-15,2029-01-01,15
|
||||
138,0,クセ毛 A(こげ茶),150,2014-05-15,2029-01-01,16
|
||||
139,0,クセ毛 A(金),150,2014-05-15,2029-01-01,17
|
||||
140,0,クセ毛 A(銀),150,2014-05-15,2029-01-01,18
|
||||
141,0,クセ毛 A(茶),150,2014-05-15,2029-01-01,19
|
||||
142,0,クセ毛 A(赤),150,2014-05-15,2029-01-01,20
|
||||
143,0,クセ毛 B(緑),150,2014-07-24,2029-01-01,21
|
||||
144,0,クセ毛 B(ピンク),150,2014-07-24,2029-01-01,23
|
||||
145,0,クセ毛 B(青),150,2014-07-24,2029-01-01,24
|
||||
146,0,クセ毛 B(こげ茶),150,2014-07-24,2029-01-01,25
|
||||
147,0,クセ毛 B(金),150,2014-07-24,2029-01-01,26
|
||||
148,0,クセ毛 B(銀),150,2014-07-24,2029-01-01,27
|
||||
149,0,クセ毛 B(茶),150,2014-07-24,2029-01-01,28
|
||||
150,0,クセ毛 B(赤),150,2014-07-24,2029-01-01,29
|
||||
151,0,クセ毛 C(緑),150,2014-09-26,2029-01-01,30
|
||||
152,0,クセ毛 C(ピンク),150,2014-09-26,2029-01-01,32
|
||||
153,0,クセ毛 C(青),150,2014-09-26,2029-01-01,33
|
||||
154,0,クセ毛 C(こげ茶),150,2014-09-26,2029-01-01,34
|
||||
155,0,クセ毛 C(金),150,2014-09-26,2029-01-01,35
|
||||
156,0,クセ毛 C(銀),150,2014-09-26,2029-01-01,36
|
||||
157,0,クセ毛 C(茶),150,2014-09-26,2029-01-01,37
|
||||
158,0,クセ毛 C(赤),150,2014-09-26,2029-01-01,38
|
||||
159,0,クセ毛 D(緑),150,2014-10-23,2029-01-01,39
|
||||
160,0,クセ毛 D(黄),150,2014-10-23,2029-01-01,40
|
||||
161,0,クセ毛 D(青),150,2014-10-23,2029-01-01,42
|
||||
162,0,クセ毛 D(こげ茶),150,2014-10-23,2029-01-01,43
|
||||
163,0,クセ毛 D(金),150,2014-10-23,2029-01-01,44
|
||||
164,0,クセ毛 D(銀),150,2014-10-23,2029-01-01,45
|
||||
165,0,クセ毛 D(茶),150,2014-10-23,2029-01-01,46
|
||||
166,0,クセ毛 D(赤),150,2014-10-23,2029-01-01,47
|
||||
167,0,クセ毛 E(緑),150,2014-12-02,2029-01-01,48
|
||||
168,0,クセ毛 E(黄),150,2014-12-02,2029-01-01,49
|
||||
169,0,クセ毛 E(ピンク),150,2014-12-02,2029-01-01,50
|
||||
170,0,クセ毛 E(こげ茶),150,2014-12-02,2029-01-01,52
|
||||
171,0,クセ毛 E(金),150,2014-12-02,2029-01-01,53
|
||||
172,0,クセ毛 E(銀),150,2014-12-02,2029-01-01,54
|
||||
173,0,クセ毛 E(茶),150,2014-12-02,2029-01-01,55
|
||||
174,0,クセ毛 E(赤),150,2014-12-02,2029-01-01,56
|
||||
175,0,クセ毛 F(緑),150,2015-01-09,2029-01-01,57
|
||||
176,0,クセ毛 F(黄),150,2015-01-09,2029-01-01,58
|
||||
177,0,クセ毛 F(ピンク),150,2015-01-09,2029-01-01,59
|
||||
178,0,クセ毛 F(青),150,2015-01-09,2029-01-01,60
|
||||
179,0,クセ毛 F(金),150,2015-01-09,2029-01-01,62
|
||||
180,0,クセ毛 F(銀),150,2015-01-09,2029-01-01,63
|
||||
181,0,クセ毛 F(茶),150,2015-01-09,2029-01-01,64
|
||||
182,0,クセ毛 F(赤),150,2015-01-09,2029-01-01,65
|
||||
183,0,イヌミミ,200,2015-10-15,2029-01-01,77
|
||||
184,0,羊角,200,2016-09-21,2029-01-01,78
|
||||
185,0,悪魔の頭羽,200,2016-09-21,2029-01-01,79
|
||||
186,0,とりの巣,200,2016-03-17,2029-01-01,80
|
||||
187,0,おばけの三角ずきん,200,2016-07-20,2029-01-01,81
|
||||
188,0,パラボラアンテナ,200,2016-11-24,2029-01-01,82
|
||||
189,0,パーティ帽(赤),100,2016-12-15,2029-01-01,83
|
||||
190,0,パーティ帽(青),100,2016-12-15,2029-01-01,84
|
||||
191,0,パーティ帽(黄),100,2016-12-15,2029-01-01,85
|
||||
192,0,ホホジロザメ,300,2016-07-20,2029-01-01,86
|
||||
193,0,パンプキンヘッド,300,2015-10-15,2029-01-01,87
|
||||
194,0,雪だるまヘッド(ノーマル),300,2016-12-15,2029-01-01,88
|
||||
195,0,雪だるまヘッド(笑顔),300,2016-12-15,2029-01-01,89
|
||||
196,0,ハート(頭),200,2017-01-18,2029-01-01,90
|
||||
197,0,ぷんぷん,200,2016-11-24,2029-01-01,91
|
||||
198,0,汗(右),100,2015-10-15,2029-01-01,92
|
||||
199,0,汗(左),100,2015-10-15,2029-01-01,93
|
||||
200,0,!?,200,2016-11-24,2029-01-01,94
|
||||
201,0,でかメガネ,150,2016-07-20,2029-01-01,49
|
||||
204,0,つけひげ,150,2016-12-15,2029-01-01,52
|
||||
205,0,くちばし,100,2016-03-17,2029-01-01,53
|
||||
208,0,目隠し線,200,2016-05-18,2029-01-01,56
|
||||
210,0,つけえり,150,2015-04-01,2029-01-01,15
|
||||
211,0,ハーモニカ,150,2016-03-17,2029-01-01,16
|
||||
212,0,金メダル,200,2016-05-18,2029-01-01,17
|
||||
213,0,銀メダル,150,2016-05-18,2029-01-01,18
|
||||
214,0,銅メダル,100,2016-05-18,2029-01-01,19
|
||||
215,0,前かけ(緑),100,2016-11-24,2029-01-01,20
|
||||
216,0,前かけ(黄),100,2016-11-24,2029-01-01,21
|
||||
217,0,前かけ(橙),100,2016-11-24,2029-01-01,22
|
||||
218,0,前かけ(ピンク),100,2016-11-24,2029-01-01,23
|
||||
219,0,前かけ(青),100,2016-11-24,2029-01-01,24
|
||||
220,0,前かけ(赤),100,2016-11-24,2029-01-01,25
|
||||
221,0,初心者マーク,150,2016-07-20,2029-01-01,26
|
||||
222,0,タイマー(緑),50,2015-10-15,2029-01-01,27
|
||||
223,0,タイマー(赤),50,2015-10-15,2029-01-01,28
|
||||
224,0,ハート(胸),200,2017-01-18,2029-01-01,29
|
||||
225,0,失恋ハート,200,2017-01-18,2029-01-01,30
|
||||
226,0,機械の翼,200,2016-03-17,2029-01-01,24
|
||||
227,0,スクールバッグ,150,2017-01-18,2029-01-01,25
|
||||
228,0,押しボタン,200,2016-05-18,2029-01-01,26
|
||||
229,0,イヌしっぽ,200,2015-10-15,2029-01-01,27
|
||||
230,0,恐竜しっぽ,200,2016-07-20,2029-01-01,28
|
||||
231,0,猫又しっぽ,300,2016-09-21,2029-01-01,29
|
||||
232,0,九尾しっぽ,300,2016-12-15,2029-01-01,30
|
||||
233,0,ぶらさがりネコ,300,2017-01-18,2029-01-01,31
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
%2A%2A%2A
|
||||
@@ -0,0 +1,60 @@
|
||||
1001,1,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Play in the Simple Mode or Contest Mode,1,1,1
|
||||
1010,10,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Play with a randomly selected Miku module,1,1,1
|
||||
1011,11,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Hit COOL 500 times or more,1,3,1
|
||||
1012,12,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Take a photo in the PV watching mode,1,1,1
|
||||
1013,13,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Play with the SE turned OFF,1,1,1
|
||||
1002,2,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Do some Max Chain Slides,1,1,1
|
||||
1003,3,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Challenge yourself to beat a trial,1,1,1
|
||||
1004,4,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Play a song on <EX_EXT>,1,2,1
|
||||
1005,5,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Play a chart by Misora,1,2,1
|
||||
1006,6,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Score at least 390390 pts in any song,1,1,1
|
||||
1007,7,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Play a song chosen at random,1,1,1
|
||||
1008,8,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Play with at least 100 percent result,1,1,1
|
||||
1009,9,0,0,2022-06-18 09:00:00.0,2022-06-20 09:00:00.0,Play with the <MDLID>169</MDLID> module,1,1,1
|
||||
3001,1,2,0,2001-01-01 09:00:00.0,2100-01-01 08:59:59.0,Clear a song with the HISPEED mode,1,2,1
|
||||
3002,2,2,0,2001-01-01 09:00:00.0,2100-01-01 08:59:59.0,Clear a song with the HIDDEN mode,1,2,1
|
||||
3003,3,2,0,2001-01-01 09:00:00.0,2100-01-01 08:59:59.0,Clear a song with the SUDDEN mode,1,2,1
|
||||
3004,4,2,0,2001-01-01 09:00:00.0,2100-01-01 08:59:59.0,Enhance your Chain-Perfect Trial streak,1,4,1
|
||||
3005,5,2,0,2001-01-01 09:00:00.0,2100-01-01 08:59:59.0,Beat your rival in a song by percentage,1,4,1
|
||||
2001,1,1,0,2022-06-18 09:00:00.0,2022-06-25 09:00:00.0,Hit COOL at least 1300 times,1,3,1
|
||||
2002,2,1,0,2022-06-18 09:00:00.0,2022-06-25 09:00:00.0,Hit COOL at least 2000 times,1,3,1
|
||||
2003,3,1,0,2022-06-18 09:00:00.0,2022-06-25 09:00:00.0,Achieve a sum of MAX COMBO of 730 or more,1,3,1
|
||||
2004,4,1,0,2022-06-18 09:00:00.0,2022-06-25 09:00:00.0,Achieve a sum of MAX COMBO of 960 or more,1,3,1
|
||||
2005,5,1,0,2022-06-18 09:00:00.0,2022-06-25 09:00:00.0,Score at least 440000 pts in any song,1,1,1
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
***
|
||||
@@ -0,0 +1,401 @@
|
||||
0,0,初音ミク,0,2009-01-01,2029-01-01,1
|
||||
1,0,弱音ハク,50,2009-01-01,2029-01-01,1
|
||||
2,0,亞北ネル,50,2009-01-01,2029-01-01,4
|
||||
3,0,メイコスタイル,100,2009-01-01,2029-01-01,2
|
||||
4,0,リンスタイル,100,2009-01-01,2029-01-01,3
|
||||
5,0,スペチャン5,100,2009-01-01,2029-01-01,4
|
||||
6,0,スペチャン39,50,2009-01-01,2029-01-01,5
|
||||
7,0,ガリア軍第7小隊,100,2009-01-01,2029-01-01,6
|
||||
8,0,P-スタイルPB,50,2009-01-01,2029-01-01,31
|
||||
9,0,P-スタイルCW,50,2009-01-01,2029-01-01,32
|
||||
10,0,P-スタイルIS,50,2009-01-01,2029-01-01,33
|
||||
11,0,P-スタイルRP,50,2009-01-01,2029-01-01,34
|
||||
12,0,P-スタイルLP,50,2009-01-01,2029-01-01,35
|
||||
13,0,P-スタイルFB,50,2009-01-01,2029-01-01,36
|
||||
14,0,P-スタイルMG,50,2009-01-01,2029-01-01,37
|
||||
15,0,P-スタイルCG,300,2009-01-01,2029-01-01,38
|
||||
16,0,チア,50,2009-01-01,2029-01-01,7
|
||||
17,0,プラグイン,100,2009-01-01,2029-01-01,8
|
||||
18,0,ゴシック,100,2009-01-01,2029-01-01,9
|
||||
19,0,プリンセス,50,2009-01-01,2029-01-01,10
|
||||
20,0,ミコ,100,2009-01-01,2029-01-01,11
|
||||
21,0,にゃんこ,50,2009-01-01,2029-01-01,12
|
||||
22,0,ねむねむ,100,2009-01-01,2029-01-01,13
|
||||
23,0,ハートハンター,100,2009-01-01,2029-01-01,14
|
||||
24,0,ボーカル,50,2009-01-01,2029-01-01,15
|
||||
25,0,パンク,100,2009-01-01,2029-01-01,16
|
||||
26,0,ダンサー,50,2009-01-01,2029-01-01,17
|
||||
27,0,スター,100,2009-01-01,2029-01-01,18
|
||||
28,0,フェアリー,100,2009-01-01,2029-01-01,19
|
||||
29,0,スクール,100,2009-01-01,2029-01-01,20
|
||||
30,0,スノウ,50,2009-01-01,2029-01-01,21
|
||||
31,0,アラビアン,100,2009-01-01,2029-01-01,22
|
||||
32,0,みやび,50,2009-01-01,2029-01-01,23
|
||||
33,0,チャイナ,300,2009-01-01,2029-01-01,24
|
||||
34,0,マジシャン,50,2009-01-01,2029-01-01,25
|
||||
35,0,ホワイトドレス,100,2009-01-01,2029-01-01,26
|
||||
36,0,パイレーツ,50,2009-01-01,2029-01-01,27
|
||||
37,0,VN02,100,2009-01-01,2029-01-01,28
|
||||
38,0,ギャラクシー,100,2009-01-01,2029-01-01,29
|
||||
39,0,ハツネミク,100,2009-01-01,2029-01-01,30
|
||||
40,0,鏡音リン,50,2009-01-01,2029-01-01,1
|
||||
41,0,鏡音レン,50,2009-01-01,2029-01-01,1
|
||||
42,0,巡音ルカ,50,2009-01-01,2029-01-01,1
|
||||
43,0,咲音メイコ,300,2009-01-01,2029-01-01,7
|
||||
44,0,メイコ,50,2009-01-01,2029-01-01,1
|
||||
45,0,カイト,50,2009-01-01,2029-01-01,1
|
||||
46,0,初音ミク スイムウェアS,1000,2009-01-01,2029-01-01,140
|
||||
47,0,初音ミク スイムウェア,1000,2009-01-01,2029-01-01,141
|
||||
48,0,鏡音リン スイムウェア,1000,2009-01-01,2029-01-01,39
|
||||
49,0,鏡音レン スイムウェア,300,2009-01-01,2029-01-01,33
|
||||
50,0,巡音ルカ スイムウェア,1000,2009-01-01,2029-01-01,31
|
||||
51,0,メイコ スイムウェア,1000,2009-01-01,2029-01-01,24
|
||||
52,0,カイト スイムウェア,300,2009-01-01,2029-01-01,31
|
||||
53,0,初音ミク アペンド,300,2010-08-31,2029-01-01,152
|
||||
54,0,ホワイトワンピース,100,2010-11-16,2029-01-01,49
|
||||
55,0,ナチュラル,200,2010-11-16,2029-01-01,48
|
||||
56,0,スピリチュアル,200,2010-11-16,2029-01-01,41
|
||||
57,0,カラフルドロップ,200,2010-12-27,2029-01-01,57
|
||||
58,0,初音ミク 蝶,100,2010-11-16,2029-01-01,40
|
||||
59,0,チアフルキャンディ,200,2010-12-27,2029-01-01,6
|
||||
60,0,スクールジャージ,100,2010-12-27,2029-01-01,3
|
||||
61,0,巡音ルカ 華,100,2010-11-16,2029-01-01,2
|
||||
62,0,初音ミク クリスマス,150,2010-11-30,2029-01-01,153
|
||||
63,0,鏡音リン クリスマス,150,2010-11-30,2029-01-01,50
|
||||
64,0,鏡音レン クリスマス,150,2010-11-30,2029-01-01,41
|
||||
65,0,巡音ルカ クリスマス,150,2010-11-30,2029-01-01,40
|
||||
66,0,メイコ クリスマス,150,2010-11-30,2029-01-01,32
|
||||
67,0,カイト クリスマス,150,2010-11-30,2029-01-01,41
|
||||
68,0,雪ミク 2010,300,2011-01-31,2029-01-01,154
|
||||
69,0,ヴィンテージドレス,200,2011-02-17,2029-01-01,39
|
||||
70,0,ピンクポップス,100,2011-01-31,2029-01-01,55
|
||||
71,0,ピンクポップス AS,100,2011-01-31,2029-01-01,56
|
||||
72,0,リアクター,200,2011-02-24,2029-01-01,3
|
||||
73,0,パンキッシュ,200,2011-02-24,2029-01-01,2
|
||||
74,0,ハードロック,200,2011-01-31,2029-01-01,5
|
||||
75,0,クラシック,200,2011-02-17,2029-01-01,2
|
||||
76,0,スカーレット,200,2011-02-17,2029-01-01,3
|
||||
77,0,雪ミク 2011,300,2011-01-31,2029-01-01,155
|
||||
78,0,おさんぽスタイル,150,2011-07-26,2029-01-01,42
|
||||
79,0,みくずきん,150,2011-05-20,2029-01-01,43
|
||||
80,0,イエロー,150,2011-11-01,2029-01-01,44
|
||||
81,0,ジャー★ジ,150,2011-09-08,2029-01-01,45
|
||||
82,0,ノーブル,150,2011-05-20,2029-01-01,46
|
||||
83,0,パウダー,150,2011-09-08,2029-01-01,47
|
||||
84,0,エールダンジュ,150,2011-11-01,2029-01-01,50
|
||||
85,0,スペイシーナース,200,2012-03-13,2029-01-01,51
|
||||
86,0,初音ミク キュート,200,2011-07-26,2029-01-01,52
|
||||
87,0,エンジェル,200,2012-01-10,2029-01-01,53
|
||||
88,0,サイハテミク,150,2011-07-26,2029-01-01,54
|
||||
89,0,∞,200,2012-02-14,2029-01-01,58
|
||||
90,0,初音ミク スイムウェアB,1000,2011-07-26,2029-01-01,143
|
||||
91,0,アシンメトリーR,200,2011-09-08,2029-01-01,2
|
||||
92,0,EoEスタイル,200,2011-11-01,2029-01-01,4
|
||||
93,0,鏡音リン キュート,200,2011-07-26,2029-01-01,5
|
||||
94,0,鏡音リン スイムウェアT,1000,2011-07-26,2029-01-01,41
|
||||
95,0,アシンメトリーL,200,2011-09-08,2029-01-01,4
|
||||
96,0,鏡音レン スイムウェアWS,750,2011-07-26,2029-01-01,35
|
||||
97,0,シフォンワンピース,150,2011-06-21,2029-01-01,3
|
||||
98,0,フロイライン,200,2011-09-08,2029-01-01,4
|
||||
99,0,VFスーツ,200,2012-01-10,2029-01-01,6
|
||||
100,0,巡音ルカ スイムウェアP,1000,2011-07-26,2029-01-01,32
|
||||
101,0,キャンパス,200,2012-02-14,2029-01-01,3
|
||||
102,0,ネコサイバー,300,2011-06-21,2029-01-01,4
|
||||
103,0,カイト スイムウェアV,750,2011-07-26,2029-01-01,32
|
||||
104,0,カイト スイムウェアV AS,750,2011-07-26,2029-01-01,34
|
||||
105,0,ふわふわコート,200,2011-11-01,2029-01-01,2
|
||||
106,0,モダンガール,150,2012-03-13,2029-01-01,4
|
||||
107,0,モダンガール AS,150,2012-03-13,2029-01-01,5
|
||||
108,0,メイコ スイムウェアB,1000,2011-07-26,2029-01-01,26
|
||||
109,0,エスニック,200,2011-05-20,2029-01-01,5
|
||||
110,0,亞北ネル スイムウェア,1000,2011-07-26,2029-01-01,12
|
||||
111,0,サイバーダイブ,200,2011-05-20,2029-01-01,2
|
||||
112,0,弱音ハク スイムウェア,1000,2011-07-26,2029-01-01,11
|
||||
113,0,ブラックワンピース,300,2011-05-20,2029-01-01,8
|
||||
114,0,ブラックワンピース NS,300,2011-05-20,2029-01-01,9
|
||||
115,0,咲音メイコ スイムウェア,1000,2011-07-26,2029-01-01,13
|
||||
116,0,メイコ 大正浪漫,250,2011-11-01,2029-01-01,30
|
||||
117,0,鏡音リン スクールウェア,250,2011-12-06,2029-01-01,45
|
||||
118,0,鏡音レン スクールウェア,250,2011-12-06,2029-01-01,40
|
||||
119,0,巡音ルカ 魔女っ娘Style,250,2012-01-31,2029-01-01,37
|
||||
120,0,カイト ホワイトブレザー,250,2012-02-14,2029-01-01,38
|
||||
121,0,フェアリーマカロン,300,2011-06-21,2029-01-01,41
|
||||
122,0,セクシープディング,300,2011-06-21,2029-01-01,33
|
||||
124,0,ホワイト・イヴ,250,2012-11-05,2029-01-01,61
|
||||
125,0,Hello World.,250,2012-10-04,2029-01-01,68
|
||||
126,0,レーシングミク2010ver.,200,2012-11-22,2029-01-01,62
|
||||
127,0,レーシングミク2011ver.,250,2012-12-06,2029-01-01,63
|
||||
128,0,フェイ・イェン スタイル,250,2012-11-22,2029-01-01,66
|
||||
129,0,回転少女,250,2012-11-05,2029-01-01,71
|
||||
130,0,ラセツトムクロ,250,2012-05-24,2029-01-01,69
|
||||
131,0,オービット,250,2012-11-05,2029-01-01,60
|
||||
132,0,パッチワーク,250,2012-04-26,2029-01-01,65
|
||||
133,0,ソニックスタイル,250,2012-08-31,2029-01-01,59
|
||||
134,0,チロル,250,2012-10-04,2029-01-01,64
|
||||
135,0,コンフリクト,200,2012-04-26,2029-01-01,70
|
||||
136,0,シャイニー,250,2012-07-05,2029-01-01,72
|
||||
137,0,TYPE2020,250,2012-08-31,2029-01-01,67
|
||||
138,0,部活少女,250,2012-07-31,2029-01-01,6
|
||||
139,0,ゴシック・パープル,250,2012-07-31,2029-01-01,3
|
||||
141,0,鏡音リン アペンド,300,2011-12-27,2029-01-01,51
|
||||
142,0,ネームレス No.1,200,2012-12-27,2029-01-01,8
|
||||
143,0,レーシングリン2010ver.,200,2012-11-22,2029-01-01,12
|
||||
144,0,ブラックスター,250,2012-09-14,2029-01-01,7
|
||||
145,0,陽炎,250,2012-04-26,2029-01-01,11
|
||||
146,0,鏡音リン 蘇芳,150,2012-04-05,2029-01-01,9
|
||||
147,0,鏡音レン アペンド,300,2011-12-27,2029-01-01,42
|
||||
148,0,ブルームーン,250,2012-09-14,2029-01-01,5
|
||||
149,0,鏡音レン 藍鉄,150,2012-04-05,2029-01-01,6
|
||||
150,0,ストレンジダーク,250,2012-07-05,2029-01-01,8
|
||||
151,0,ネームレス No.7,200,2012-12-27,2029-01-01,9
|
||||
153,0,サイレンス,250,2012-07-05,2029-01-01,7
|
||||
154,0,レーシングルカ2010ver.,200,2012-11-22,2029-01-01,10
|
||||
155,0,サイバーネイション,300,2011-12-15,2029-01-01,42
|
||||
156,0,ナギサ・レプカ,200,2012-10-04,2029-01-01,8
|
||||
157,0,ナギサ・レプカ AS,200,2012-10-04,2029-01-01,9
|
||||
158,0,時雨,250,2012-05-24,2029-01-01,6
|
||||
159,0,スミレ,250,2012-07-05,2029-01-01,5
|
||||
160,0,VFニンジャ,200,2013-02-15,2029-01-01,7
|
||||
161,0,VFニンジャ AS,200,2013-02-15,2029-01-01,8
|
||||
162,0,怪盗ブラックテール,250,2012-11-05,2029-01-01,6
|
||||
163,0,紅葉,250,2012-05-24,2029-01-01,8
|
||||
164,0,レーシングメイコ2010ver.,200,2012-11-22,2029-01-01,9
|
||||
165,0,ローレライ,250,2012-08-31,2029-01-01,7
|
||||
166,0,ノスタルジー,250,2012-07-31,2029-01-01,10
|
||||
167,0,雪ミク 2012,300,2011-12-19,2029-01-01,156
|
||||
168,0,AMERICANA,300,2012-07-31,2029-01-01,167
|
||||
169,0,桜ミク,300,2012-04-05,2029-01-01,168
|
||||
170,0,巡音ルカ コンフリクト,300,2012-04-26,2029-01-01,43
|
||||
171,0,鏡音リン 蘇芳 妖狐,200,2012-04-05,2029-01-01,10
|
||||
172,0,鏡音レン 藍鉄 妖狐,200,2012-04-05,2029-01-01,7
|
||||
188,0,ドリーマー,250,2013-01-30,2029-01-01,120
|
||||
189,0,初音ミク 妄想ガール,250,2012-12-06,2029-01-01,121
|
||||
190,0,雪ミク 2013,300,2012-12-17,2029-01-01,157
|
||||
191,0,鏡音リン 妄想ガール,250,2012-12-06,2029-01-01,29
|
||||
192,0,ロジカリスト,250,2012-12-06,2029-01-01,25
|
||||
193,0,オンザロック,250,2013-01-30,2029-01-01,22
|
||||
194,0,雪ミク 2013 AS,300,2012-12-17,2029-01-01,158
|
||||
195,0,ディープスカイ,250,2014-02-25,2029-01-01,73
|
||||
196,0,紫揚羽,250,2015-04-23,2029-01-01,74
|
||||
197,0,メモリア,250,2015-03-26,2029-01-01,75
|
||||
198,0,理系少女,250,2014-06-10,2029-01-01,76
|
||||
199,0,ピエレッタ,250,2013-09-25,2029-01-01,77
|
||||
200,0,イノセント,250,2014-04-17,2029-01-01,78
|
||||
201,0,堕悪天使,250,2014-04-17,2029-01-01,79
|
||||
202,0,サマーメモリー,250,2014-08-28,2029-01-01,80
|
||||
203,0,初音ミク 翠玉,250,2016-05-26,2029-01-01,81
|
||||
204,0,ソリチュード,250,2015-04-23,2029-01-01,82
|
||||
205,0,ホーリーゴッデス,250,2015-05-28,2029-01-01,83
|
||||
206,0,フォニュエールスタイル,250,2014-07-29,2029-01-01,84
|
||||
207,0,ねこねこケープ,250,2014-06-10,2029-01-01,85
|
||||
208,0,アジテーション,250,2013-09-25,2029-01-01,86
|
||||
209,0,スターヴォイス,200,2013-09-25,2029-01-01,87
|
||||
210,0,ハートビート,250,2014-09-17,2029-01-01,89
|
||||
211,0,パンジー,250,2013-09-25,2029-01-01,90
|
||||
212,0,レーシングミク2012ver.,250,2013-03-12,2029-01-01,91
|
||||
213,0,わがまま工場長,250,2015-05-28,2029-01-01,92
|
||||
214,0,Hello,Good night.,250,2014-02-25,2029-01-01,93
|
||||
215,0,初音ミク みずたまビキニ,1000,2013-07-04,2029-01-01,145
|
||||
216,0,初音ミク スクール競泳,1000,2013-06-06,2029-01-01,144
|
||||
217,0,初音ミク 浴衣スタイル,200,2013-07-31,2029-01-01,94
|
||||
218,0,らんみんぐ,250,2013-04-26,2029-01-01,95
|
||||
219,0,リボンガール,250,2013-01-30,2029-01-01,96
|
||||
220,0,メランコリー,250,2014-01-15,2029-01-01,13
|
||||
221,0,トランスミッター,250,2014-04-17,2029-01-01,14
|
||||
222,0,鏡音リン 桜月,250,2013-12-10,2029-01-01,15
|
||||
223,0,鏡音リン 雨,250,2014-07-29,2029-01-01,16
|
||||
224,0,鏡音リン しましまビキニ,1000,2013-07-04,2029-01-01,42
|
||||
225,0,鏡音リン SW スクール,1000,2013-06-06,2029-01-01,43
|
||||
226,0,鏡音リン 浴衣スタイル,150,2013-07-31,2029-01-01,17
|
||||
227,0,魔導師のタマゴ,250,2013-09-11,2029-01-01,19
|
||||
228,0,スタイリッシュエナジーR,250,2013-04-05,2029-01-01,20
|
||||
229,0,トラッドスクール,250,2012-12-27,2029-01-01,21
|
||||
230,0,スターマイン,250,2013-09-25,2029-01-01,10
|
||||
231,0,レシーバー,250,2014-04-17,2029-01-01,11
|
||||
232,0,鏡音レン 鳳月,250,2014-07-29,2029-01-01,12
|
||||
233,0,鏡音レン 鶴,250,2013-12-10,2029-01-01,13
|
||||
234,0,バッドボーイ,200,2013-09-25,2029-01-01,14
|
||||
235,0,鏡音レン SW ボクサー,1000,2013-06-06,2029-01-01,36
|
||||
236,0,鏡音レン 浴衣スタイル,200,2013-07-31,2029-01-01,16
|
||||
237,0,スタイリッシュエナジーL,250,2013-04-05,2029-01-01,17
|
||||
238,0,生徒会執行部,250,2012-12-27,2029-01-01,18
|
||||
239,0,バッドボーイ AS,200,2013-09-25,2029-01-01,15
|
||||
240,0,ゆるふわコーデ,250,2014-06-25,2029-01-01,11
|
||||
241,0,エターナルホワイト,250,2013-12-10,2029-01-01,12
|
||||
242,0,アムール,250,2014-04-17,2029-01-01,13
|
||||
243,0,巡音ルカ 紅玉,250,2016-05-26,2029-01-01,14
|
||||
244,0,巡音ルカ リゾートビキニ,1000,2013-07-04,2029-01-01,34
|
||||
245,0,巡音ルカ 競泳タイプ,1000,2013-06-06,2029-01-01,35
|
||||
246,0,巡音ルカ 浴衣スタイル,200,2013-07-31,2029-01-01,15
|
||||
247,0,森の妖精姫,250,2013-09-11,2029-01-01,16
|
||||
248,0,クイン・ビー,250,2013-04-26,2029-01-01,17
|
||||
249,0,放課後モード,250,2013-01-30,2029-01-01,18
|
||||
250,0,レクイエム,250,2013-12-17,2029-01-01,9
|
||||
251,0,ギルティ,250,2014-04-17,2029-01-01,10
|
||||
252,0,ジェネラル,200,2013-09-25,2029-01-01,11
|
||||
253,0,KAITO ハーフスパッツ,1000,2013-06-06,2029-01-01,36
|
||||
254,0,KAITO 浴衣スタイル,200,2013-07-31,2029-01-01,13
|
||||
255,0,ジーニアス,250,2013-05-15,2029-01-01,14
|
||||
256,0,学ラン★パーカー,250,2013-02-15,2029-01-01,15
|
||||
257,0,ジェネラル AS,200,2013-09-25,2029-01-01,12
|
||||
258,0,ブルークリスタル,250,2014-11-05,2029-01-01,10
|
||||
259,0,ノエル・ルージュ,250,2013-12-10,2029-01-01,11
|
||||
260,0,MEIKO ロングパレオ,1000,2013-07-04,2029-01-01,27
|
||||
261,0,MEIKO ウォーターポロ,1000,2013-06-06,2029-01-01,28
|
||||
262,0,MEIKO 浴衣スタイル,200,2013-07-31,2029-01-01,12
|
||||
263,0,ホイッスル,250,2013-05-15,2029-01-01,13
|
||||
264,0,グラデュエート,250,2013-02-15,2029-01-01,14
|
||||
265,0,BBオペレーター,250,2013-03-12,2029-01-01,15
|
||||
266,0,鏡音リン 浴衣スタイル AS,150,2013-07-31,2029-01-01,18
|
||||
267,0,カイト V3,300,2013-03-12,2029-01-01,42
|
||||
268,0,深海少女,250,2013-07-31,2029-01-01,169
|
||||
269,0,ハニーウィップ,250,2014-10-02,2029-01-01,148
|
||||
270,0,壱ノ桜・桜花,150,2015-03-26,2029-01-01,149
|
||||
271,0,リンちゃん愛し隊1号,200,2014-12-18,2029-01-01,151
|
||||
272,0,シザーズ,250,2014-06-25,2029-01-01,46
|
||||
273,0,弐ノ桜・胡蝶,200,2015-03-26,2029-01-01,47
|
||||
274,0,鏡音リン Future Style,300,2014-12-18,2029-01-01,49
|
||||
275,0,トリッカー,250,2014-12-18,2029-01-01,38
|
||||
276,0,弐ノ桜・扇舞,200,2015-03-26,2029-01-01,39
|
||||
277,0,参ノ桜・楓香,200,2015-03-26,2029-01-01,38
|
||||
278,0,リンちゃん愛し隊2号,200,2014-12-18,2029-01-01,39
|
||||
279,0,零ノ桜・蒼雪,150,2015-03-26,2029-01-01,39
|
||||
280,0,零ノ桜・紅椿,200,2015-03-26,2029-01-01,31
|
||||
281,0,リンケージ,250,2013-12-17,2029-01-01,147
|
||||
282,0,スターヴォイス AS,200,2013-09-25,2029-01-01,88
|
||||
283,0,重音テト,300,2013-09-25,2029-01-01,14
|
||||
284,0,雪ミク 2014,300,2013-12-17,2029-01-01,159
|
||||
285,0,雪ミク 2014 AS,100,2029-01-01,2029-01-01,160
|
||||
286,0,CA 初音ミク,250,2014-01-15,2029-01-01,122
|
||||
287,0,CA 鏡音リン,250,2014-01-15,2029-01-01,30
|
||||
288,0,CA 巡音ルカ,250,2014-01-15,2029-01-01,26
|
||||
289,0,CA メイコ,250,2014-01-15,2029-01-01,19
|
||||
290,0,マジカルミライ,300,2014-02-12,2029-01-01,170
|
||||
291,0,Cheerful ミク,150,2014-02-25,2029-01-01,123
|
||||
292,0,Cheerful ミク AS,150,2014-02-25,2029-01-01,124
|
||||
293,0,Cheerful リン,200,2014-02-25,2029-01-01,31
|
||||
294,0,Cheerful レン,200,2014-02-25,2029-01-01,26
|
||||
295,0,Cheerful ルカ,200,2014-02-25,2029-01-01,27
|
||||
296,0,Cheerful カイト,200,2014-02-25,2029-01-01,23
|
||||
297,0,Cheerful メイコ,200,2014-02-25,2029-01-01,20
|
||||
298,0,Cheerful カイト AS,200,2029-01-01,2029-01-01,24
|
||||
299,0,初音ミク V3,300,2014-08-28,2029-01-01,171
|
||||
300,0,アバンガード,250,2015-07-30,2029-01-01,97
|
||||
301,0,ナナイロライン,250,2015-08-28,2029-01-01,98
|
||||
302,0,ブレス・ユー,250,2015-10-08,2029-01-01,99
|
||||
303,0,花詞,250,2015-11-05,2029-01-01,100
|
||||
304,0,華車,250,2015-11-05,2029-01-01,101
|
||||
305,0,リグレット,250,2015-11-05,2029-01-01,102
|
||||
306,0,マリオネット,250,2015-11-05,2029-01-01,104
|
||||
308,0,ライアー,250,2016-01-28,2029-01-01,105
|
||||
309,0,月光アゲハ,250,2015-12-22,2029-01-01,106
|
||||
310,0,サイレン,250,2015-10-08,2029-01-01,107
|
||||
311,0,ローザ・ビアンカ,250,2016-06-30,2029-01-01,108
|
||||
313,0,メテオライト,250,2015-07-30,2029-01-01,111
|
||||
314,0,シャノワール,200,2015-06-26,2029-01-01,112
|
||||
315,0,シャノワール AS,200,2015-06-26,2029-01-01,113
|
||||
316,0,シュープリーム,250,2016-04-01,2029-01-01,114
|
||||
317,0,オレンジブロッサム,250,2015-08-28,2029-01-01,115
|
||||
318,0,ディメンション,250,2015-07-30,2029-01-01,116
|
||||
319,0,ストリートポップ,250,2016-01-28,2029-01-01,117
|
||||
320,0,ゆるふわパステル,250,2016-01-28,2029-01-01,118
|
||||
321,0,夢見るパンダ,250,2015-06-26,2029-01-01,22
|
||||
322,0,フェイカー,250,2016-01-28,2029-01-01,23
|
||||
323,0,ヒマワリ,200,2015-12-22,2029-01-01,24
|
||||
324,0,ソレイユ,250,2015-12-22,2029-01-01,26
|
||||
325,0,フェアリーワンピース,250,2015-12-22,2029-01-01,27
|
||||
326,0,恋するシロクマ,250,2015-06-26,2029-01-01,19
|
||||
327,0,アヤサキ,200,2015-12-22,2029-01-01,20
|
||||
328,0,シエル,250,2015-12-22,2029-01-01,22
|
||||
329,0,イレイザー,250,2016-01-28,2029-01-01,23
|
||||
330,0,ホワイトエッジ,250,2015-12-22,2029-01-01,24
|
||||
331,0,サクセサー,250,2015-07-30,2029-01-01,19
|
||||
332,0,テンプテーション,250,2016-01-28,2029-01-01,20
|
||||
334,0,リクルーター,250,2015-01-27,2029-01-01,22
|
||||
335,0,フローラル,250,2016-01-28,2029-01-01,23
|
||||
336,0,ローザ・ブルー,250,2016-06-30,2029-01-01,16
|
||||
338,0,オリジネイター,250,2016-01-28,2029-01-01,19
|
||||
339,0,ホリデイ,250,2015-11-05,2029-01-01,20
|
||||
340,0,ブレイジング,250,2015-11-05,2029-01-01,16
|
||||
341,0,マリーン・リボン,250,2015-11-05,2029-01-01,17
|
||||
343,0,うさみみパーカー,250,2016-08-31,2029-01-01,119
|
||||
344,0,アルパーカー R,250,2016-09-29,2029-01-01,28
|
||||
345,0,アルパーカー L,250,2016-09-29,2029-01-01,25
|
||||
346,0,ねこみみパーカー,250,2016-08-31,2029-01-01,24
|
||||
347,0,おサカナつなぎ,250,2016-10-27,2029-01-01,21
|
||||
348,0,ひつじさんウェア,250,2016-10-27,2029-01-01,18
|
||||
349,0,初音ミク スイムウェア/ST,1000,2016-07-28,2029-01-01,142
|
||||
350,0,鏡音リン スイムウェア/ST,1000,2016-07-28,2029-01-01,40
|
||||
351,0,鏡音レン スイムウェア/ST,300,2016-07-28,2029-01-01,34
|
||||
352,0,巡音ルカ スイムウェアP/ST,1000,2016-07-28,2029-01-01,33
|
||||
353,0,KAITO スイムウェアV/ST,750,2016-07-28,2029-01-01,33
|
||||
354,0,KAITO スイムウェアV AS/ST,750,2016-07-28,2029-01-01,35
|
||||
355,0,MEIKO スイムウェア/ST,1000,2016-07-28,2029-01-01,25
|
||||
356,0,M・S・J,300,2016-04-01,2029-01-01,15
|
||||
359,0,out of the gravity,250,2014-08-28,2029-01-01,126
|
||||
360,0,インタビュア ミク,250,2014-10-02,2029-01-01,127
|
||||
361,0,インタビュア ルカ,250,2014-10-02,2029-01-01,28
|
||||
362,0,スイートパンプキン,300,2014-10-02,2029-01-01,172
|
||||
363,0,MEIKO V3,300,2014-11-05,2029-01-01,34
|
||||
364,0,雪ミク 2015,300,2014-12-18,2029-01-01,161
|
||||
365,0,壱ノ桜・白桜花,150,2015-03-26,2029-01-01,150
|
||||
366,0,零ノ桜・白雪,150,2015-03-26,2029-01-01,40
|
||||
367,0,ダイヤモンドダスト,250,2015-01-27,2029-01-01,25
|
||||
368,0,アイスフォグ,250,2015-01-27,2029-01-01,27
|
||||
369,0,テレカクシパーカー 黄色,250,2015-04-23,2029-01-01,28
|
||||
370,0,テレカクシパーカー 青色,250,2015-04-23,2029-01-01,26
|
||||
371,0,スチャラカハツネ,250,2015-05-28,2029-01-01,130
|
||||
372,0,マジックシェフ,250,2015-06-26,2029-01-01,32
|
||||
373,0,グラデーションリゾート,1000,2015-08-06,2029-01-01,146
|
||||
374,0,ミラクルスターリゾート,1000,2015-08-06,2029-01-01,44
|
||||
375,0,ポップスターリゾート,1000,2015-08-06,2029-01-01,37
|
||||
376,0,トゥインクルリゾート,1000,2015-08-06,2029-01-01,36
|
||||
377,0,プレイドリゾート,1000,2015-08-06,2029-01-01,37
|
||||
378,0,バイカラーリボンリゾート,1000,2015-08-06,2029-01-01,29
|
||||
379,0,ありふれミク,250,2015-08-28,2029-01-01,128
|
||||
380,0,P4Dスタイル,300,2016-06-23,2029-01-01,173
|
||||
381,0,PIANO*GIRL,250,2015-10-08,2029-01-01,129
|
||||
382,0,重音テト スイムウェア,1000,2015-11-05,2029-01-01,16
|
||||
383,0,巡音ルカV4X,300,2016-01-28,2029-01-01,44
|
||||
385,0,Trip The Light Fantastic,250,2016-04-27,2029-01-01,132
|
||||
386,0,Poppin Delight,250,2016-04-27,2029-01-01,33
|
||||
387,0,Bebop Knave,250,2016-04-27,2029-01-01,29
|
||||
389,0,プランセス・ブランシュ,250,2016-04-27,2029-01-01,133
|
||||
390,0,プランス・ブラン,250,2016-04-27,2029-01-01,27
|
||||
391,0,アドレサンスプリンセス,250,2016-04-27,2029-01-01,343
|
||||
392,0,アドレサンスナイト,250,2016-04-27,2029-01-01,30
|
||||
393,0,マーチ・ヘイヤ,250,2016-08-31,2029-01-01,136
|
||||
394,0,アゲアゲアゲイン,250,2016-02-26,2029-01-01,131
|
||||
395,0,エトワール,250,2016-06-30,2029-01-01,135
|
||||
398,0,フェアウェル,250,2016-06-30,2029-01-01,134
|
||||
399,0,天袖,250,2016-12-21,2029-01-01,36
|
||||
402,0,雪ミク 2016,300,2015-12-22,2029-01-01,162
|
||||
403,0,パジャマパーティ ミク,250,2017-01-26,2029-01-01,139
|
||||
404,0,パジャマパーティ リン,250,2017-01-26,2029-01-01,38
|
||||
405,0,パジャマパーティ レン,250,2017-01-26,2029-01-01,32
|
||||
406,0,パジャマパーティ ルカ,250,2017-01-26,2029-01-01,30
|
||||
407,0,パジャマパーティ カイト,250,2017-01-26,2029-01-01,30
|
||||
408,0,パジャマパーティ メイコ,250,2017-01-26,2029-01-01,23
|
||||
409,0,Phantom Thief ミク,250,2016-10-27,2029-01-01,137
|
||||
410,0,Phantom Thief リン,250,2016-10-27,2029-01-01,35
|
||||
411,0,Phantom Thief メイコ,250,2016-10-27,2029-01-01,21
|
||||
412,0,Phantom Thief カイト,250,2016-10-27,2029-01-01,28
|
||||
413,0,鉄道員・鶯,250,2016-12-21,2029-01-01,138
|
||||
414,0,鉄道員・金糸雀,250,2016-12-21,2029-01-01,37
|
||||
415,0,鉄道員・銀朱,250,2016-12-21,2029-01-01,31
|
||||
416,0,鉄道員・薔薇,250,2016-12-21,2029-01-01,29
|
||||
417,0,鉄道員・空,250,2016-12-21,2029-01-01,29
|
||||
418,0,鉄道員・紅葡萄,250,2016-12-21,2029-01-01,22
|
||||
419,0,雪ミク 2017,300,2016-12-21,2029-01-01,163
|
||||
420,0,ヒマワリ AS,200,2015-12-22,2029-01-01,25
|
||||
421,0,アヤサキ AS,200,2015-12-22,2029-01-01,21
|
||||
422,0,みくりすたる☆,300,2016-05-26,2029-01-01,125
|
||||
423,0,マイディアバニー,1000,2017-08-31,2029-01-01,174
|
||||
424,0,ローザ・ノッテ,250,2016-12-21,2029-01-01,110
|
||||
425,0,ローザ・ルーノ,250,2016-12-21,2029-01-01,18
|
||||
426,0,GHOST,250,2017-12-13,2029-01-01,175
|
||||
427,0,セレブレーション,300,2017-12-13,2029-01-01,176
|
||||
428,0,雪ミク 2018 AS,300,2019-04-24,2029-01-01,165
|
||||
429,0,雪ミク 2019,300,2019-04-24,2029-01-01,166
|
||||
430,0,雪ミク 2018,300,2019-04-24,2029-01-01,164
|
||||
431,0,Catch The Wave,900,2020-02-20,2029-01-01,177
|
||||
@@ -0,0 +1,12 @@
|
||||
from core.data import Data
|
||||
from core.config import CoreConfig
|
||||
from titles.diva.schema import DivaProfileData, DivaScoreData, DivaItemData, DivaStaticData
|
||||
|
||||
class DivaData(Data):
|
||||
def __init__(self, cfg: CoreConfig) -> None:
|
||||
super().__init__(cfg)
|
||||
|
||||
self.profile = DivaProfileData(self.config, self.session)
|
||||
self.score = DivaScoreData(self.config, self.session)
|
||||
self.item = DivaItemData(self.config, self.session)
|
||||
self.static = DivaStaticData(self.config, self.session)
|
||||
@@ -0,0 +1,105 @@
|
||||
from twisted.web.http import Request
|
||||
import yaml
|
||||
import logging, coloredlogs
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
import zlib
|
||||
import json
|
||||
import urllib.parse
|
||||
import base64
|
||||
|
||||
from core.config import CoreConfig
|
||||
from titles.diva.config import DivaConfig
|
||||
from titles.diva.base import DivaBase
|
||||
|
||||
class DivaServlet():
|
||||
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
|
||||
self.core_cfg = core_cfg
|
||||
self.game_cfg = DivaConfig()
|
||||
self.game_cfg.update(yaml.safe_load(open(f"{cfg_dir}/diva.yaml")))
|
||||
|
||||
self.base = DivaBase(core_cfg, self.game_cfg)
|
||||
|
||||
self.logger = logging.getLogger("diva")
|
||||
log_fmt_str = "[%(asctime)s] Diva | %(levelname)s | %(message)s"
|
||||
log_fmt = logging.Formatter(log_fmt_str)
|
||||
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(self.core_cfg.server.log_dir, "diva"), encoding='utf8',
|
||||
when="d", backupCount=10)
|
||||
|
||||
fileHandler.setFormatter(log_fmt)
|
||||
|
||||
consoleHandler = logging.StreamHandler()
|
||||
consoleHandler.setFormatter(log_fmt)
|
||||
|
||||
self.logger.addHandler(fileHandler)
|
||||
self.logger.addHandler(consoleHandler)
|
||||
|
||||
self.logger.setLevel(self.game_cfg.server.loglevel)
|
||||
coloredlogs.install(level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str)
|
||||
|
||||
def render_POST(self, req: Request, version: int, url_path: str) -> bytes:
|
||||
req_raw = req.content.getvalue()
|
||||
url_header = req.getAllHeaders()
|
||||
|
||||
#Ping Dispatch
|
||||
if "THIS_STRING_SEPARATES"in str(url_header):
|
||||
binary_request = req_raw.splitlines()
|
||||
binary_cmd_decoded = binary_request[3].decode("utf-8")
|
||||
binary_array = binary_cmd_decoded.split('&')
|
||||
|
||||
bin_req_data = {}
|
||||
|
||||
for kvp in binary_array:
|
||||
split_bin = kvp.split("=")
|
||||
bin_req_data[split_bin[0]] = split_bin[1]
|
||||
|
||||
self.logger.info(f"Binary {bin_req_data['cmd']} Request")
|
||||
self.logger.debug(bin_req_data)
|
||||
|
||||
handler = getattr(self.base, f"handle_{bin_req_data['cmd']}_request")
|
||||
resp = handler(bin_req_data)
|
||||
|
||||
self.logger.debug(f"Response cmd={bin_req_data['cmd']}&req_id={bin_req_data['req_id']}&stat=ok{resp}")
|
||||
return f"cmd={bin_req_data['cmd']}&req_id={bin_req_data['req_id']}&stat=ok{resp}".encode('utf-8')
|
||||
|
||||
#Main Dispatch
|
||||
json_string = json.dumps(req_raw.decode("utf-8")) #Take the response and decode as UTF-8 and dump
|
||||
b64string = json_string.replace(r'\n', '\n') # Remove all \n and separate them as new lines
|
||||
gz_string = base64.b64decode(b64string) # Decompressing the base64 string
|
||||
|
||||
try:
|
||||
url_data = zlib.decompress( gz_string ).decode("utf-8") # Decompressing the gzip
|
||||
except zlib.error as e:
|
||||
self.logger.error(f"Failed to defalte! {e} -> {gz_string}")
|
||||
return "stat=0"
|
||||
|
||||
req_kvp = urllib.parse.unquote(url_data)
|
||||
req_data = {}
|
||||
|
||||
# We then need to split each parts with & so we can reuse them to fill out the requests
|
||||
splitted_request = str.split(req_kvp, "&")
|
||||
for kvp in splitted_request:
|
||||
split = kvp.split("=")
|
||||
req_data[split[0]] = split[1]
|
||||
|
||||
self.logger.info(f"{req_data['cmd']} Request")
|
||||
self.logger.debug(req_data)
|
||||
|
||||
func_to_find = f"handle_{req_data['cmd']}_request"
|
||||
|
||||
# Load the requests
|
||||
try:
|
||||
handler = getattr(self.base, func_to_find)
|
||||
resp = handler(req_data)
|
||||
|
||||
except AttributeError as e:
|
||||
self.logger.warning(f"Unhandled {req_data['cmd']} request {e}")
|
||||
return f"cmd={req_data['cmd']}&req_id={req_data['req_id']}&stat=ok".encode('utf-8')
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error handling method {func_to_find} {e}")
|
||||
return f"cmd={req_data['cmd']}&req_id={req_data['req_id']}&stat=ok".encode('utf-8')
|
||||
|
||||
req.responseHeaders.addRawHeader(b"content-type", b"text/plain")
|
||||
self.logger.debug(f"Response cmd={req_data['cmd']}&req_id={req_data['req_id']}&stat=ok{resp}")
|
||||
|
||||
return f"cmd={req_data['cmd']}&req_id={req_data['req_id']}&stat=ok{resp}".encode('utf-8')
|
||||
@@ -0,0 +1,203 @@
|
||||
from typing import Optional, Dict, List
|
||||
from os import walk, path
|
||||
import urllib
|
||||
|
||||
from read import BaseReader
|
||||
from core.config import CoreConfig
|
||||
from titles.diva.database import DivaData
|
||||
from titles.diva.const import DivaConstants
|
||||
|
||||
class DivaReader(BaseReader):
|
||||
def __init__(self, config: CoreConfig, version: int, bin_dir: Optional[str], opt_dir: Optional[str], extra: Optional[str]) -> None:
|
||||
super().__init__(config, version, bin_dir, opt_dir, extra)
|
||||
self.data = DivaData(config)
|
||||
|
||||
try:
|
||||
self.logger.info(f"Start importer for {DivaConstants.game_ver_to_string(version)}")
|
||||
except IndexError:
|
||||
self.logger.error(f"Invalid project diva version {version}")
|
||||
exit(1)
|
||||
|
||||
def read(self) -> None:
|
||||
pull_bin_ram = True
|
||||
pull_bin_rom = True
|
||||
pull_opt_rom = True
|
||||
|
||||
if not path.exists(f"{self.bin_dir}/ram"):
|
||||
self.logger.warn(f"Couldn't find ram folder in {self.bin_dir}, skipping")
|
||||
pull_bin_ram = False
|
||||
|
||||
if not path.exists(f"{self.bin_dir}/rom"):
|
||||
self.logger.warn(f"Couldn't find rom folder in {self.bin_dir}, skipping")
|
||||
pull_bin_rom = False
|
||||
|
||||
if self.opt_dir is not None:
|
||||
opt_dirs = self.get_data_directories(self.opt_dir)
|
||||
else:
|
||||
pull_opt_rom = False
|
||||
self.logger.warn("No option directory specified, skipping")
|
||||
|
||||
if pull_bin_ram:
|
||||
self.read_ram(f"{self.bin_dir}/ram")
|
||||
if pull_bin_rom:
|
||||
self.read_rom(f"{self.bin_dir}/rom")
|
||||
if pull_opt_rom:
|
||||
for dir in opt_dirs:
|
||||
self.read_rom(f"{dir}/rom")
|
||||
|
||||
def read_ram(self, ram_root_dir: str) -> None:
|
||||
self.logger.info(f"Read RAM from {ram_root_dir}")
|
||||
|
||||
if path.exists(f"{ram_root_dir}/databank"):
|
||||
for root, dirs, files in walk(f"{ram_root_dir}/databank"):
|
||||
for file in files:
|
||||
if file.startswith("ShopCatalog_") or file.startswith("CustomizeItemCatalog_") or \
|
||||
(file.startswith("QuestInfo") and not file.startswith("QuestInfoTm")):
|
||||
|
||||
with open(f"{root}/{file}", "r") as f:
|
||||
file_data: str = urllib.parse.unquote(urllib.parse.unquote(f.read()))
|
||||
if file_data == "***":
|
||||
self.logger.info(f"{file} is empty, skipping")
|
||||
continue
|
||||
|
||||
file_lines: List[str] = file_data.split("\n")
|
||||
|
||||
for line in file_lines:
|
||||
split = line.split(",")
|
||||
|
||||
if not split[0]:
|
||||
split.pop(0)
|
||||
|
||||
if file.startswith("ShopCatalog_"):
|
||||
for x in range(0, len(split), 7):
|
||||
self.logger.info(f"Added shop item {split[x+0]}")
|
||||
|
||||
self.data.static.put_shop(self.version, split[x+0], split[x+2], split[x+6], split[x+3],
|
||||
split[x+1], split[x+4], split[x+5])
|
||||
|
||||
elif file.startswith("CustomizeItemCatalog_") and len(split) >= 7:
|
||||
for x in range(0, len(split), 7):
|
||||
self.logger.info(f"Added item {split[x+0]}")
|
||||
|
||||
self.data.static.put_items(self.version, split[x+0], split[x+2], split[x+6], split[x+3],
|
||||
split[x+1], split[x+4], split[x+5])
|
||||
|
||||
elif file.startswith("QuestInfo") and len(split) >= 9:
|
||||
self.logger.info(f"Added quest {split[0]}")
|
||||
|
||||
self.data.static.put_quests(self.version, split[0], split[6], split[2], split[3],
|
||||
split[7], split[8], split[1], split[4], split[5])
|
||||
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
self.logger.warn(f"Databank folder not found in {ram_root_dir}, skipping")
|
||||
|
||||
def read_rom(self, rom_root_dir: str) -> None:
|
||||
self.logger.info(f"Read ROM from {rom_root_dir}")
|
||||
pv_list: Dict[str, Dict] = {}
|
||||
|
||||
if path.exists(f"{rom_root_dir}/mdata_pv_db.txt"):
|
||||
file_path = f"{rom_root_dir}/mdata_pv_db.txt"
|
||||
elif path.exists(f"{rom_root_dir}/pv_db.txt"):
|
||||
file_path = f"{rom_root_dir}/pv_db.txt"
|
||||
else:
|
||||
self.logger.warn(f"Cannot find pv_db.txt or mdata_pv_db.txt in {rom_root_dir}, skipping")
|
||||
return
|
||||
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
|
||||
for line in f.readlines():
|
||||
|
||||
if line.startswith("#") or not line:
|
||||
continue
|
||||
|
||||
line_split = line.split("=")
|
||||
if len(line_split) != 2:
|
||||
continue
|
||||
|
||||
key = line_split[0]
|
||||
val = line_split[1]
|
||||
if val.endswith("\n"):
|
||||
val = val[:-1]
|
||||
|
||||
key_split = key.split(".")
|
||||
pv_id = key_split[0]
|
||||
key_args = []
|
||||
|
||||
for x in range(1, len(key_split)):
|
||||
key_args.append(key_split[x])
|
||||
|
||||
try:
|
||||
pv_list[pv_id] = self.add_branch(pv_list[pv_id], key_args, val)
|
||||
except KeyError:
|
||||
pv_list[pv_id] = {}
|
||||
pv_list[pv_id] = self.add_branch(pv_list[pv_id], key_args, val)
|
||||
|
||||
|
||||
for pv_id, pv_data in pv_list.items():
|
||||
song_id = int(pv_id.split("_")[1])
|
||||
if "songinfo" not in pv_data:
|
||||
continue
|
||||
if "illustrator" not in pv_data["songinfo"]:
|
||||
pv_data["songinfo"]["illustrator"] = "-"
|
||||
if "arranger" not in pv_data["songinfo"]:
|
||||
pv_data["songinfo"]["arranger"] = "-"
|
||||
if "lyrics" not in pv_data["songinfo"]:
|
||||
pv_data["songinfo"]["lyrics"] = "-"
|
||||
if "music" not in pv_data["songinfo"]:
|
||||
pv_data["songinfo"]["music"] = "-"
|
||||
|
||||
if "easy" in pv_data['difficulty'] and '0' in pv_data['difficulty']['easy']:
|
||||
diff = pv_data['difficulty']['easy']['0']['level'].split('_')
|
||||
self.logger.info(f"Added song {song_id} chart 0")
|
||||
|
||||
self.data.static.put_music(self.version, song_id, 0, pv_data["song_name"], pv_data["songinfo"]["arranger"],
|
||||
pv_data["songinfo"]["illustrator"], pv_data["songinfo"]["lyrics"], pv_data["songinfo"]["music"],
|
||||
float(f"{diff[2]}.{diff[3]}"), pv_data["bpm"], pv_data["date"])
|
||||
|
||||
if "normal" in pv_data['difficulty'] and '0' in pv_data['difficulty']['normal']:
|
||||
diff = pv_data['difficulty']['normal']['0']['level'].split('_')
|
||||
self.logger.info(f"Added song {song_id} chart 1")
|
||||
|
||||
self.data.static.put_music(self.version, song_id, 1, pv_data["song_name"], pv_data["songinfo"]["arranger"],
|
||||
pv_data["songinfo"]["illustrator"], pv_data["songinfo"]["lyrics"], pv_data["songinfo"]["music"],
|
||||
float(f"{diff[2]}.{diff[3]}"), pv_data["bpm"], pv_data["date"])
|
||||
|
||||
if "hard" in pv_data['difficulty'] and '0' in pv_data['difficulty']['hard']:
|
||||
diff = pv_data['difficulty']['hard']['0']['level'].split('_')
|
||||
self.logger.info(f"Added song {song_id} chart 2")
|
||||
|
||||
self.data.static.put_music(self.version, song_id, 2, pv_data["song_name"], pv_data["songinfo"]["arranger"],
|
||||
pv_data["songinfo"]["illustrator"], pv_data["songinfo"]["lyrics"], pv_data["songinfo"]["music"],
|
||||
float(f"{diff[2]}.{diff[3]}"), pv_data["bpm"], pv_data["date"])
|
||||
|
||||
if "extreme" in pv_data['difficulty']:
|
||||
if "0" in pv_data['difficulty']['extreme']:
|
||||
diff = pv_data['difficulty']['extreme']['0']['level'].split('_')
|
||||
self.logger.info(f"Added song {song_id} chart 3")
|
||||
|
||||
self.data.static.put_music(self.version, song_id, 3, pv_data["song_name"], pv_data["songinfo"]["arranger"],
|
||||
pv_data["songinfo"]["illustrator"], pv_data["songinfo"]["lyrics"], pv_data["songinfo"]["music"],
|
||||
float(f"{diff[2]}.{diff[3]}"), pv_data["bpm"], pv_data["date"])
|
||||
|
||||
if "1" in pv_data['difficulty']['extreme']:
|
||||
diff = pv_data['difficulty']['extreme']['1']['level'].split('_')
|
||||
self.logger.info(f"Added song {song_id} chart 4")
|
||||
|
||||
self.data.static.put_music(self.version, song_id, 4, pv_data["song_name"], pv_data["songinfo"]["arranger"],
|
||||
pv_data["songinfo"]["illustrator"], pv_data["songinfo"]["lyrics"], pv_data["songinfo"]["music"],
|
||||
float(f"{diff[2]}.{diff[3]}"), pv_data["bpm"], pv_data["date"])
|
||||
|
||||
def add_branch(self, tree: Dict, vector: List, value: str):
|
||||
"""
|
||||
Recursivly adds nodes to a dictionary
|
||||
Author: iJames on StackOverflow
|
||||
"""
|
||||
key = vector[0]
|
||||
tree[key] = value \
|
||||
if len(vector) == 1 \
|
||||
else self.add_branch(tree[key] if key in tree else {},
|
||||
vector[1:],
|
||||
value)
|
||||
return tree
|
||||
@@ -0,0 +1,6 @@
|
||||
from titles.diva.schema.profile import DivaProfileData
|
||||
from titles.diva.schema.score import DivaScoreData
|
||||
from titles.diva.schema.item import DivaItemData
|
||||
from titles.diva.schema.static import DivaStaticData
|
||||
|
||||
__all__ = [DivaProfileData, DivaScoreData, DivaItemData, DivaStaticData]
|
||||
@@ -0,0 +1,50 @@
|
||||
from typing import Optional, Dict, List
|
||||
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_, case
|
||||
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean
|
||||
from sqlalchemy.schema import ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
|
||||
from core.data.schema import BaseData, metadata
|
||||
|
||||
shop = Table(
|
||||
"diva_profile_shop",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||||
Column("version", Integer, nullable=False),
|
||||
Column("mdl_eqp_ary", String(32)),
|
||||
UniqueConstraint("user", "version", name="diva_profile_shop_uk"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
class DivaItemData(BaseData):
|
||||
def put_shop(self, aime_id: int, version: int, mdl_eqp_ary: str) -> None:
|
||||
sql = insert(shop).values(
|
||||
version=version,
|
||||
user=aime_id,
|
||||
mdl_eqp_ary=mdl_eqp_ary
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(
|
||||
mdl_eqp_ary = sql.inserted.mdl_eqp_ary
|
||||
)
|
||||
|
||||
result = self.execute(conflict)
|
||||
if result is None:
|
||||
self.logger.error(f"{__name__} Failed to insert diva profile! aime id: {aime_id} array: {mdl_eqp_ary}")
|
||||
return None
|
||||
return result.lastrowid
|
||||
|
||||
def get_shop(self, aime_id: int, version: int) -> Optional[List[Dict]]:
|
||||
"""
|
||||
Given a game version and either a profile or aime id, return the profile
|
||||
"""
|
||||
sql = shop.select(and_(
|
||||
shop.c.version == version,
|
||||
shop.c.user == aime_id
|
||||
))
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchone()
|
||||
@@ -0,0 +1,113 @@
|
||||
from typing import Optional, Dict, List
|
||||
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
|
||||
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON
|
||||
from sqlalchemy.schema import ForeignKey
|
||||
from sqlalchemy.sql import func, select
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
|
||||
from core.data.schema import BaseData, metadata
|
||||
|
||||
profile = Table(
|
||||
"diva_profile",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
||||
Column("version", Integer, nullable=False),
|
||||
Column("player_name", String(8), nullable=False),
|
||||
Column("lv_str", String(24), nullable=False, server_default="Dab on 'em"),
|
||||
Column("lv_num", Integer, nullable=False, server_default="0"),
|
||||
Column("lv_pnt", Integer, nullable=False, server_default="0"),
|
||||
Column("vcld_pts", Integer, nullable=False, server_default="0"),
|
||||
Column("hp_vol", Integer, nullable=False, server_default="100"),
|
||||
Column("btn_se_vol", Integer, nullable=False, server_default="100"),
|
||||
Column("btn_se_vol2", Integer, nullable=False, server_default="100"),
|
||||
Column("sldr_se_vol2", Integer, nullable=False, server_default="100"),
|
||||
Column("sort_kind", Integer, nullable=False, server_default="2"),
|
||||
Column("use_pv_mdl_eqp", String(8), nullable=False, server_default="true"),
|
||||
Column("use_pv_btn_se_eqp", String(8), nullable=False, server_default="true"),
|
||||
Column("use_pv_sld_se_eqp", String(8), nullable=False, server_default="false"),
|
||||
Column("use_pv_chn_sld_se_eqp", String(8), nullable=False, server_default="false"),
|
||||
Column("use_pv_sldr_tch_se_eqp", String(8), nullable=False, server_default="false"),
|
||||
Column("nxt_pv_id", Integer, nullable=False, server_default="708"),
|
||||
Column("nxt_dffclty", Integer, nullable=False, server_default="2"),
|
||||
Column("nxt_edtn", Integer, nullable=False, server_default="0"),
|
||||
Column("dsp_clr_brdr", Integer, nullable=False, server_default="7"),
|
||||
Column("dsp_intrm_rnk", Integer, nullable=False, server_default="1"),
|
||||
Column("dsp_clr_sts", Integer, nullable=False, server_default="1"),
|
||||
Column("rgo_sts", Integer, nullable=False, server_default="1"),
|
||||
Column("lv_efct_id", Integer, nullable=False, server_default="0"),
|
||||
Column("lv_plt_id", Integer, nullable=False, server_default="1"),
|
||||
Column("my_qst_id", String(128), server_default="-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"),
|
||||
Column("my_qst_sts", String(128), server_default="-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"),
|
||||
UniqueConstraint("user", "version", name="diva_profile_uk"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
class DivaProfileData(BaseData):
|
||||
def create_profile(self, version: int, aime_id: int, player_name: str) -> Optional[int]:
|
||||
"""
|
||||
Given a game version, aime id, and player_name, create a profile and return it's ID
|
||||
"""
|
||||
sql = insert(profile).values(
|
||||
version=version,
|
||||
user=aime_id,
|
||||
player_name=player_name
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(
|
||||
player_name = sql.inserted.player_name
|
||||
)
|
||||
|
||||
result = self.execute(conflict)
|
||||
if result is None:
|
||||
self.logger.error(f"{__name__} Failed to insert diva profile! aime id: {aime_id} username: {player_name}")
|
||||
return None
|
||||
return result.lastrowid
|
||||
|
||||
def update_profile(self, profile_id: int, lv_num: int, lv_pnt: int, vcld_pts: int, hp_vol: int, btn_se_vol: int, btn_se_vol2: int, sldr_se_vol2: int, sort_kind: int, use_pv_mdl_eqp: str, use_pv_btn_se_eqp: str, use_pv_sld_se_eqp: str, use_pv_chn_sld_se_eqp: str, use_pv_sldr_tch_se_eqp: str, nxt_pv_id: int, nxt_dffclty: int, nxt_edtn: int, dsp_clr_brdr: int, dsp_intrm_rnk: int, dsp_clr_sts: int, rgo_sts: int, lv_efct_id: int, lv_plt_id: int, my_qst_id: str, my_qst_sts: str) -> None:
|
||||
sql = profile.update(profile.c.user == profile_id).values(
|
||||
|
||||
lv_num = lv_num,
|
||||
lv_pnt = lv_pnt,
|
||||
vcld_pts = vcld_pts,
|
||||
hp_vol = hp_vol,
|
||||
btn_se_vol = btn_se_vol,
|
||||
btn_se_vol2 = btn_se_vol2,
|
||||
sldr_se_vol2 = sldr_se_vol2,
|
||||
sort_kind = sort_kind,
|
||||
use_pv_mdl_eqp = use_pv_mdl_eqp,
|
||||
use_pv_btn_se_eqp = use_pv_btn_se_eqp,
|
||||
use_pv_sld_se_eqp = use_pv_sld_se_eqp,
|
||||
use_pv_chn_sld_se_eqp = use_pv_chn_sld_se_eqp,
|
||||
use_pv_sldr_tch_se_eqp = use_pv_sldr_tch_se_eqp,
|
||||
nxt_pv_id = nxt_pv_id,
|
||||
nxt_dffclty = nxt_dffclty,
|
||||
nxt_edtn = nxt_edtn,
|
||||
dsp_clr_brdr = dsp_clr_brdr,
|
||||
dsp_intrm_rnk = dsp_intrm_rnk,
|
||||
dsp_clr_sts = dsp_clr_sts,
|
||||
rgo_sts = rgo_sts,
|
||||
lv_efct_id = lv_efct_id,
|
||||
lv_plt_id = lv_plt_id,
|
||||
my_qst_id = my_qst_id,
|
||||
my_qst_sts = my_qst_sts
|
||||
|
||||
)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"update_profile: failed to update profile! profile: {profile_id}")
|
||||
return None
|
||||
|
||||
def get_profile(self, aime_id: int, version: int) -> Optional[List[Dict]]:
|
||||
"""
|
||||
Given a game version and either a profile or aime id, return the profile
|
||||
"""
|
||||
sql = profile.select(and_(
|
||||
profile.c.version == version,
|
||||
profile.c.user == aime_id
|
||||
))
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchone()
|
||||
@@ -0,0 +1,141 @@
|
||||
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
|
||||
from sqlalchemy.types import Integer, String, TIMESTAMP, JSON, Boolean
|
||||
from sqlalchemy.schema import ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
from typing import Optional, List, Dict, Any
|
||||
|
||||
from core.data.schema import BaseData, metadata
|
||||
from core.data import cached
|
||||
|
||||
score = Table(
|
||||
"diva_score",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("user", ForeignKey("aime_user.id", ondelete="cascade"), nullable=False),
|
||||
Column("version", Integer),
|
||||
Column("pv_id", Integer),
|
||||
Column("difficulty", Integer),
|
||||
Column("score", Integer),
|
||||
Column("atn_pnt", Integer),
|
||||
Column("clr_kind", Integer),
|
||||
Column("sort_kind", Integer),
|
||||
Column("cool", Integer),
|
||||
Column("fine", Integer),
|
||||
Column("safe", Integer),
|
||||
Column("sad", Integer),
|
||||
Column("worst", Integer),
|
||||
Column("max_combo", Integer),
|
||||
UniqueConstraint("user", "pv_id", "difficulty", name="diva_score_uk"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
playlog = Table(
|
||||
"diva_playlog",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("user", ForeignKey("aime_user.id", ondelete="cascade"), nullable=False),
|
||||
Column("version", Integer),
|
||||
Column("pv_id", Integer),
|
||||
Column("difficulty", Integer),
|
||||
Column("score", Integer),
|
||||
Column("atn_pnt", Integer),
|
||||
Column("clr_kind", Integer),
|
||||
Column("sort_kind", Integer),
|
||||
Column("cool", Integer),
|
||||
Column("fine", Integer),
|
||||
Column("safe", Integer),
|
||||
Column("sad", Integer),
|
||||
Column("worst", Integer),
|
||||
Column("max_combo", Integer),
|
||||
Column("date_scored", TIMESTAMP, server_default=func.now()),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
class DivaScoreData(BaseData):
|
||||
def put_best_score(self, user_id: int, game_version: int, song_id: int, difficulty: int, song_score: int, atn_pnt: int,
|
||||
clr_kind: int, sort_kind:int, cool: int, fine: int, safe: int, sad: int, worst: int, max_combo: int) -> Optional[int]:
|
||||
"""
|
||||
Update the user's best score for a chart
|
||||
"""
|
||||
sql = insert(score).values(
|
||||
user=user_id,
|
||||
version=game_version,
|
||||
pv_id = song_id,
|
||||
difficulty=difficulty,
|
||||
score=song_score,
|
||||
atn_pnt = atn_pnt,
|
||||
clr_kind = clr_kind,
|
||||
sort_kind = sort_kind,
|
||||
cool = cool,
|
||||
fine = fine,
|
||||
safe = safe,
|
||||
sad = sad,
|
||||
worst = worst,
|
||||
max_combo = max_combo,
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(
|
||||
score=song_score,
|
||||
atn_pnt = atn_pnt,
|
||||
clr_kind = clr_kind,
|
||||
sort_kind = sort_kind,
|
||||
cool = cool,
|
||||
fine = fine,
|
||||
safe = safe,
|
||||
sad = sad,
|
||||
worst = worst,
|
||||
max_combo = max_combo,
|
||||
)
|
||||
|
||||
result = self.execute(conflict)
|
||||
if result is None:
|
||||
self.logger.error(f"{__name__} failed to insert best score! profile: {user_id}, song: {song_id}")
|
||||
return None
|
||||
|
||||
return result.lastrowid
|
||||
|
||||
def put_playlog(self, user_id: int, game_version: int, song_id: int, difficulty: int, song_score: int, atn_pnt: int,
|
||||
clr_kind: int, sort_kind:int, cool: int, fine: int, safe: int, sad: int, worst: int, max_combo: int) -> Optional[int]:
|
||||
"""
|
||||
Add an entry to the user's play log
|
||||
"""
|
||||
sql = playlog.insert().values(
|
||||
user=user_id,
|
||||
version=game_version,
|
||||
pv_id = song_id,
|
||||
difficulty=difficulty,
|
||||
score=song_score,
|
||||
atn_pnt = atn_pnt,
|
||||
clr_kind = clr_kind,
|
||||
sort_kind = sort_kind,
|
||||
cool = cool,
|
||||
fine = fine,
|
||||
safe = safe,
|
||||
sad = sad,
|
||||
worst = worst,
|
||||
max_combo = max_combo
|
||||
)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"{__name__} failed to insert playlog! profile: {user_id}, song: {song_id}, chart: {difficulty}")
|
||||
return None
|
||||
|
||||
return result.lastrowid
|
||||
|
||||
def get_best_score(self, user_id: int, pv_id: int, chart_id: int) -> Optional[Dict]:
|
||||
sql = score.select(
|
||||
and_(score.c.user == user_id, score.c.pv_id == pv_id, score.c.difficulty == chart_id)
|
||||
)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchone()
|
||||
|
||||
def get_best_scores(self, user_id: int) -> Optional[Dict]:
|
||||
sql = score.select(score.c.user == user_id)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchall()
|
||||
@@ -0,0 +1,222 @@
|
||||
from typing import Dict, List, Optional
|
||||
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
|
||||
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON, Float
|
||||
from sqlalchemy.engine.base import Connection
|
||||
from sqlalchemy.engine import Row
|
||||
from sqlalchemy.schema import ForeignKey
|
||||
from sqlalchemy.sql import func, select
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
|
||||
from core.data.schema import BaseData, metadata
|
||||
|
||||
music = Table(
|
||||
"diva_static_music",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("version", Integer, nullable=False),
|
||||
Column("songId", Integer),
|
||||
Column("chartId", Integer),
|
||||
Column("title", String(255)),
|
||||
Column("vocaloid_arranger", String(255)),
|
||||
Column("pv_illustrator", String(255)),
|
||||
Column("lyrics", String(255)),
|
||||
Column("bg_music", String(255)),
|
||||
Column("level", Float),
|
||||
Column("bpm", Integer),
|
||||
Column("date", String(255)),
|
||||
UniqueConstraint("version", "songId", "chartId", name="diva_static_music_uk"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
quests = Table(
|
||||
"diva_static_quests",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("version", Integer, nullable=False),
|
||||
Column("questId", Integer),
|
||||
Column("name", String(255)),
|
||||
Column("quest_enable", Boolean, server_default="1"),
|
||||
Column("kind", Integer),
|
||||
Column("unknown_0", Integer),
|
||||
Column("unknown_1", Integer),
|
||||
Column("unknown_2", Integer),
|
||||
Column("quest_order", Integer),
|
||||
Column("start_datetime", String(255)),
|
||||
Column("end_datetime", String(255)),
|
||||
|
||||
UniqueConstraint("version", "questId", name="diva_static_quests_uk"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
shop = Table(
|
||||
"diva_static_shop",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("version", Integer, nullable=False),
|
||||
Column("shopId", Integer),
|
||||
Column("name", String(255)),
|
||||
Column("type", Integer),
|
||||
Column("points", Integer),
|
||||
Column("unknown_0", Integer),
|
||||
Column("start_date", String(255)),
|
||||
Column("end_date", String(255)),
|
||||
Column("enabled", Boolean, server_default="1"),
|
||||
UniqueConstraint("version", "shopId", name="diva_static_shop_uk"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
items = Table(
|
||||
"diva_static_items",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column("version", Integer, nullable=False),
|
||||
Column("itemId", Integer),
|
||||
Column("name", String(255)),
|
||||
Column("type", Integer),
|
||||
Column("points", Integer),
|
||||
Column("unknown_0", Integer),
|
||||
Column("start_date", String(255)),
|
||||
Column("end_date", String(255)),
|
||||
Column("enabled", Boolean, server_default="1"),
|
||||
UniqueConstraint("version", "itemId", name="diva_static_items_uk"),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
|
||||
class DivaStaticData(BaseData):
|
||||
def put_quests(self, version: int, questId: int, name: str, kind: int, unknown_0: int, unknown_1: int, unknown_2: int, quest_order: int, start_datetime: str, end_datetime: str) -> Optional[int]:
|
||||
sql = insert(quests).values(
|
||||
version = version,
|
||||
questId = questId,
|
||||
name = name,
|
||||
kind = kind,
|
||||
unknown_0 = unknown_0,
|
||||
unknown_1 = unknown_1,
|
||||
unknown_2 = unknown_2,
|
||||
quest_order = quest_order,
|
||||
start_datetime = start_datetime,
|
||||
end_datetime = end_datetime
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(
|
||||
name = name
|
||||
)
|
||||
|
||||
result = self.execute(conflict)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def get_enabled_quests(self, version: int) -> Optional[List[Row]]:
|
||||
sql = select(quests).where(and_(quests.c.version == version, quests.c.quest_enable == True))
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchall()
|
||||
|
||||
def put_shop(self, version: int, shopId: int, name: str, type: int, points: int, unknown_0: int, start_date: str, end_date: str) -> Optional[int]:
|
||||
sql = insert(shop).values(
|
||||
version = version,
|
||||
shopId = shopId,
|
||||
name = name,
|
||||
type = type,
|
||||
points = points,
|
||||
unknown_0 = unknown_0,
|
||||
start_date = start_date,
|
||||
end_date = end_date
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(
|
||||
name = name
|
||||
)
|
||||
|
||||
result = self.execute(conflict)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def get_enabled_shop(self, version: int) -> Optional[List[Row]]:
|
||||
sql = select(shop).where(and_(shop.c.version == version, shop.c.enabled == True))
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchall()
|
||||
|
||||
def put_items(self, version: int, itemId: int, name: str, type: int, points: int, unknown_0: int, start_date: str, end_date: str) -> Optional[int]:
|
||||
sql = insert(items).values(
|
||||
version = version,
|
||||
itemId = itemId,
|
||||
name = name,
|
||||
type = type,
|
||||
points = points,
|
||||
unknown_0 = unknown_0,
|
||||
start_date = start_date,
|
||||
end_date = end_date
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(
|
||||
name = name
|
||||
)
|
||||
|
||||
result = self.execute(conflict)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def get_enabled_items(self, version: int) -> Optional[List[Row]]:
|
||||
sql = select(items).where(and_(items.c.version == version, items.c.enabled == True))
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchall()
|
||||
|
||||
def put_music(self, version: int, song: int, chart: int, title: str, arranger: str, illustrator: str,
|
||||
lyrics: str, music_comp: str, level: float, bpm: int, date: str) -> Optional[int]:
|
||||
sql = insert(music).values(
|
||||
version = version,
|
||||
songId = song,
|
||||
chartId = chart,
|
||||
title = title,
|
||||
vocaloid_arranger = arranger,
|
||||
pv_illustrator = illustrator,
|
||||
lyrics = lyrics,
|
||||
bg_music = music_comp,
|
||||
level = level,
|
||||
bpm = bpm,
|
||||
date = date
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(
|
||||
title = title,
|
||||
vocaloid_arranger = arranger,
|
||||
pv_illustrator = illustrator,
|
||||
lyrics = lyrics,
|
||||
bg_music = music_comp,
|
||||
level = level,
|
||||
bpm = bpm,
|
||||
date = date
|
||||
)
|
||||
|
||||
result = self.execute(conflict)
|
||||
if result is None: return None
|
||||
return result.lastrowid
|
||||
|
||||
def get_music(self, version: int, song_id: Optional[int] = None) -> Optional[List[Row]]:
|
||||
if song_id is None:
|
||||
sql = select(music).where(music.c.version == version)
|
||||
else:
|
||||
sql = select(music).where(and_(
|
||||
music.c.version == version,
|
||||
music.c.songId == song_id,
|
||||
))
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchall()
|
||||
|
||||
def get_music_chart(self, version: int, song_id: int, chart_id: int) -> Optional[List[Row]]:
|
||||
sql = select(music).where(and_(
|
||||
music.c.version == version,
|
||||
music.c.songId == song_id,
|
||||
music.c.chartId == chart_id
|
||||
))
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None: return None
|
||||
return result.fetchone()
|
||||
Reference in New Issue
Block a user