maimai: Initial Festival support

This commit is contained in:
Dniel97
2023-04-10 18:58:19 +02:00
parent 7fdb3e8222
commit f63dd07937
14 changed files with 347 additions and 198 deletions

View File

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

View File

@@ -1,5 +1,5 @@
from datetime import datetime, date, timedelta
from typing import Dict
from typing import Any, Dict
import logging
from core.config import CoreConfig
@@ -52,6 +52,7 @@ class Mai2Base:
events = self.data.static.get_enabled_events(self.version)
events_lst = []
if events is None:
self.logger.warn("No enabled events, did you run the reader?")
return {"type": data["type"], "length": 0, "gameEventList": []}
for event in events:
@@ -59,7 +60,11 @@ class Mai2Base:
{
"type": event["type"],
"id": event["eventId"],
"startDate": "2017-12-05 07:00:00.0",
# actually use the startDate from the import so it
# properly shows all the events when new ones are imported
"startDate": datetime.strftime(
event["startDate"], f"{Mai2Constants.DATE_TIME_FORMAT}.0"
),
"endDate": "2099-12-31 00:00:00.0",
}
)
@@ -79,12 +84,12 @@ class Mai2Base:
return {"length": 0, "gameChargeList": []}
charge_list = []
for x in range(len(game_charge_list)):
for i, charge in enumerate(game_charge_list):
charge_list.append(
{
"orderId": x,
"chargeId": game_charge_list[x]["ticketId"],
"price": game_charge_list[x]["price"],
"orderId": i,
"chargeId": charge["ticketId"],
"price": charge["price"],
"startDate": "2017-12-05 07:00:00.0",
"endDate": "2099-12-31 00:00:00.0",
}
@@ -167,6 +172,20 @@ class Mai2Base:
self.data.score.put_playlog(user_id, playlog)
def handle_upsert_user_chargelog_api_request(self, data: Dict) -> Dict:
user_id = data["userId"]
charge = data["userCharge"]
# remove the ".0" from the date string, festival only?
charge["purchaseDate"] = charge["purchaseDate"].replace(".0", "")
self.data.item.put_charge(
user_id,
charge["chargeId"],
charge["stock"],
datetime.strptime(charge["purchaseDate"], Mai2Constants.DATE_TIME_FORMAT),
datetime.strptime(charge["validDate"], Mai2Constants.DATE_TIME_FORMAT),
)
def handle_upsert_user_all_api_request(self, data: Dict) -> Dict:
user_id = data["userId"]
upsert = data["upsertUserAll"]
@@ -204,15 +223,21 @@ class Mai2Base:
if "userChargeList" in upsert and len(upsert["userChargeList"]) > 0:
for charge in upsert["userChargeList"]:
# remove the ".0" from the date string, festival only?
charge["purchaseDate"] = charge["purchaseDate"].replace(".0", "")
self.data.item.put_charge(
user_id,
charge["chargeId"],
charge["stock"],
datetime.strptime(charge["purchaseDate"], "%Y-%m-%d %H:%M:%S"),
datetime.strptime(charge["validDate"], "%Y-%m-%d %H:%M:%S")
datetime.strptime(
charge["purchaseDate"], Mai2Constants.DATE_TIME_FORMAT
),
datetime.strptime(
charge["validDate"], Mai2Constants.DATE_TIME_FORMAT
),
)
if upsert["isNewCharacterList"] and int(upsert["isNewCharacterList"]) > 0:
if "userCharacterList" in upsert and len(upsert["userCharacterList"]) > 0:
for char in upsert["userCharacterList"]:
self.data.item.put_character(
user_id,
@@ -222,7 +247,7 @@ class Mai2Base:
char["useCount"],
)
if upsert["isNewItemList"] and int(upsert["isNewItemList"]) > 0:
if "userItemList" in upsert and len(upsert["userItemList"]) > 0:
for item in upsert["userItemList"]:
self.data.item.put_item(
user_id,
@@ -232,7 +257,7 @@ class Mai2Base:
item["isValid"],
)
if upsert["isNewLoginBonusList"] and int(upsert["isNewLoginBonusList"]) > 0:
if "userLoginBonusList" in upsert and len(upsert["userLoginBonusList"]) > 0:
for login_bonus in upsert["userLoginBonusList"]:
self.data.item.put_login_bonus(
user_id,
@@ -242,7 +267,7 @@ class Mai2Base:
login_bonus["isComplete"],
)
if upsert["isNewMapList"] and int(upsert["isNewMapList"]) > 0:
if "userMapList" in upsert and len(upsert["userMapList"]) > 0:
for map in upsert["userMapList"]:
self.data.item.put_map(
user_id,
@@ -253,21 +278,27 @@ class Mai2Base:
map["isComplete"],
)
if upsert["isNewMusicDetailList"] and int(upsert["isNewMusicDetailList"]) > 0:
if "userMusicDetailList" in upsert and len(upsert["userMusicDetailList"]) > 0:
for music in upsert["userMusicDetailList"]:
self.data.score.put_best_score(user_id, music)
if upsert["isNewCourseList"] and int(upsert["isNewCourseList"]) > 0:
if "userCourseList" in upsert and len(upsert["userCourseList"]) > 0:
for course in upsert["userCourseList"]:
self.data.score.put_course(user_id, course)
if upsert["isNewFavoriteList"] and int(upsert["isNewFavoriteList"]) > 0:
if "userFavoriteList" in upsert and len(upsert["userFavoriteList"]) > 0:
for fav in upsert["userFavoriteList"]:
self.data.item.put_favorite(user_id, fav["kind"], fav["itemIdList"])
# if "isNewFriendSeasonRankingList" in upsert and int(upsert["isNewFriendSeasonRankingList"]) > 0:
# for fsr in upsert["userFriendSeasonRankingList"]:
# pass
if (
"userFriendSeasonRankingList" in upsert
and len(upsert["userFriendSeasonRankingList"]) > 0
):
for fsr in upsert["userFriendSeasonRankingList"]:
fsr["recordDate"] = (
datetime.strptime(fsr["recordDate"], f"{Mai2Constants.DATE_TIME_FORMAT}.0"),
)
self.data.item.put_friend_season_ranking(user_id, fsr)
def handle_user_logout_api_request(self, data: Dict) -> Dict:
pass
@@ -311,11 +342,7 @@ class Mai2Base:
def handle_get_user_card_api_request(self, data: Dict) -> Dict:
user_cards = self.data.item.get_cards(data["userId"])
if user_cards is None:
return {
"userId": data["userId"],
"nextIndex": 0,
"userCardList": []
}
return {"userId": data["userId"], "nextIndex": 0, "userCardList": []}
max_ct = data["maxCount"]
next_idx = data["nextIndex"]
@@ -333,25 +360,23 @@ class Mai2Base:
tmp.pop("id")
tmp.pop("user")
tmp["startDate"] = datetime.strftime(
tmp["startDate"], "%Y-%m-%d %H:%M:%S")
tmp["startDate"], Mai2Constants.DATE_TIME_FORMAT
)
tmp["endDate"] = datetime.strftime(
tmp["endDate"], "%Y-%m-%d %H:%M:%S")
tmp["endDate"], Mai2Constants.DATE_TIME_FORMAT
)
card_list.append(tmp)
return {
"userId": data["userId"],
"nextIndex": next_idx,
"userCardList": card_list[start_idx:end_idx]
"userCardList": card_list[start_idx:end_idx],
}
def handle_get_user_charge_api_request(self, data: Dict) -> Dict:
user_charges = self.data.item.get_charges(data["userId"])
if user_charges is None:
return {
"userId": data["userId"],
"length": 0,
"userChargeList": []
}
return {"userId": data["userId"], "length": 0, "userChargeList": []}
user_charge_list = []
for charge in user_charges:
@@ -359,45 +384,46 @@ class Mai2Base:
tmp.pop("id")
tmp.pop("user")
tmp["purchaseDate"] = datetime.strftime(
tmp["purchaseDate"], "%Y-%m-%d %H:%M:%S")
tmp["purchaseDate"], Mai2Constants.DATE_TIME_FORMAT
)
tmp["validDate"] = datetime.strftime(
tmp["validDate"], "%Y-%m-%d %H:%M:%S")
tmp["validDate"], Mai2Constants.DATE_TIME_FORMAT
)
user_charge_list.append(tmp)
return {
"userId": data["userId"],
"length": len(user_charge_list),
"userChargeList": user_charge_list
"userChargeList": user_charge_list,
}
def handle_get_user_item_api_request(self, data: Dict) -> Dict:
kind = int(data["nextIndex"] / 10000000000)
next_idx = int(data["nextIndex"] % 10000000000)
user_items = self.data.item.get_items(data["userId"], kind)
user_item_list = []
next_idx = 0
user_item_list = self.data.item.get_items(data["userId"], kind)
for x in range(next_idx, data["maxCount"]):
try:
user_item_list.append({
"itemKind": user_items[x]["itemKind"],
"itemId": user_items[x]["itemId"],
"stock": user_items[x]["stock"],
"isValid": user_items[x]["isValid"]
})
except IndexError:
items: list[Dict[str, Any]] = []
for i in range(next_idx, len(user_item_list)):
tmp = user_item_list[i]._asdict()
tmp.pop("user")
tmp.pop("id")
items.append(tmp)
if len(items) >= int(data["maxCount"]):
break
if len(user_item_list) == data["maxCount"]:
next_idx = data["nextIndex"] + data["maxCount"] + 1
break
xout = kind * 10000000000 + next_idx + len(items)
if len(items) < int(data["maxCount"]):
next_idx = 0
else:
next_idx = xout
return {
"userId": data["userId"],
"nextIndex": next_idx,
"itemKind": kind,
"userItemList": user_item_list
"userItemList": items,
}
def handle_get_user_character_api_request(self, data: Dict) -> Dict:
@@ -479,21 +505,12 @@ class Mai2Base:
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"])
if user_courses is None:
return {
"userId": data["userId"],
"nextIndex": 0,
"userCourseList": []
}
return {"userId": data["userId"], "nextIndex": 0, "userCourseList": []}
course_list = []
for course in user_courses:
@@ -502,11 +519,7 @@ class Mai2Base:
tmp.pop("id")
course_list.append(tmp)
return {
"userId": data["userId"],
"nextIndex": 0,
"userCourseList": course_list
}
return {"userId": data["userId"], "nextIndex": 0, "userCourseList": course_list}
def handle_get_user_portrait_api_request(self, data: Dict) -> Dict:
# No support for custom pfps
@@ -514,96 +527,103 @@ class Mai2Base:
def handle_get_user_friend_season_ranking_api_request(self, data: Dict) -> Dict:
friend_season_ranking = self.data.item.get_friend_season_ranking(data["userId"])
friend_season_ranking_list = []
next_index = 0
if friend_season_ranking is None:
return {
"userId": data["userId"],
"nextIndex": 0,
"userFriendSeasonRankingList": [],
}
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"],
}
)
except:
friend_season_ranking_list = []
next_idx = int(data["nextIndex"])
max_ct = int(data["maxCount"])
for x in range(next_idx, len(friend_season_ranking)):
tmp = friend_season_ranking[x]._asdict()
tmp.pop("user")
tmp.pop("id")
tmp["recordDate"] = datetime.strftime(
tmp["recordDate"], f"{Mai2Constants.DATE_TIME_FORMAT}.0"
)
friend_season_ranking_list.append(tmp)
if len(friend_season_ranking_list) >= max_ct:
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"]
):
next_index = data["maxCount"] + data["nextIndex"]
if len(friend_season_ranking) >= next_idx + max_ct:
next_idx += max_ct
else:
next_idx = 0
return {
"userId": data["userId"],
"nextIndex": next_index,
"nextIndex": next_idx,
"userFriendSeasonRankingList": friend_season_ranking_list,
}
def handle_get_user_map_api_request(self, data: Dict) -> Dict:
maps = self.data.item.get_maps(data["userId"])
map_list = []
next_index = 0
if maps is None:
return {
"userId": data["userId"],
"nextIndex": 0,
"userMapList": [],
}
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"],
}
)
except:
map_list = []
next_idx = int(data["nextIndex"])
max_ct = int(data["maxCount"])
for x in range(next_idx, len(maps)):
tmp = maps[x]._asdict()
tmp.pop("user")
tmp.pop("id")
map_list.append(tmp)
if len(map_list) >= max_ct:
break
# We're capped and still have some left to go
if (
len(map_list) == data["maxCount"]
and len(maps) > data["maxCount"] + data["nextIndex"]
):
next_index = data["maxCount"] + data["nextIndex"]
if len(maps) >= next_idx + max_ct:
next_idx += max_ct
else:
next_idx = 0
return {
"userId": data["userId"],
"nextIndex": next_index,
"nextIndex": next_idx,
"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"])
login_bonus_list = []
next_index = 0
if login_bonuses is None:
return {
"userId": data["userId"],
"nextIndex": 0,
"userLoginBonusList": [],
}
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"],
}
)
except:
login_bonus_list = []
next_idx = int(data["nextIndex"])
max_ct = int(data["maxCount"])
for x in range(next_idx, len(login_bonuses)):
tmp = login_bonuses[x]._asdict()
tmp.pop("user")
tmp.pop("id")
login_bonus_list.append(tmp)
if len(login_bonus_list) >= max_ct:
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"]
):
next_index = data["maxCount"] + data["nextIndex"]
if len(login_bonuses) >= next_idx + max_ct:
next_idx += max_ct
else:
next_idx = 0
return {
"userId": data["userId"],
"nextIndex": next_index,
"nextIndex": next_idx,
"userLoginBonusList": login_bonus_list,
}
@@ -629,5 +649,5 @@ class Mai2Base:
return {
"userId": data["userId"],
"nextIndex": next_index,
"userMusicList": [{"userMusicDetailList": music_detail_list}]
"userMusicList": [{"userMusicDetailList": music_detail_list}],
}

