let black do it's magic

This commit is contained in:
Hay1tsme
2023-03-09 11:38:58 -05:00
parent fa7206848c
commit a76bb94eb1
150 changed files with 8474 additions and 4843 deletions

View File

@@ -7,4 +7,4 @@ index = Mai2Servlet
database = Mai2Data
reader = Mai2Reader
game_codes = [Mai2Constants.GAME_CODE]
current_schema_version = 2
current_schema_version = 2

View File

@@ -7,7 +7,8 @@ from titles.mai2.const import Mai2Constants
from titles.mai2.config import Mai2Config
from titles.mai2.database import Mai2Data
class Mai2Base():
class Mai2Base:
def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None:
self.core_config = cfg
self.game_config = game_cfg
@@ -17,23 +18,27 @@ class Mai2Base():
self.logger = logging.getLogger("mai2")
def handle_get_game_setting_api_request(self, data: Dict):
reboot_start = date.strftime(datetime.now() + timedelta(hours=3), Mai2Constants.DATE_TIME_FORMAT)
reboot_end = date.strftime(datetime.now() + timedelta(hours=4), Mai2Constants.DATE_TIME_FORMAT)
reboot_start = date.strftime(
datetime.now() + timedelta(hours=3), Mai2Constants.DATE_TIME_FORMAT
)
reboot_end = date.strftime(
datetime.now() + timedelta(hours=4), Mai2Constants.DATE_TIME_FORMAT
)
return {
"gameSetting": {
"isMaintenance": "false",
"requestInterval": 10,
"rebootStartTime": reboot_start,
"rebootEndTime": reboot_end,
"movieUploadLimit": 10000,
"movieStatus": 0,
"movieServerUri": "",
"deliverServerUri": "",
"oldServerUri": "",
"usbDlServerUri": "",
"rebootInterval": 0
"gameSetting": {
"isMaintenance": "false",
"requestInterval": 10,
"rebootStartTime": reboot_start,
"rebootEndTime": reboot_end,
"movieUploadLimit": 10000,
"movieStatus": 0,
"movieServerUri": "",
"deliverServerUri": "",
"oldServerUri": "",
"usbDlServerUri": "",
"rebootInterval": 0,
},
"isAouAccession": "true",
"isAouAccession": "true",
}
def handle_get_game_ranking_api_request(self, data: Dict) -> Dict:
@@ -46,34 +51,44 @@ class Mai2Base():
def handle_get_game_event_api_request(self, data: Dict) -> Dict:
events = self.data.static.get_enabled_events(self.version)
events_lst = []
if events is None: return {"type": data["type"], "length": 0, "gameEventList": []}
if events is None:
return {"type": data["type"], "length": 0, "gameEventList": []}
for event in events:
events_lst.append({
"type": event["type"],
"id": event["eventId"],
"startDate": "2017-12-05 07:00:00.0",
"endDate": "2099-12-31 00:00:00.0"
})
events_lst.append(
{
"type": event["type"],
"id": event["eventId"],
"startDate": "2017-12-05 07:00:00.0",
"endDate": "2099-12-31 00:00:00.0",
}
)
return {"type": data["type"], "length": len(events_lst), "gameEventList": events_lst}
return {
"type": data["type"],
"length": len(events_lst),
"gameEventList": events_lst,
}
def handle_get_game_ng_music_id_api_request(self, data: Dict) -> Dict:
return {"length": 0, "musicIdList": []}
def handle_get_game_charge_api_request(self, data: Dict) -> Dict:
game_charge_list = self.data.static.get_enabled_tickets(self.version, 1)
if game_charge_list is None: return {"length": 0, "gameChargeList": []}
if game_charge_list is None:
return {"length": 0, "gameChargeList": []}
charge_list = []
for x in range(len(game_charge_list)):
charge_list.append({
"orderId": x,
"chargeId": game_charge_list[x]["ticketId"],
"price": game_charge_list[x]["price"],
"startDate": "2017-12-05 07:00:00.0",
"endDate": "2099-12-31 00:00:00.0"
})
charge_list.append(
{
"orderId": x,
"chargeId": game_charge_list[x]["ticketId"],
"price": game_charge_list[x]["price"],
"startDate": "2017-12-05 07:00:00.0",
"endDate": "2099-12-31 00:00:00.0",
}
)
return {"length": len(charge_list), "gameChargeList": charge_list}
@@ -92,7 +107,8 @@ class Mai2Base():
def handle_get_user_preview_api_request(self, data: Dict) -> Dict:
p = self.data.profile.get_profile_detail(data["userId"], self.version)
o = self.data.profile.get_profile_option(data["userId"], self.version)
if p is None or o is None: return {} # Register
if p is None or o is None:
return {} # Register
profile = p._asdict()
option = o._asdict()
@@ -106,20 +122,24 @@ class Mai2Base():
"lastLoginDate": profile["lastLoginDate"],
"lastPlayDate": profile["lastPlayDate"],
"playerRating": profile["playerRating"],
"nameplateId": 0, # Unused
"nameplateId": 0, # Unused
"iconId": profile["iconId"],
"trophyId": 0, # Unused
"trophyId": 0, # Unused
"partnerId": profile["partnerId"],
"frameId": profile["frameId"],
"dispRate": option["dispRate"], # 0: all/begin, 1: disprate, 2: dispDan, 3: hide, 4: end
"dispRate": option[
"dispRate"
], # 0: all/begin, 1: disprate, 2: dispDan, 3: hide, 4: end
"totalAwake": profile["totalAwake"],
"isNetMember": profile["isNetMember"],
"dailyBonusDate": profile["dailyBonusDate"],
"headPhoneVolume": option["headPhoneVolume"],
"isInherit": False, # Not sure what this is or does??
"banState": profile["banState"] if profile["banState"] is not None else 0 # New with uni+
"isInherit": False, # Not sure what this is or does??
"banState": profile["banState"]
if profile["banState"] is not None
else 0, # New with uni+
}
def handle_user_login_api_request(self, data: Dict) -> Dict:
profile = self.data.profile.get_profile_detail(data["userId"], self.version)
@@ -137,10 +157,10 @@ class Mai2Base():
"returnCode": 1,
"lastLoginDate": lastLoginDate,
"loginCount": loginCt,
"consecutiveLoginCount": 0, # We don't really have a way to track this...
"loginId": loginCt # Used with the playlog!
"consecutiveLoginCount": 0, # We don't really have a way to track this...
"loginId": loginCt, # Used with the playlog!
}
def handle_upload_user_playlog_api_request(self, data: Dict) -> Dict:
user_id = data["userId"]
playlog = data["userPlaylog"]
@@ -154,50 +174,83 @@ class Mai2Base():
if "userData" in upsert and len(upsert["userData"]) > 0:
upsert["userData"][0]["isNetMember"] = 1
upsert["userData"][0].pop("accessCode")
self.data.profile.put_profile_detail(user_id, self.version, upsert["userData"][0])
self.data.profile.put_profile_detail(
user_id, self.version, upsert["userData"][0]
)
if "userExtend" in upsert and len(upsert["userExtend"]) > 0:
self.data.profile.put_profile_extend(user_id, self.version, upsert["userExtend"][0])
self.data.profile.put_profile_extend(
user_id, self.version, upsert["userExtend"][0]
)
if "userGhost" in upsert:
for ghost in upsert["userGhost"]:
self.data.profile.put_profile_extend(user_id, self.version, ghost)
if "userOption" in upsert and len(upsert["userOption"]) > 0:
self.data.profile.put_profile_option(user_id, self.version, upsert["userOption"][0])
self.data.profile.put_profile_option(
user_id, self.version, upsert["userOption"][0]
)
if "userRatingList" in upsert and len(upsert["userRatingList"]) > 0:
self.data.profile.put_profile_rating(user_id, self.version, upsert["userRatingList"][0])
self.data.profile.put_profile_rating(
user_id, self.version, upsert["userRatingList"][0]
)
if "userActivityList" in upsert and len(upsert["userActivityList"]) > 0:
for k,v in upsert["userActivityList"][0].items():
for k, v in upsert["userActivityList"][0].items():
for act in v:
self.data.profile.put_profile_activity(user_id, act)
if upsert["isNewCharacterList"] and int(upsert["isNewCharacterList"]) > 0:
for char in upsert["userCharacterList"]:
self.data.item.put_character(user_id, char["characterId"], char["level"], char["awakening"], char["useCount"])
self.data.item.put_character(
user_id,
char["characterId"],
char["level"],
char["awakening"],
char["useCount"],
)
if upsert["isNewItemList"] and int(upsert["isNewItemList"]) > 0:
for item in upsert["userItemList"]:
self.data.item.put_item(user_id, int(item["itemKind"]), item["itemId"], item["stock"], item["isValid"])
self.data.item.put_item(
user_id,
int(item["itemKind"]),
item["itemId"],
item["stock"],
item["isValid"],
)
if upsert["isNewLoginBonusList"] and int(upsert["isNewLoginBonusList"]) > 0:
for login_bonus in upsert["userLoginBonusList"]:
self.data.item.put_login_bonus(user_id, login_bonus["bonusId"], login_bonus["point"], login_bonus["isCurrent"], login_bonus["isComplete"])
self.data.item.put_login_bonus(
user_id,
login_bonus["bonusId"],
login_bonus["point"],
login_bonus["isCurrent"],
login_bonus["isComplete"],
)
if upsert["isNewMapList"] and int(upsert["isNewMapList"]) > 0:
for map in upsert["userMapList"]:
self.data.item.put_map(user_id, map["mapId"], map["distance"], map["isLock"], map["isClear"], map["isComplete"])
self.data.item.put_map(
user_id,
map["mapId"],
map["distance"],
map["isLock"],
map["isClear"],
map["isComplete"],
)
if upsert["isNewMusicDetailList"] and int(upsert["isNewMusicDetailList"]) > 0:
for music in upsert["userMusicDetailList"]:
self.data.score.put_best_score(user_id, music)
if upsert["isNewCourseList"] and int(upsert["isNewCourseList"]) > 0:
for course in upsert["userCourseList"]:
self.data.score.put_course(user_id, course)
if upsert["isNewFavoriteList"] and int(upsert["isNewFavoriteList"]) > 0:
for fav in upsert["userFavoriteList"]:
self.data.item.put_favorite(user_id, fav["kind"], fav["itemIdList"])
@@ -211,45 +264,39 @@ class Mai2Base():
def handle_get_user_data_api_request(self, data: Dict) -> Dict:
profile = self.data.profile.get_profile_detail(data["userId"], self.version)
if profile is None: return
if profile is None:
return
profile_dict = profile._asdict()
profile_dict.pop("id")
profile_dict.pop("user")
profile_dict.pop("version")
return {
"userId": data["userId"],
"userData": profile_dict
}
return {"userId": data["userId"], "userData": profile_dict}
def handle_get_user_extend_api_request(self, data: Dict) -> Dict:
extend = self.data.profile.get_profile_extend(data["userId"], self.version)
if extend is None: return
if extend is None:
return
extend_dict = extend._asdict()
extend_dict.pop("id")
extend_dict.pop("user")
extend_dict.pop("version")
return {
"userId": data["userId"],
"userExtend": extend_dict
}
return {"userId": data["userId"], "userExtend": extend_dict}
def handle_get_user_option_api_request(self, data: Dict) -> Dict:
options = self.data.profile.get_profile_option(data["userId"], self.version)
if options is None: return
if options is None:
return
options_dict = options._asdict()
options_dict.pop("id")
options_dict.pop("user")
options_dict.pop("version")
return {
"userId": data["userId"],
"userOption": options_dict
}
return {"userId": data["userId"], "userOption": options_dict}
def handle_get_user_card_api_request(self, data: Dict) -> Dict:
return {"userId": data["userId"], "nextIndex": 0, "userCardList": []}
@@ -266,73 +313,83 @@ class Mai2Base():
for x in range(next_idx, data["maxCount"]):
try:
user_item_list.append({"item_kind": user_items[x]["item_kind"], "item_id": user_items[x]["item_id"],
"stock": user_items[x]["stock"], "isValid": user_items[x]["is_valid"]})
except: break
user_item_list.append(
{
"item_kind": user_items[x]["item_kind"],
"item_id": user_items[x]["item_id"],
"stock": user_items[x]["stock"],
"isValid": user_items[x]["is_valid"],
}
)
except:
break
if len(user_item_list) == data["maxCount"]:
next_idx = data["nextIndex"] + data["maxCount"] + 1
break
return {"userId": data["userId"], "nextIndex": next_idx, "itemKind": kind, "userItemList": user_item_list}
return {
"userId": data["userId"],
"nextIndex": next_idx,
"itemKind": kind,
"userItemList": user_item_list,
}
def handle_get_user_character_api_request(self, data: Dict) -> Dict:
characters = self.data.item.get_characters(data["userId"])
chara_list = []
for chara in characters:
chara_list.append({
"characterId": chara["character_id"],
"level": chara["level"],
"awakening": chara["awakening"],
"useCount": chara["use_count"],
})
chara_list.append(
{
"characterId": chara["character_id"],
"level": chara["level"],
"awakening": chara["awakening"],
"useCount": chara["use_count"],
}
)
return {"userId": data["userId"], "userCharacterList": chara_list}
def handle_get_user_favorite_api_request(self, data: Dict) -> Dict:
favorites = self.data.item.get_favorites(data["userId"], data["itemKind"])
if favorites is None: return
if favorites is None:
return
userFavs = []
for fav in favorites:
userFavs.append({
"userId": data["userId"],
"itemKind": fav["itemKind"],
"itemIdList": fav["itemIdList"]
})
userFavs.append(
{
"userId": data["userId"],
"itemKind": fav["itemKind"],
"itemIdList": fav["itemIdList"],
}
)
return {
"userId": data["userId"],
"userFavoriteData": userFavs
}
return {"userId": data["userId"], "userFavoriteData": userFavs}
def handle_get_user_ghost_api_request(self, data: Dict) -> Dict:
ghost = self.data.profile.get_profile_ghost(data["userId"], self.version)
if ghost is None: return
if ghost is None:
return
ghost_dict = ghost._asdict()
ghost_dict.pop("user")
ghost_dict.pop("id")
ghost_dict.pop("version_int")
return {
"userId": data["userId"],
"userGhost": ghost_dict
}
return {"userId": data["userId"], "userGhost": ghost_dict}
def handle_get_user_rating_api_request(self, data: Dict) -> Dict:
rating = self.data.profile.get_profile_rating(data["userId"], self.version)
if rating is None: return
if rating is None:
return
rating_dict = rating._asdict()
rating_dict.pop("user")
rating_dict.pop("id")
rating_dict.pop("version")
return {
"userId": data["userId"],
"userRating": rating_dict
}
return {"userId": data["userId"], "userRating": rating_dict}
def handle_get_user_activity_api_request(self, data: Dict) -> Dict:
"""
@@ -340,31 +397,27 @@ class Mai2Base():
"""
playlist = self.data.profile.get_profile_activity(data["userId"], 1)
musiclist = self.data.profile.get_profile_activity(data["userId"], 2)
if playlist is None or musiclist is None: return
if playlist is None or musiclist is None:
return
plst = []
mlst = []
for play in playlist:
tmp = play._asdict()
tmp = play._asdict()
tmp["id"] = tmp["activityId"]
tmp.pop("activityId")
tmp.pop("user")
plst.append(tmp)
for music in musiclist:
tmp = music._asdict()
tmp = music._asdict()
tmp["id"] = tmp["activityId"]
tmp.pop("activityId")
tmp.pop("user")
mlst.append(tmp)
return {
"userActivity": {
"playList": plst,
"musicList": mlst
}
}
return {"userActivity": {"playList": plst, "musicList": mlst}}
def handle_get_user_course_api_request(self, data: Dict) -> Dict:
user_courses = self.data.score.get_courses(data["userId"])
@@ -389,21 +442,30 @@ class Mai2Base():
for x in range(data["nextIndex"], data["maxCount"] + data["nextIndex"]):
try:
friend_season_ranking_list.append({
"mapId": friend_season_ranking_list[x]["map_id"],
"distance": friend_season_ranking_list[x]["distance"],
"isLock": friend_season_ranking_list[x]["is_lock"],
"isClear": friend_season_ranking_list[x]["is_clear"],
"isComplete": friend_season_ranking_list[x]["is_complete"],
})
friend_season_ranking_list.append(
{
"mapId": friend_season_ranking_list[x]["map_id"],
"distance": friend_season_ranking_list[x]["distance"],
"isLock": friend_season_ranking_list[x]["is_lock"],
"isClear": friend_season_ranking_list[x]["is_clear"],
"isComplete": friend_season_ranking_list[x]["is_complete"],
}
)
except:
break
# We're capped and still have some left to go
if len(friend_season_ranking_list) == data["maxCount"] and len(friend_season_ranking) > data["maxCount"] + data["nextIndex"]:
if (
len(friend_season_ranking_list) == data["maxCount"]
and len(friend_season_ranking) > data["maxCount"] + data["nextIndex"]
):
next_index = data["maxCount"] + data["nextIndex"]
return {"userId": data["userId"], "nextIndex": next_index, "userFriendSeasonRankingList": friend_season_ranking_list}
return {
"userId": data["userId"],
"nextIndex": next_index,
"userFriendSeasonRankingList": friend_season_ranking_list,
}
def handle_get_user_map_api_request(self, data: Dict) -> Dict:
maps = self.data.item.get_maps(data["userId"])
@@ -412,21 +474,30 @@ class Mai2Base():
for x in range(data["nextIndex"], data["maxCount"] + data["nextIndex"]):
try:
map_list.append({
"mapId": maps[x]["map_id"],
"distance": maps[x]["distance"],
"isLock": maps[x]["is_lock"],
"isClear": maps[x]["is_clear"],
"isComplete": maps[x]["is_complete"],
})
map_list.append(
{
"mapId": maps[x]["map_id"],
"distance": maps[x]["distance"],
"isLock": maps[x]["is_lock"],
"isClear": maps[x]["is_clear"],
"isComplete": maps[x]["is_complete"],
}
)
except:
break
# We're capped and still have some left to go
if len(map_list) == data["maxCount"] and len(maps) > data["maxCount"] + data["nextIndex"]:
if (
len(map_list) == data["maxCount"]
and len(maps) > data["maxCount"] + data["nextIndex"]
):
next_index = data["maxCount"] + data["nextIndex"]
return {"userId": data["userId"], "nextIndex": next_index, "userMapList": map_list}
return {
"userId": data["userId"],
"nextIndex": next_index,
"userMapList": map_list,
}
def handle_get_user_login_bonus_api_request(self, data: Dict) -> Dict:
login_bonuses = self.data.item.get_login_bonuses(data["userId"])
@@ -435,20 +506,29 @@ class Mai2Base():
for x in range(data["nextIndex"], data["maxCount"] + data["nextIndex"]):
try:
login_bonus_list.append({
"bonusId": login_bonuses[x]["bonus_id"],
"point": login_bonuses[x]["point"],
"isCurrent": login_bonuses[x]["is_current"],
"isComplete": login_bonuses[x]["is_complete"],
})
login_bonus_list.append(
{
"bonusId": login_bonuses[x]["bonus_id"],
"point": login_bonuses[x]["point"],
"isCurrent": login_bonuses[x]["is_current"],
"isComplete": login_bonuses[x]["is_complete"],
}
)
except:
break
# We're capped and still have some left to go
if len(login_bonus_list) == data["maxCount"] and len(login_bonuses) > data["maxCount"] + data["nextIndex"]:
if (
len(login_bonus_list) == data["maxCount"]
and len(login_bonuses) > data["maxCount"] + data["nextIndex"]
):
next_index = data["maxCount"] + data["nextIndex"]
return {"userId": data["userId"], "nextIndex": next_index, "userLoginBonusList": login_bonus_list}
return {
"userId": data["userId"],
"nextIndex": next_index,
"userLoginBonusList": login_bonus_list,
}
def handle_get_user_region_api_request(self, data: Dict) -> Dict:
return {"userId": data["userId"], "length": 0, "userRegionList": []}
@@ -460,18 +540,24 @@ class Mai2Base():
if songs is not None:
for song in songs:
music_detail_list.append({
"musicId": song["song_id"],
"level": song["chart_id"],
"playCount": song["play_count"],
"achievement": song["achievement"],
"comboStatus": song["combo_status"],
"syncStatus": song["sync_status"],
"deluxscoreMax": song["dx_score"],
"scoreRank": song["score_rank"],
})
music_detail_list.append(
{
"musicId": song["song_id"],
"level": song["chart_id"],
"playCount": song["play_count"],
"achievement": song["achievement"],
"comboStatus": song["combo_status"],
"syncStatus": song["sync_status"],
"deluxscoreMax": song["dx_score"],
"scoreRank": song["score_rank"],
}
)
if len(music_detail_list) == data["maxCount"]:
next_index = data["maxCount"] + data["nextIndex"]
break
return {"userId": data["userId"], "nextIndex": next_index, "userMusicList": [{"userMusicDetailList": music_detail_list}]}
return {
"userId": data["userId"],
"nextIndex": next_index,
"userMusicList": [{"userMusicDetailList": music_detail_list}],
}