View File

@@ -30,14 +30,16 @@ class Mai2Constants:
VER_MAIMAI_DX_SPLASH_PLUS = 3
VER_MAIMAI_DX_UNIVERSE = 4
VER_MAIMAI_DX_UNIVERSE_PLUS = 5
VER_MAIMAI_DX_FESTIVAL = 6
VERSION_STRING = (
"maimai Delux",
"maimai Delux PLUS",
"maimai Delux Splash",
"maimai Delux Splash PLUS",
"maimai Delux Universe",
"maimai Delux Universe PLUS",
"maimai DX",
"maimai DX PLUS",
"maimai DX Splash",
"maimai DX Splash PLUS",
"maimai DX Universe",
"maimai DX Universe PLUS",
"maimai DX Festival"
)
@classmethod

31
titles/mai2/festival.py Normal file
View File

@@ -0,0 +1,31 @@
from typing import Dict
from core.config import CoreConfig
from titles.mai2.universeplus import Mai2UniversePlus
from titles.mai2.const import Mai2Constants
from titles.mai2.config import Mai2Config
class Mai2Festival(Mai2UniversePlus):
def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None:
super().__init__(cfg, game_cfg)
self.version = Mai2Constants.VER_MAIMAI_DX_FESTIVAL
def handle_cm_get_user_preview_api_request(self, data: Dict) -> Dict:
user_data = super().handle_cm_get_user_preview_api_request(data)
# hardcode lastDataVersion for CardMaker 1.36
user_data["lastDataVersion"] = "1.30.00"
return user_data
def handle_user_login_api_request(self, data: Dict) -> Dict:
user_login = super().handle_user_login_api_request(data)
# useless?
user_login["Bearer"] = "ARTEMiSTOKEN"
return user_login
def handle_get_user_recommend_rate_music_api_request(self, data: Dict) -> Dict:
return {"userId": data["userId"], "userRecommendRateMusicIdList": []}
def handle_get_user_recommend_select_music_api_request(self, data: Dict) -> Dict:
return {"userId": data["userId"], "userRecommendSelectionMusicIdList": []}

View File

@@ -10,6 +10,7 @@ from os import path
from typing import Tuple
from core.config import CoreConfig
from core.utils import Utils
from titles.mai2.config import Mai2Config
from titles.mai2.const import Mai2Constants
from titles.mai2.base import Mai2Base
@@ -18,6 +19,7 @@ from titles.mai2.splash import Mai2Splash
from titles.mai2.splashplus import Mai2SplashPlus
from titles.mai2.universe import Mai2Universe
from titles.mai2.universeplus import Mai2UniversePlus
from titles.mai2.festival import Mai2Festival
class Mai2Servlet:
@@ -30,12 +32,13 @@ class Mai2Servlet:
)
self.versions = [
Mai2Base(core_cfg, self.game_cfg),
Mai2Plus(core_cfg, self.game_cfg),
Mai2Splash(core_cfg, self.game_cfg),
Mai2SplashPlus(core_cfg, self.game_cfg),
Mai2Universe(core_cfg, self.game_cfg),
Mai2UniversePlus(core_cfg, self.game_cfg),
Mai2Base,
Mai2Plus,
Mai2Splash,
Mai2SplashPlus,
Mai2Universe,
Mai2UniversePlus,
Mai2Festival
]
self.logger = logging.getLogger("mai2")
@@ -97,6 +100,7 @@ class Mai2Servlet:
url_split = url_path.split("/")
internal_ver = 0
endpoint = url_split[len(url_split) - 1]
client_ip = Utils.get_ip_addr(request)
if version < 105: # 1.0
internal_ver = Mai2Constants.VER_MAIMAI_DX
@@ -108,8 +112,10 @@ class Mai2Servlet:
internal_ver = Mai2Constants.VER_MAIMAI_DX_SPLASH_PLUS
elif version >= 120 and version < 125: # Universe
internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE
elif version >= 125: # Universe Plus
elif version >= 125 and version < 130: # Universe Plus
internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS
elif version >= 130: # Festival
internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL
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
@@ -128,25 +134,30 @@ class Mai2Servlet:
req_data = json.loads(unzip)
self.logger.info(f"v{version} {endpoint} request - {req_data}")
self.logger.info(
f"v{version} {endpoint} request from {client_ip}"
)
self.logger.debug(req_data)
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
handler_cls = self.versions[internal_ver](self.core_cfg, self.game_cfg)
if not hasattr(self.versions[internal_ver], func_to_find):
if not hasattr(handler_cls, func_to_find):
self.logger.warning(f"Unhandled v{version} request {endpoint}")
return zlib.compress(b'{"returnCode": 1}')
resp = {"returnCode": 1}
try:
handler = getattr(self.versions[internal_ver], func_to_find)
resp = handler(req_data)
else:
try:
handler = getattr(handler_cls, func_to_find)
resp = handler(req_data)
except Exception as e:
self.logger.error(f"Error handling v{version} method {endpoint} - {e}")
return zlib.compress(b'{"stat": "0"}')
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}
self.logger.info(f"Response {resp}")
self.logger.debug(f"Response {resp}")
return zlib.compress(json.dumps(resp, ensure_ascii=False).encode("utf-8"))