View File

@@ -1,17 +1,25 @@
from core.config import CoreConfig
class Mai2ServerConfig():
class Mai2ServerConfig:
def __init__(self, parent: "Mai2Config") -> None:
self.__config = parent
@property
def enable(self) -> bool:
return CoreConfig.get_config_field(self.__config, 'mai2', 'server', 'enable', default=True)
return CoreConfig.get_config_field(
self.__config, "mai2", "server", "enable", default=True
)
@property
def loglevel(self) -> int:
return CoreConfig.str_to_loglevel(CoreConfig.get_config_field(self.__config, 'mai2', 'server', 'loglevel', default="info"))
return CoreConfig.str_to_loglevel(
CoreConfig.get_config_field(
self.__config, "mai2", "server", "loglevel", default="info"
)
)
class Mai2Config(dict):
def __init__(self) -> None:
self.server = Mai2ServerConfig(self)
self.server = Mai2ServerConfig(self)

View File

@@ -1,4 +1,4 @@
class Mai2Constants():
class Mai2Constants:
GRADE = {
"D": 0,
"C": 1,
@@ -13,22 +13,10 @@ class Mai2Constants():
"SS": 10,
"SS+": 11,
"SSS": 12,
"SSS+": 13
}
FC = {
"None": 0,
"FC": 1,
"FC+": 2,
"AP": 3,
"AP+": 4
}
SYNC = {
"None": 0,
"FS": 1,
"FS+": 2,
"FDX": 3,
"FDX+": 4
"SSS+": 13,
}
FC = {"None": 0, "FC": 1, "FC+": 2, "AP": 3, "AP+": 4}
SYNC = {"None": 0, "FS": 1, "FS+": 2, "FDX": 3, "FDX+": 4}
DATE_TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
@@ -43,9 +31,15 @@ class Mai2Constants():
VER_MAIMAI_DX_UNIVERSE = 4
VER_MAIMAI_DX_UNIVERSE_PLUS = 5
VERSION_STRING = ("maimai Delux", "maimai Delux PLUS", "maimai Delux Splash", "maimai Delux Splash PLUS", "maimai Delux Universe",
"maimai Delux Universe PLUS")
VERSION_STRING = (
"maimai Delux",
"maimai Delux PLUS",
"maimai Delux Splash",
"maimai Delux Splash PLUS",
"maimai Delux Universe",
"maimai Delux Universe PLUS",
)
@classmethod
def game_ver_to_string(cls, ver: int):
return cls.VERSION_STRING[ver]
return cls.VERSION_STRING[ver]