View File

@@ -71,12 +71,12 @@ map = Table(
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("map_id", Integer, nullable=False),
Column("mapId", 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"),
Column("isLock", Boolean, nullable=False, server_default="0"),
Column("isClear", Boolean, nullable=False, server_default="0"),
Column("isComplete", Boolean, nullable=False, server_default="0"),
UniqueConstraint("user", "mapId", name="mai2_item_map_uk"),
mysql_charset="utf8mb4",
)
@@ -89,11 +89,11 @@ login_bonus = Table(
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("bonus_id", Integer, nullable=False),
Column("bonusId", 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"),
Column("isCurrent", Boolean, nullable=False, server_default="0"),
Column("isComplete", Boolean, nullable=False, server_default="0"),
UniqueConstraint("user", "bonusId", name="mai2_item_login_bonus_uk"),
mysql_charset="utf8mb4",
)
@@ -106,13 +106,15 @@ friend_season_ranking = Table(
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("season_id", Integer, nullable=False),
Column("seasonId", Integer, nullable=False),
Column("point", Integer, nullable=False),
Column("rank", Integer, nullable=False),
Column("reward_get", Boolean, nullable=False),
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"),
Column("rewardGet", Boolean, nullable=False),
Column("userName", String(8), nullable=False),
Column("recordDate", TIMESTAMP, nullable=False),
UniqueConstraint(
"user", "seasonId", "userName", name="mai2_item_friend_season_ranking_uk"
),
mysql_charset="utf8mb4",
)
@@ -293,18 +295,18 @@ class Mai2ItemData(BaseData):
) -> None:
sql = insert(map).values(
user=user_id,
map_id=map_id,
mapId=map_id,
distance=distance,
is_lock=is_lock,
is_clear=is_clear,
is_complete=is_complete,
isLock=is_lock,
isClear=is_clear,
isComplete=is_complete,
)
conflict = sql.on_duplicate_key_update(
distance=distance,
is_lock=is_lock,
is_clear=is_clear,
is_complete=is_complete,
isLock=is_lock,
isClear=is_clear,
isComplete=is_complete,
)
result = self.execute(conflict)
@@ -324,7 +326,7 @@ class Mai2ItemData(BaseData):
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))
sql = map.select(and_(map.c.user == user_id, map.c.mapId == map_id))
result = self.execute(sql)
if result is None:
@@ -341,16 +343,16 @@ class Mai2ItemData(BaseData):
) -> None:
sql = insert(character).values(
user=user_id,
character_id=character_id,
characterId=character_id,
level=level,
awakening=awakening,
use_count=use_count,
useCount=use_count,
)
conflict = sql.on_duplicate_key_update(
level=level,
awakening=awakening,
use_count=use_count,
useCount=use_count,
)
result = self.execute(conflict)
@@ -385,7 +387,25 @@ class Mai2ItemData(BaseData):
result = self.execute(sql)
if result is None:
return None
return result.fetchone()
return result.fetchall()
def put_friend_season_ranking(
self, aime_id: int, friend_season_ranking_data: Dict
) -> Optional[int]:
sql = insert(friend_season_ranking).values(
user=aime_id, **friend_season_ranking_data
)
conflict = sql.on_duplicate_key_update(**friend_season_ranking_data)
result = self.execute(conflict)
if result is None:
self.logger.warn(
f"put_friend_season_ranking: failed to insert",
f"friend_season_ranking! aime_id: {aime_id}"
)
return None
return result.lastrowid
def put_favorite(
self, user_id: int, kind: int, item_id_list: List[int]

View File

@@ -158,6 +158,7 @@ extend = Table(
Column("sortMusicSetting", Integer),
Column("selectedCardList", JSON),
Column("encountMapNpcList", JSON),
Column("playStatusSetting", Integer, server_default="0"),
UniqueConstraint("user", "version", name="mai2_profile_extend_uk"),
mysql_charset="utf8mb4",
)
@@ -178,6 +179,7 @@ option = Table(
Column("slideSpeed", Integer),
Column("touchSpeed", Integer),
Column("tapDesign", Integer),
Column("tapSe", Integer, server_default="0"),
Column("holdDesign", Integer),
Column("slideDesign", Integer),
Column("starType", Integer),
@@ -298,8 +300,8 @@ class Mai2ProfileData(BaseData):
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)
)
and_(detail.c.user == user_id, detail.c.version <= version)
).order_by(detail.c.version.desc())
result = self.execute(sql)
if result is None:
@@ -323,8 +325,8 @@ class Mai2ProfileData(BaseData):
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)
)
and_(ghost.c.user == user_id, ghost.c.version_int <= version)
).order_by(ghost.c.version.desc())
result = self.execute(sql)
if result is None:
@@ -348,8 +350,8 @@ class Mai2ProfileData(BaseData):
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)
)
and_(extend.c.user == user_id, extend.c.version <= version)
).order_by(extend.c.version.desc())
result = self.execute(sql)
if result is None:
@@ -373,8 +375,8 @@ class Mai2ProfileData(BaseData):
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)
)
and_(option.c.user == user_id, option.c.version <= version)
).order_by(option.c.version.desc())
result = self.execute(sql)
if result is None:
@@ -398,8 +400,8 @@ class Mai2ProfileData(BaseData):
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)
)
and_(rating.c.user == user_id, rating.c.version <= version)
).order_by(rating.c.version.desc())
result = self.execute(sql)
if result is None:

View File

@@ -25,6 +25,7 @@ best_score = Table(
Column("syncStatus", Integer),
Column("deluxscoreMax", Integer),
Column("scoreRank", Integer),
Column("extNum1", Integer, server_default="0"),
UniqueConstraint("user", "musicId", "level", name="mai2_score_best_uk"),
mysql_charset="utf8mb4",
)
@@ -143,6 +144,7 @@ playlog = Table(
Column("isNewFree", Boolean),
Column("extNum1", Integer),
Column("extNum2", Integer),
Column("extNum4", Integer, server_default="0"),
Column("trialPlayAchievement", Integer),
mysql_charset="utf8mb4",
)

View File

@@ -16,6 +16,7 @@ event = Table(
Column("eventId", Integer),
Column("type", Integer),
Column("name", String(255)),
Column("startDate", TIMESTAMP, server_default=func.now()),
Column("enabled", Boolean, server_default="1"),
UniqueConstraint("version", "eventId", "type", name="mai2_static_event_uk"),
mysql_charset="utf8mb4",
@@ -108,7 +109,7 @@ class Mai2StaticData(BaseData):
return None
return result.fetchall()
def toggle_game_events(
def toggle_game_event(
self, version: int, event_id: int, toggle: bool
) -> Optional[List]:
sql = event.update(
@@ -118,7 +119,7 @@ class Mai2StaticData(BaseData):
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}"
f"toggle_game_event: Failed to update event! event_id {event_id} toggle {toggle}"
)
return result.last_updated_params()

View File

@@ -1,7 +1,4 @@
from typing import Any, List, Dict
from datetime import datetime, timedelta
import pytz
import json
from typing import Dict
from core.config import CoreConfig
from titles.mai2.universe import Mai2Universe