View File

@@ -1,6 +1,12 @@
from core.data import Data
from core.config import CoreConfig
from titles.mai2.schema import Mai2ItemData, Mai2ProfileData, Mai2StaticData, Mai2ScoreData
from titles.mai2.schema import (
Mai2ItemData,
Mai2ProfileData,
Mai2StaticData,
Mai2ScoreData,
)
class Mai2Data(Data):
def __init__(self, cfg: CoreConfig) -> None:
@@ -9,4 +15,4 @@ class Mai2Data(Data):
self.profile = Mai2ProfileData(self.config, self.session)
self.item = Mai2ItemData(self.config, self.session)
self.static = Mai2StaticData(self.config, self.session)
self.score = Mai2ScoreData(self.config, self.session)
self.score = Mai2ScoreData(self.config, self.session)

View File

@@ -20,12 +20,14 @@ from titles.mai2.universe import Mai2Universe
from titles.mai2.universeplus import Mai2UniversePlus
class Mai2Servlet():
class Mai2Servlet:
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
self.core_cfg = core_cfg
self.game_cfg = Mai2Config()
if path.exists(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}"):
self.game_cfg.update(yaml.safe_load(open(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}")))
self.game_cfg.update(
yaml.safe_load(open(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}"))
)
self.versions = [
Mai2Base(core_cfg, self.game_cfg),
@@ -39,34 +41,52 @@ class Mai2Servlet():
self.logger = logging.getLogger("mai2")
log_fmt_str = "[%(asctime)s] Mai2 | %(levelname)s | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(self.core_cfg.server.log_dir, "mai2"), encoding='utf8',
when="d", backupCount=10)
fileHandler = TimedRotatingFileHandler(
"{0}/{1}.log".format(self.core_cfg.server.log_dir, "mai2"),
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)
coloredlogs.install(
level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str
)
@classmethod
def get_allnet_info(cls, game_code: str, core_cfg: CoreConfig, cfg_dir: str) -> Tuple[bool, str, str]:
def get_allnet_info(
cls, game_code: str, core_cfg: CoreConfig, cfg_dir: str
) -> Tuple[bool, str, str]:
game_cfg = Mai2Config()
if path.exists(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}"):
game_cfg.update(yaml.safe_load(open(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}")))
game_cfg.update(
yaml.safe_load(open(f"{cfg_dir}/{Mai2Constants.CONFIG_NAME}"))
)
if not game_cfg.server.enable:
return (False, "", "")
if core_cfg.server.is_develop:
return (True, f"http://{core_cfg.title.hostname}:{core_cfg.title.port}/{game_code}/$v/", f"{core_cfg.title.hostname}:{core_cfg.title.port}/")
return (True, f"http://{core_cfg.title.hostname}/{game_code}/$v/", f"{core_cfg.title.hostname}/")
return (
True,
f"http://{core_cfg.title.hostname}:{core_cfg.title.port}/{game_code}/$v/",
f"{core_cfg.title.hostname}:{core_cfg.title.port}/",
)
return (
True,
f"http://{core_cfg.title.hostname}/{game_code}/$v/",
f"{core_cfg.title.hostname}/",
)
def render_POST(self, request: Request, version: int, url_path: str) -> bytes:
if url_path.lower() == "/ping":
@@ -78,34 +98,36 @@ class Mai2Servlet():
internal_ver = 0
endpoint = url_split[len(url_split) - 1]
if version < 105: # 1.0
if version < 105: # 1.0
internal_ver = Mai2Constants.VER_MAIMAI_DX
elif version >= 105 and version < 110: # Plus
elif version >= 105 and version < 110: # Plus
internal_ver = Mai2Constants.VER_MAIMAI_DX_PLUS
elif version >= 110 and version < 115: # Splash
elif version >= 110 and version < 115: # Splash
internal_ver = Mai2Constants.VER_MAIMAI_DX_SPLASH
elif version >= 115 and version < 120: # Splash Plus
elif version >= 115 and version < 120: # Splash Plus
internal_ver = Mai2Constants.VER_MAIMAI_DX_SPLASH_PLUS
elif version >= 120 and version < 125: # Universe
elif version >= 120 and version < 125: # Universe
internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE
elif version >= 125: # Universe Plus
elif version >= 125: # Universe Plus
internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS
if all(c in string.hexdigits for c in endpoint) and len(endpoint) == 32:
# If we get a 32 character long hex string, it's a hash and we're
# doing encrypted. The likelyhood of false positives is low but
# If we get a 32 character long hex string, it's a hash and we're
# doing encrypted. The likelyhood of false positives is low but
# technically not 0
self.logger.error("Encryption not supported at this time")
try:
try:
unzip = zlib.decompress(req_raw)
except zlib.error as e:
self.logger.error(f"Failed to decompress v{version} {endpoint} request -> {e}")
self.logger.error(
f"Failed to decompress v{version} {endpoint} request -> {e}"
)
return zlib.compress(b'{"stat": "0"}')
req_data = json.loads(unzip)
self.logger.info(f"v{version} {endpoint} request - {req_data}")
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
@@ -121,10 +143,10 @@ class Mai2Servlet():
except Exception as e:
self.logger.error(f"Error handling v{version} method {endpoint} - {e}")
return zlib.compress(b'{"stat": "0"}')
if resp == None:
resp = {'returnCode': 1}
resp = {"returnCode": 1}
self.logger.info(f"Response {resp}")
return zlib.compress(json.dumps(resp, ensure_ascii=False).encode("utf-8"))

View File

@@ -8,7 +8,8 @@ from titles.mai2.base import Mai2Base
from titles.mai2.config import Mai2Config
from titles.mai2.const import Mai2Constants
class Mai2Plus(Mai2Base):
def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None:
super().__init__(cfg, game_cfg)
self.version = Mai2Constants.VER_MAIMAI_DX_PLUS
self.version = Mai2Constants.VER_MAIMAI_DX_PLUS

View File

@@ -11,25 +11,35 @@ from read import BaseReader
from titles.mai2.const import Mai2Constants
from titles.mai2.database import Mai2Data
class Mai2Reader(BaseReader):
def __init__(self, config: CoreConfig, version: int, bin_dir: Optional[str], opt_dir: Optional[str], extra: Optional[str]) -> None:
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 = Mai2Data(config)
try:
self.logger.info(f"Start importer for {Mai2Constants.game_ver_to_string(version)}")
self.logger.info(
f"Start importer for {Mai2Constants.game_ver_to_string(version)}"
)
except IndexError:
self.logger.error(f"Invalid maidx version {version}")
exit(1)
def read(self) -> None:
data_dirs = []
if self.bin_dir is not None:
data_dirs += self.get_data_directories(self.bin_dir)
if self.opt_dir is not None:
data_dirs += self.get_data_directories(self.opt_dir)
data_dirs += self.get_data_directories(self.opt_dir)
for dir in data_dirs:
self.logger.info(f"Read from {dir}")
self.get_events(f"{dir}/event")
@@ -43,47 +53,64 @@ class Mai2Reader(BaseReader):
for dir in dirs:
if os.path.exists(f"{root}/{dir}/Event.xml"):
with open(f"{root}/{dir}/Event.xml", encoding="utf-8") as f:
troot = ET.fromstring(f.read())
name = troot.find('name').find('str').text
id = int(troot.find('name').find('id').text)
event_type = int(troot.find('infoType').text)
name = troot.find("name").find("str").text
id = int(troot.find("name").find("id").text)
event_type = int(troot.find("infoType").text)
self.data.static.put_game_event(self.version, event_type, id, name)
self.data.static.put_game_event(
self.version, event_type, id, name
)
self.logger.info(f"Added event {id}...")
def read_music(self, base_dir: str) -> None:
self.logger.info(f"Reading music from {base_dir}...")
for root, dirs, files in os.walk(base_dir):
for dir in dirs:
for dir in dirs:
if os.path.exists(f"{root}/{dir}/Music.xml"):
with open(f"{root}/{dir}/Music.xml", encoding="utf-8") as f:
troot = ET.fromstring(f.read())
song_id = int(troot.find('name').find('id').text)
title = troot.find('name').find('str').text
artist = troot.find('artistName').find('str').text
genre = troot.find('genreName').find('str').text
bpm = int(troot.find('bpm').text)
added_ver = troot.find('AddVersion').find('str').text
song_id = int(troot.find("name").find("id").text)
title = troot.find("name").find("str").text
artist = troot.find("artistName").find("str").text
genre = troot.find("genreName").find("str").text
bpm = int(troot.find("bpm").text)
added_ver = troot.find("AddVersion").find("str").text
note_data = troot.find('notesData').findall('Notes')
note_data = troot.find("notesData").findall("Notes")
for dif in note_data:
path = dif.find('file').find('path').text
path = dif.find("file").find("path").text
if path is not None:
if os.path.exists(f"{root}/{dir}/{path}"):
chart_id = int(path.split(".")[0].split('_')[1])
diff_num = float(f"{dif.find('level').text}.{dif.find('levelDecimal').text}")
note_designer = dif.find('notesDesigner').find('str').text
chart_id = int(path.split(".")[0].split("_")[1])
diff_num = float(
f"{dif.find('level').text}.{dif.find('levelDecimal').text}"
)
note_designer = (
dif.find("notesDesigner").find("str").text
)
self.data.static.put_game_music(
self.version,
song_id,
chart_id,
title,
artist,
genre,
bpm,
added_ver,
diff_num,
note_designer,
)
self.logger.info(
f"Added music id {song_id} chart {chart_id}"
)
self.data.static.put_game_music(self.version, song_id, chart_id, title, artist,
genre, bpm, added_ver, diff_num, note_designer)
self.logger.info(f"Added music id {song_id} chart {chart_id}")
def read_tickets(self, base_dir: str) -> None:
self.logger.info(f"Reading tickets from {base_dir}...")
@@ -91,13 +118,14 @@ class Mai2Reader(BaseReader):
for dir in dirs:
if os.path.exists(f"{root}/{dir}/Ticket.xml"):
with open(f"{root}/{dir}/Ticket.xml", encoding="utf-8") as f:
troot = ET.fromstring(f.read())
name = troot.find('name').find('str').text
id = int(troot.find('name').find('id').text)
ticket_type = int(troot.find('ticketKind').find('id').text)
price = int(troot.find('creditNum').text)
name = troot.find("name").find("str").text
id = int(troot.find("name").find("id").text)
ticket_type = int(troot.find("ticketKind").find("id").text)
price = int(troot.find("creditNum").text)
self.data.static.put_game_ticket(self.version, id, ticket_type, price, name)
self.data.static.put_game_ticket(
self.version, id, ticket_type, price, name
)
self.logger.info(f"Added ticket {id}...")

View File

@@ -3,4 +3,4 @@ from titles.mai2.schema.item import Mai2ItemData
from titles.mai2.schema.static import Mai2StaticData
from titles.mai2.schema.score import Mai2ScoreData
__all__ = [Mai2ProfileData, Mai2ItemData, Mai2StaticData, Mai2ScoreData]
__all__ = [Mai2ProfileData, Mai2ItemData, Mai2StaticData, Mai2ScoreData]

View File

@@ -12,20 +12,28 @@ character = Table(
"mai2_item_character",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("character_id", Integer, nullable=False),
Column("level", Integer, nullable=False, server_default="1"),
Column("awakening", Integer, nullable=False, server_default="0"),
Column("use_count", Integer, nullable=False, server_default="0"),
UniqueConstraint("user", "character_id", name="mai2_item_character_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
card = Table(
"mai2_item_card",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("card_kind", Integer, nullable=False),
Column("card_id", Integer, nullable=False),
Column("chara_id", Integer, nullable=False),
@@ -33,54 +41,70 @@ card = Table(
Column("start_date", String(255), nullable=False),
Column("end_date", String(255), nullable=False),
UniqueConstraint("user", "card_kind", "card_id", name="mai2_item_card_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
item = Table(
"mai2_item_item",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("item_kind", Integer, nullable=False),
Column("item_id", Integer, nullable=False),
Column("stock", Integer, nullable=False, server_default="1"),
Column("is_valid", Boolean, nullable=False, server_default="1"),
UniqueConstraint("user", "item_kind", "item_id", name="mai2_item_item_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
map = Table(
"mai2_item_map",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("map_id", Integer, nullable=False),
Column("distance", Integer, nullable=False),
Column("is_lock", Boolean, nullable=False, server_default="0"),
Column("is_clear", Boolean, nullable=False, server_default="0"),
Column("is_complete", Boolean, nullable=False, server_default="0"),
UniqueConstraint("user", "map_id", name="mai2_item_map_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
login_bonus = Table(
"mai2_item_login_bonus",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("bonus_id", Integer, nullable=False),
Column("point", Integer, nullable=False),
Column("is_current", Boolean, nullable=False, server_default="0"),
Column("is_complete", Boolean, nullable=False, server_default="0"),
UniqueConstraint("user", "bonus_id", name="mai2_item_login_bonus_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
friend_season_ranking = Table(
"mai2_item_friend_season_ranking",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("season_id", Integer, nullable=False),
Column("point", Integer, nullable=False),
Column("rank", Integer, nullable=False),
@@ -88,35 +112,46 @@ friend_season_ranking = Table(
Column("user_name", String(8), nullable=False),
Column("record_date", String(255), nullable=False),
UniqueConstraint("user", "season_id", "user_name", name="mai2_item_login_bonus_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
favorite = Table(
"mai2_item_favorite",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("itemKind", Integer, nullable=False),
Column("itemIdList", JSON),
UniqueConstraint("user", "itemKind", name="mai2_item_favorite_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
charge = Table(
"mai2_item_charge",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("charge_id", Integer, nullable=False),
Column("stock", Integer, nullable=False),
Column("purchase_date", String(255), nullable=False),
Column("valid_date", String(255), nullable=False),
UniqueConstraint("user", "charge_id", name="mai2_item_charge_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
class Mai2ItemData(BaseData):
def put_item(self, user_id: int, item_kind: int, item_id: int, stock: int, is_valid: bool) -> None:
def put_item(
self, user_id: int, item_kind: int, item_id: int, stock: int, is_valid: bool
) -> None:
sql = insert(item).values(
user=user_id,
item_kind=item_kind,
@@ -132,28 +167,47 @@ class Mai2ItemData(BaseData):
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_item: failed to insert item! user_id: {user_id}, item_kind: {item_kind}, item_id: {item_id}")
self.logger.warn(
f"put_item: failed to insert item! user_id: {user_id}, item_kind: {item_kind}, item_id: {item_id}"
)
return None
return result.lastrowid
def get_items(self, user_id: int, item_kind: int = None) -> Optional[List[Row]]:
if item_kind is None:
sql = item.select(item.c.user == user_id)
else:
sql = item.select(and_(item.c.user == user_id, item.c.item_kind == item_kind))
sql = item.select(
and_(item.c.user == user_id, item.c.item_kind == item_kind)
)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchall()
def get_item(self, user_id: int, item_kind: int, item_id: int) -> Optional[Row]:
sql = item.select(and_(item.c.user == user_id, item.c.item_kind == item_kind, item.c.item_id == item_id))
sql = item.select(
and_(
item.c.user == user_id,
item.c.item_kind == item_kind,
item.c.item_id == item_id,
)
)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchone()
def put_login_bonus(self, user_id: int, bonus_id: int, point: int, is_current: bool, is_complete: bool) -> None:
def put_login_bonus(
self,
user_id: int,
bonus_id: int,
point: int,
is_current: bool,
is_complete: bool,
) -> None:
sql = insert(login_bonus).values(
user=user_id,
bonus_id=bonus_id,
@@ -170,25 +224,39 @@ class Mai2ItemData(BaseData):
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_login_bonus: failed to insert item! user_id: {user_id}, bonus_id: {bonus_id}, point: {point}")
self.logger.warn(
f"put_login_bonus: failed to insert item! user_id: {user_id}, bonus_id: {bonus_id}, point: {point}"
)
return None
return result.lastrowid
def get_login_bonuses(self, user_id: int) -> Optional[List[Row]]:
sql = login_bonus.select(login_bonus.c.user == user_id)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchall()
def get_login_bonus(self, user_id: int, bonus_id: int) -> Optional[Row]:
sql = login_bonus.select(and_(login_bonus.c.user == user_id, login_bonus.c.bonus_id == bonus_id))
sql = login_bonus.select(
and_(login_bonus.c.user == user_id, login_bonus.c.bonus_id == bonus_id)
)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchone()
def put_map(self, user_id: int, map_id: int, distance: int, is_lock: bool, is_clear: bool, is_complete: bool) -> None:
def put_map(
self,
user_id: int,
map_id: int,
distance: int,
is_lock: bool,
is_clear: bool,
is_complete: bool,
) -> None:
sql = insert(map).values(
user=user_id,
map_id=map_id,
@@ -207,25 +275,36 @@ class Mai2ItemData(BaseData):
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_map: failed to insert item! user_id: {user_id}, map_id: {map_id}, distance: {distance}")
self.logger.warn(
f"put_map: failed to insert item! user_id: {user_id}, map_id: {map_id}, distance: {distance}"
)
return None
return result.lastrowid
def get_maps(self, user_id: int) -> Optional[List[Row]]:
sql = map.select(map.c.user == user_id)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchall()
def get_map(self, user_id: int, map_id: int) -> Optional[Row]:
sql = map.select(and_(map.c.user == user_id, map.c.map_id == map_id))
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchone()
def put_character(self, user_id: int, character_id: int, level: int, awakening: int, use_count: int) -> None:
def put_character(
self,
user_id: int,
character_id: int,
level: int,
awakening: int,
use_count: int,
) -> None:
sql = insert(character).values(
user=user_id,
character_id=character_id,
@@ -242,57 +321,64 @@ class Mai2ItemData(BaseData):
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_character: failed to insert item! user_id: {user_id}, character_id: {character_id}, level: {level}")
self.logger.warn(
f"put_character: failed to insert item! user_id: {user_id}, character_id: {character_id}, level: {level}"
)
return None
return result.lastrowid
def get_characters(self, user_id: int) -> Optional[List[Row]]:
sql = character.select(character.c.user == user_id)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchall()
def get_character(self, user_id: int, character_id: int) -> Optional[Row]:
sql = character.select(and_(character.c.user == user_id, character.c.character_id == character_id))
sql = character.select(
and_(character.c.user == user_id, character.c.character_id == character_id)
)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchone()
def get_friend_season_ranking(self, user_id: int) -> Optional[Row]:
sql = friend_season_ranking.select(friend_season_ranking.c.user == user_id)
result = self.execute(sql)
if result is None:return None
if result is None:
return None
return result.fetchone()
def put_favorite(self, user_id: int, kind: int, item_id_list: List[int]) -> Optional[int]:
def put_favorite(
self, user_id: int, kind: int, item_id_list: List[int]
) -> Optional[int]:
sql = insert(favorite).values(
user=user_id,
kind=kind,
item_id_list=item_id_list
user=user_id, kind=kind, item_id_list=item_id_list
)
conflict = sql.on_duplicate_key_update(
item_id_list=item_id_list
)
conflict = sql.on_duplicate_key_update(item_id_list=item_id_list)
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_favorite: failed to insert item! user_id: {user_id}, kind: {kind}")
self.logger.warn(
f"put_favorite: failed to insert item! user_id: {user_id}, kind: {kind}"
)
return None
return result.lastrowid
def get_favorites(self, user_id: int, kind: int = None) -> Optional[Row]:
if kind is None:
sql = favorite.select(favorite.c.user == user_id)
else:
sql = favorite.select(and_(
favorite.c.user == user_id,
favorite.c.itemKind == kind
))
sql = favorite.select(
and_(favorite.c.user == user_id, favorite.c.itemKind == kind)
)
result = self.execute(sql)
if result is None:return None
return result.fetchall()
if result is None:
return None
return result.fetchall()

View File

@@ -14,7 +14,11 @@ detail = Table(
"mai2_profile_detail",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("version", Integer, nullable=False),
Column("userName", String(25)),
Column("isNetMember", Integer),
@@ -41,9 +45,9 @@ detail = Table(
Column("lastRomVersion", String(25)),
Column("lastDataVersion", String(25)),
Column("lastLoginDate", String(25)),
Column("lastPairLoginDate", String(25)), # new with uni+
Column("lastPairLoginDate", String(25)), # new with uni+
Column("lastPlayDate", String(25)),
Column("lastTrialPlayDate", String(25)), # new with uni+
Column("lastTrialPlayDate", String(25)), # new with uni+
Column("lastPlayCredit", Integer),
Column("lastPlayMode", Integer),
Column("lastPlaceId", Integer),
@@ -90,16 +94,20 @@ detail = Table(
Column("playerOldRating", BigInteger),
Column("playerNewRating", BigInteger),
Column("dateTime", BigInteger),
Column("banState", Integer), # new with uni+
Column("banState", Integer), # new with uni+
UniqueConstraint("user", "version", name="mai2_profile_detail_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
ghost = Table(
"mai2_profile_ghost",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("version_int", Integer, nullable=False),
Column("name", String(25)),
Column("iconId", Integer),
@@ -120,15 +128,21 @@ ghost = Table(
Column("resultBitList", JSON),
Column("resultNum", Integer),
Column("achievement", Integer),
UniqueConstraint("user", "version", "musicId", "difficulty", name="mai2_profile_ghost_uk"),
mysql_charset='utf8mb4'
UniqueConstraint(
"user", "version", "musicId", "difficulty", name="mai2_profile_ghost_uk"
),
mysql_charset="utf8mb4",
)
extend = Table(
"mai2_profile_extend",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("version", Integer, nullable=False),
Column("selectMusicId", Integer),
Column("selectDifficultyId", Integer),
@@ -145,14 +159,18 @@ extend = Table(
Column("selectedCardList", JSON),
Column("encountMapNpcList", JSON),
UniqueConstraint("user", "version", name="mai2_profile_extend_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
option = Table(
"mai2_profile_option",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("version", Integer, nullable=False),
Column("selectMusicId", Integer),
Column("optionKind", Integer),
@@ -200,14 +218,18 @@ option = Table(
Column("sortTab", Integer),
Column("sortMusic", Integer),
UniqueConstraint("user", "version", name="mai2_profile_option_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
rating = Table(
"mai2_profile_rating",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("version", Integer, nullable=False),
Column("rating", Integer),
Column("ratingList", JSON),
@@ -216,26 +238,34 @@ rating = Table(
Column("nextNewRatingList", JSON),
Column("udemae", JSON),
UniqueConstraint("user", "version", name="mai2_profile_rating_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
region = Table(
"mai2_profile_region",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("regionId", Integer),
Column("playCount", Integer, server_default="1"),
Column("created", String(25)),
UniqueConstraint("user", "regionId", name="mai2_profile_region_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
activity = Table(
"mai2_profile_activity",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("kind", Integer, nullable=False),
Column("activityId", Integer, nullable=False),
Column("param1", Integer, nullable=False),
@@ -244,11 +274,14 @@ activity = Table(
Column("param4", Integer, nullable=False),
Column("sortNumber", Integer, nullable=False),
UniqueConstraint("user", "kind", "activityId", name="mai2_profile_activity_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
class Mai2ProfileData(BaseData):
def put_profile_detail(self, user_id: int, version: int, detail_data: Dict) -> Optional[Row]:
def put_profile_detail(
self, user_id: int, version: int, detail_data: Dict
) -> Optional[Row]:
detail_data["user"] = user_id
detail_data["version"] = version
sql = insert(detail).values(**detail_data)
@@ -257,18 +290,25 @@ class Mai2ProfileData(BaseData):
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_profile: Failed to create profile! user_id {user_id}")
self.logger.warn(
f"put_profile: Failed to create profile! user_id {user_id}"
)
return None
return result.lastrowid
def get_profile_detail(self, user_id: int, version: int) -> Optional[Row]:
sql = select(detail).where(and_(detail.c.user == user_id, detail.c.version == version))
sql = select(detail).where(
and_(detail.c.user == user_id, detail.c.version == version)
)
result = self.execute(sql)
if result is None:return None
if result is None:
return None
return result.fetchone()
def put_profile_ghost(self, user_id: int, version: int, ghost_data: Dict) -> Optional[int]:
def put_profile_ghost(
self, user_id: int, version: int, ghost_data: Dict
) -> Optional[int]:
ghost_data["user"] = user_id
ghost_data["version_int"] = version
@@ -282,13 +322,18 @@ class Mai2ProfileData(BaseData):
return result.lastrowid
def get_profile_ghost(self, user_id: int, version: int) -> Optional[Row]:
sql = select(ghost).where(and_(ghost.c.user == user_id, ghost.c.version_int == version))
sql = select(ghost).where(
and_(ghost.c.user == user_id, ghost.c.version_int == version)
)
result = self.execute(sql)
if result is None:return None
if result is None:
return None
return result.fetchone()
def put_profile_extend(self, user_id: int, version: int, extend_data: Dict) -> Optional[int]:
def put_profile_extend(
self, user_id: int, version: int, extend_data: Dict
) -> Optional[int]:
extend_data["user"] = user_id
extend_data["version"] = version
@@ -302,13 +347,18 @@ class Mai2ProfileData(BaseData):
return result.lastrowid
def get_profile_extend(self, user_id: int, version: int) -> Optional[Row]:
sql = select(extend).where(and_(extend.c.user == user_id, extend.c.version == version))
sql = select(extend).where(
and_(extend.c.user == user_id, extend.c.version == version)
)
result = self.execute(sql)
if result is None:return None
if result is None:
return None
return result.fetchone()
def put_profile_option(self, user_id: int, version: int, option_data: Dict) -> Optional[int]:
def put_profile_option(
self, user_id: int, version: int, option_data: Dict
) -> Optional[int]:
option_data["user"] = user_id
option_data["version"] = version
@@ -322,13 +372,18 @@ class Mai2ProfileData(BaseData):
return result.lastrowid
def get_profile_option(self, user_id: int, version: int) -> Optional[Row]:
sql = select(option).where(and_(option.c.user == user_id, option.c.version == version))
sql = select(option).where(
and_(option.c.user == user_id, option.c.version == version)
)
result = self.execute(sql)
if result is None:return None
if result is None:
return None
return result.fetchone()
def put_profile_rating(self, user_id: int, version: int, rating_data: Dict) -> Optional[int]:
def put_profile_rating(
self, user_id: int, version: int, rating_data: Dict
) -> Optional[int]:
rating_data["user"] = user_id
rating_data["version"] = version
@@ -342,23 +397,24 @@ class Mai2ProfileData(BaseData):
return result.lastrowid
def get_profile_rating(self, user_id: int, version: int) -> Optional[Row]:
sql = select(rating).where(and_(rating.c.user == user_id, rating.c.version == version))
sql = select(rating).where(
and_(rating.c.user == user_id, rating.c.version == version)
)
result = self.execute(sql)
if result is None:return None
if result is None:
return None
return result.fetchone()
def put_profile_region(self, user_id: int, region_id: int) -> Optional[int]:
sql = insert(region).values(
user = user_id,
regionId = region_id,
created = datetime.strftime(datetime.now(), Mai2Constants.DATE_TIME_FORMAT)
)
conflict = sql.on_duplicate_key_update(
playCount = region.c.playCount + 1
user=user_id,
regionId=region_id,
created=datetime.strftime(datetime.now(), Mai2Constants.DATE_TIME_FORMAT),
)
conflict = sql.on_duplicate_key_update(playCount=region.c.playCount + 1)
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_region: failed to update! {user_id}")
@@ -369,34 +425,38 @@ class Mai2ProfileData(BaseData):
sql = select(region).where(region.c.user == user_id)
result = self.execute(sql)
if result is None:return None
if result is None:
return None
return result.fetchall()
def put_profile_activity(self, user_id: int, activity_data: Dict) -> Optional[int]:
if "id" in activity_data:
activity_data["activityId"] = activity_data["id"]
activity_data.pop("id")
activity_data["user"] = user_id
sql = insert(activity).values(**activity_data)
conflict = sql.on_duplicate_key_update(**activity_data)
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_profile_activity: failed to update! user_id: {user_id}")
self.logger.warn(
f"put_profile_activity: failed to update! user_id: {user_id}"
)
return None
return result.lastrowid
def get_profile_activity(self, user_id: int, kind: int = None) -> Optional[Row]:
sql = activity.select(
and_(
activity.c.user == user_id,
activity.c.user == user_id,
(activity.c.kind == kind) if kind is not None else True,
)
)
result = self.execute(sql)
if result is None:return None
if result is None:
return None
return result.fetchone()

View File

@@ -12,7 +12,11 @@ best_score = Table(
"mai2_score_best",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("musicId", Integer),
Column("level", Integer),
Column("playCount", Integer),
@@ -22,14 +26,18 @@ best_score = Table(
Column("deluxscoreMax", Integer),
Column("scoreRank", Integer),
UniqueConstraint("user", "musicId", "level", name="mai2_score_best_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
playlog = Table(
"mai2_playlog",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("userId", BigInteger),
Column("orderId", Integer),
Column("playlogId", BigInteger),
@@ -136,14 +144,18 @@ playlog = Table(
Column("extNum1", Integer),
Column("extNum2", Integer),
Column("trialPlayAchievement", Integer),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
course = Table(
"mai2_score_course",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("courseId", Integer),
Column("isLastClear", Boolean),
Column("totalRestlife", Integer),
@@ -157,9 +169,10 @@ course = Table(
Column("bestDeluxscore", Integer),
Column("bestDeluxscoreDate", String(25)),
UniqueConstraint("user", "courseId", name="mai2_score_best_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
class Mai2ScoreData(BaseData):
def put_best_score(self, user_id: int, score_data: Dict) -> Optional[int]:
score_data["user"] = user_id
@@ -169,33 +182,39 @@ class Mai2ScoreData(BaseData):
result = self.execute(conflict)
if result is None:
self.logger.error(f"put_best_score: Failed to insert best score! user_id {user_id}")
self.logger.error(
f"put_best_score: Failed to insert best score! user_id {user_id}"
)
return None
return result.lastrowid
def get_best_scores(self, user_id: int, song_id: int = None) -> Optional[List[Row]]:
sql = best_score.select(
and_(
best_score.c.user == user_id,
(best_score.c.song_id == song_id) if song_id is not None else True
)
best_score.c.user == user_id,
(best_score.c.song_id == song_id) if song_id is not None else True,
)
)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchall()
def get_best_score(self, user_id: int, song_id: int, chart_id: int) -> Optional[Row]:
def get_best_score(
self, user_id: int, song_id: int, chart_id: int
) -> Optional[Row]:
sql = best_score.select(
and_(
best_score.c.user == user_id,
best_score.c.song_id == song_id,
best_score.c.chart_id == chart_id
)
best_score.c.user == user_id,
best_score.c.song_id == song_id,
best_score.c.chart_id == chart_id,
)
)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchone()
def put_playlog(self, user_id: int, playlog_data: Dict) -> Optional[int]:
@@ -209,7 +228,7 @@ class Mai2ScoreData(BaseData):
self.logger.error(f"put_playlog: Failed to insert! user_id {user_id}")
return None
return result.lastrowid
def put_course(self, user_id: int, course_data: Dict) -> Optional[int]:
course_data["user"] = user_id
sql = insert(course).values(**course_data)
@@ -221,10 +240,11 @@ class Mai2ScoreData(BaseData):
self.logger.error(f"put_course: Failed to insert! user_id {user_id}")
return None
return result.lastrowid
def get_courses(self, user_id: int) -> Optional[List[Row]]:
sql = course.select(best_score.c.user == user_id)
result = self.execute(sql)
if result is None: return None
if result is None:
return None
return result.fetchone()

View File

@@ -12,20 +12,20 @@ event = Table(
"mai2_static_event",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("version", Integer,nullable=False),
Column("version", Integer, nullable=False),
Column("eventId", Integer),
Column("type", Integer),
Column("name", String(255)),
Column("enabled", Boolean, server_default="1"),
UniqueConstraint("version", "eventId", "type", name="mai2_static_event_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
music = Table(
"mai2_static_music",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("version", Integer,nullable=False),
Column("id", Integer, primary_key=True, nullable=False),
Column("version", Integer, nullable=False),
Column("songId", Integer),
Column("chartId", Integer),
Column("title", String(255)),
@@ -36,39 +36,42 @@ music = Table(
Column("difficulty", Float),
Column("noteDesigner", String(255)),
UniqueConstraint("songId", "chartId", "version", name="mai2_static_music_uk"),
mysql_charset='utf8mb4'
mysql_charset="utf8mb4",
)
ticket = Table(
"mai2_static_ticket",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("version", Integer,nullable=False),
Column("version", Integer, nullable=False),
Column("ticketId", Integer),
Column("kind", Integer),
Column("name", String(255)),
Column("price", Integer, server_default="1"),
Column("enabled", Boolean, server_default="1"),
UniqueConstraint("version","ticketId", name="mai2_static_ticket_uk"),
mysql_charset='utf8mb4'
UniqueConstraint("version", "ticketId", name="mai2_static_ticket_uk"),
mysql_charset="utf8mb4",
)
class Mai2StaticData(BaseData):
def put_game_event(self, version: int, type: int, event_id: int, name: str) -> Optional[int]:
def put_game_event(
self, version: int, type: int, event_id: int, name: str
) -> Optional[int]:
sql = insert(event).values(
version = version,
type = type,
eventId = event_id,
name = name,
version=version,
type=type,
eventId=event_id,
name=name,
)
conflict = sql.on_duplicate_key_update(
eventId = event_id
)
conflict = sql.on_duplicate_key_update(eventId=event_id)
result = self.execute(conflict)
if result is None:
self.logger.warning(f"put_game_event: Failed to insert event! event_id {event_id} type {type} name {name}")
self.logger.warning(
f"put_game_event: Failed to insert event! event_id {event_id} type {type} name {name}"
)
return result.lastrowid
def get_game_events(self, version: int) -> Optional[List[Row]]:
@@ -78,50 +81,65 @@ class Mai2StaticData(BaseData):
if result is None:
return None
return result.fetchall()
def get_enabled_events(self, version: int) -> Optional[List[Row]]:
sql = select(event).where(and_(
event.c.version == version,
event.c.enabled == True
))
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def toggle_game_events(self, version: int, event_id: int, toggle: bool) -> Optional[List]:
sql = event.update(and_(event.c.version == version, event.c.event_id == event_id)).values(
enabled = int(toggle)
sql = select(event).where(
and_(event.c.version == version, event.c.enabled == True)
)
result = self.execute(sql)
if result is None:
self.logger.warning(f"toggle_game_events: Failed to update event! event_id {event_id} toggle {toggle}")
return None
return result.fetchall()
def toggle_game_events(
self, version: int, event_id: int, toggle: bool
) -> Optional[List]:
sql = event.update(
and_(event.c.version == version, event.c.event_id == event_id)
).values(enabled=int(toggle))
result = self.execute(sql)
if result is None:
self.logger.warning(
f"toggle_game_events: Failed to update event! event_id {event_id} toggle {toggle}"
)
return result.last_updated_params()
def put_game_music(self, version: int, song_id: int, chart_id: int, title: str, artist: str,
genre: str, bpm: str, added_version: str, difficulty: float, note_designer: str) -> None:
def put_game_music(
self,
version: int,
song_id: int,
chart_id: int,
title: str,
artist: str,
genre: str,
bpm: str,
added_version: str,
difficulty: float,
note_designer: str,
) -> None:
sql = insert(music).values(
version = version,
songId = song_id,
chartId = chart_id,
title = title,
artist = artist,
genre = genre,
bpm = bpm,
addedVersion = added_version,
difficulty = difficulty,
noteDesigner = note_designer,
version=version,
songId=song_id,
chartId=chart_id,
title=title,
artist=artist,
genre=genre,
bpm=bpm,
addedVersion=added_version,
difficulty=difficulty,
noteDesigner=note_designer,
)
conflict = sql.on_duplicate_key_update(
title = title,
artist = artist,
genre = genre,
bpm = bpm,
addedVersion = added_version,
difficulty = difficulty,
noteDesigner = note_designer,
title=title,
artist=artist,
genre=genre,
bpm=bpm,
addedVersion=added_version,
difficulty=difficulty,
noteDesigner=note_designer,
)
result = self.execute(conflict)
@@ -129,50 +147,64 @@ class Mai2StaticData(BaseData):
self.logger.warn(f"Failed to insert song {song_id} chart {chart_id}")
return None
return result.lastrowid
def put_game_ticket(self, version: int, ticket_id: int, ticket_type: int, ticket_price: int, name: str) -> Optional[int]:
def put_game_ticket(
self,
version: int,
ticket_id: int,
ticket_type: int,
ticket_price: int,
name: str,
) -> Optional[int]:
sql = insert(ticket).values(
version = version,
ticketId = ticket_id,
kind = ticket_type,
price = ticket_price,
name = name
version=version,
ticketId=ticket_id,
kind=ticket_type,
price=ticket_price,
name=name,
)
conflict = sql.on_duplicate_key_update(
price = ticket_price
)
conflict = sql.on_duplicate_key_update(price=ticket_price)
result = self.execute(conflict)
if result is None:
self.logger.warn(f"Failed to insert charge {ticket_id} type {ticket_type}")
return None
return result.lastrowid
def get_enabled_tickets(self, version: int, kind: int = None) -> Optional[List[Row]]:
def get_enabled_tickets(
self, version: int, kind: int = None
) -> Optional[List[Row]]:
if kind is not None:
sql = select(ticket).where(and_(
ticket.c.version == version,
ticket.c.enabled == True,
ticket.c.kind == kind
))
sql = select(ticket).where(
and_(
ticket.c.version == version,
ticket.c.enabled == True,
ticket.c.kind == kind,
)
)
else:
sql = select(ticket).where(and_(
ticket.c.version == version,
ticket.c.enabled == True
))
sql = select(ticket).where(
and_(ticket.c.version == version, ticket.c.enabled == True)
)
result = self.execute(sql)
if result is None:return None
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
))
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
if result is None:
return None
return result.fetchone()

View File

@@ -8,7 +8,8 @@ from titles.mai2.base import Mai2Base
from titles.mai2.config import Mai2Config
from titles.mai2.const import Mai2Constants
class Mai2Splash(Mai2Base):
def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None:
super().__init__(cfg, game_cfg)
self.version = Mai2Constants.VER_MAIMAI_DX_SPLASH
self.version = Mai2Constants.VER_MAIMAI_DX_SPLASH

View File

@@ -8,7 +8,8 @@ from titles.mai2.base import Mai2Base
from titles.mai2.config import Mai2Config
from titles.mai2.const import Mai2Constants
class Mai2SplashPlus(Mai2Base):
def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None:
super().__init__(cfg, game_cfg)
self.version = Mai2Constants.VER_MAIMAI_DX_SPLASH_PLUS
self.version = Mai2Constants.VER_MAIMAI_DX_SPLASH_PLUS

View File

@@ -8,7 +8,8 @@ from titles.mai2.base import Mai2Base
from titles.mai2.const import Mai2Constants
from titles.mai2.config import Mai2Config
class Mai2Universe(Mai2Base):
def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None:
super().__init__(cfg, game_cfg)
self.version = Mai2Constants.VER_MAIMAI_DX_UNIVERSE
self.version = Mai2Constants.VER_MAIMAI_DX_UNIVERSE

View File

@@ -8,7 +8,8 @@ from titles.mai2.base import Mai2Base
from titles.mai2.const import Mai2Constants
from titles.mai2.config import Mai2Config
class Mai2UniversePlus(Mai2Base):
def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None:
super().__init__(cfg, game_cfg)
self.version = Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS
self.version = Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS