forked from Hay1tsme/artemis
chuni: initial verse support
This commit is contained in:
@ -53,7 +53,9 @@ class ChuniBase:
|
||||
if not self.game_cfg.mods.use_login_bonus:
|
||||
return {"returnCode": 1}
|
||||
|
||||
login_bonus_presets = await self.data.static.get_login_bonus_presets(self.version)
|
||||
login_bonus_presets = await self.data.static.get_login_bonus_presets(
|
||||
self.version
|
||||
)
|
||||
|
||||
for preset in login_bonus_presets:
|
||||
# check if a user already has some pogress and if not add the
|
||||
@ -197,15 +199,21 @@ class ChuniBase:
|
||||
|
||||
async def handle_get_game_message_api_request(self, data: Dict) -> Dict:
|
||||
return {
|
||||
"type": data["type"],
|
||||
"length": 1,
|
||||
"gameMessageList": [{
|
||||
"id": 1,
|
||||
"type": 1,
|
||||
"message": f"Welcome to {self.core_cfg.server.name} network!" if not self.game_cfg.server.news_msg else self.game_cfg.server.news_msg,
|
||||
"startDate": "2017-12-05 07:00:00.0",
|
||||
"endDate": "2099-12-31 00:00:00.0"
|
||||
}]
|
||||
"type": data["type"],
|
||||
"length": 1,
|
||||
"gameMessageList": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": 1,
|
||||
"message": (
|
||||
f"Welcome to {self.core_cfg.server.name} network!"
|
||||
if not self.game_cfg.server.news_msg
|
||||
else self.game_cfg.server.news_msg
|
||||
),
|
||||
"startDate": "2017-12-05 07:00:00.0",
|
||||
"endDate": "2099-12-31 00:00:00.0",
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
async def handle_get_game_ranking_api_request(self, data: Dict) -> Dict:
|
||||
@ -217,7 +225,10 @@ class ChuniBase:
|
||||
|
||||
async def handle_get_game_setting_api_request(self, data: Dict) -> Dict:
|
||||
# if reboot start/end time is not defined use the default behavior of being a few hours ago
|
||||
if self.core_cfg.title.reboot_start_time == "" or self.core_cfg.title.reboot_end_time == "":
|
||||
if (
|
||||
self.core_cfg.title.reboot_start_time == ""
|
||||
or self.core_cfg.title.reboot_end_time == ""
|
||||
):
|
||||
reboot_start = datetime.strftime(
|
||||
datetime.utcnow() + timedelta(hours=6), self.date_time_format
|
||||
)
|
||||
@ -226,15 +237,29 @@ class ChuniBase:
|
||||
)
|
||||
else:
|
||||
# get current datetime in JST
|
||||
current_jst = datetime.now(pytz.timezone('Asia/Tokyo')).date()
|
||||
current_jst = datetime.now(pytz.timezone("Asia/Tokyo")).date()
|
||||
|
||||
# parse config start/end times into datetime
|
||||
reboot_start_time = datetime.strptime(self.core_cfg.title.reboot_start_time, "%H:%M")
|
||||
reboot_end_time = datetime.strptime(self.core_cfg.title.reboot_end_time, "%H:%M")
|
||||
reboot_start_time = datetime.strptime(
|
||||
self.core_cfg.title.reboot_start_time, "%H:%M"
|
||||
)
|
||||
reboot_end_time = datetime.strptime(
|
||||
self.core_cfg.title.reboot_end_time, "%H:%M"
|
||||
)
|
||||
|
||||
# offset datetimes with current date/time
|
||||
reboot_start_time = reboot_start_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo'))
|
||||
reboot_end_time = reboot_end_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo'))
|
||||
reboot_start_time = reboot_start_time.replace(
|
||||
year=current_jst.year,
|
||||
month=current_jst.month,
|
||||
day=current_jst.day,
|
||||
tzinfo=pytz.timezone("Asia/Tokyo"),
|
||||
)
|
||||
reboot_end_time = reboot_end_time.replace(
|
||||
year=current_jst.year,
|
||||
month=current_jst.month,
|
||||
day=current_jst.day,
|
||||
tzinfo=pytz.timezone("Asia/Tokyo"),
|
||||
)
|
||||
|
||||
# create strings for use in gameSetting
|
||||
reboot_start = reboot_start_time.strftime(self.date_time_format)
|
||||
@ -255,6 +280,7 @@ class ChuniBase:
|
||||
"isDumpUpload": "false",
|
||||
"isAou": "false",
|
||||
}
|
||||
|
||||
async def handle_get_user_activity_api_request(self, data: Dict) -> Dict:
|
||||
user_activity_list = await self.data.profile.get_profile_activity(
|
||||
data["userId"], data["kind"]
|
||||
@ -285,7 +311,7 @@ class ChuniBase:
|
||||
rows = await self.data.item.get_characters(
|
||||
user_id, limit=max_ct + 1, offset=next_idx
|
||||
)
|
||||
|
||||
|
||||
if rows is None or len(rows) == 0:
|
||||
return {
|
||||
"userId": user_id,
|
||||
@ -335,7 +361,7 @@ class ChuniBase:
|
||||
return {
|
||||
"userId": data["userId"],
|
||||
"length": 0,
|
||||
"userRecentPlayerList": [], # playUserId, playUserName, playDate, friendPoint
|
||||
"userRecentPlayerList": [], # playUserId, playUserName, playDate, friendPoint
|
||||
}
|
||||
|
||||
async def handle_get_user_course_api_request(self, data: Dict) -> Dict:
|
||||
@ -421,15 +447,9 @@ class ChuniBase:
|
||||
p = await self.data.profile.get_rival(data["rivalId"])
|
||||
if p is None:
|
||||
return {}
|
||||
userRivalData = {
|
||||
"rivalId": p.user,
|
||||
"rivalName": p.userName
|
||||
}
|
||||
return {
|
||||
"userId": data["userId"],
|
||||
"userRivalData": userRivalData
|
||||
}
|
||||
|
||||
userRivalData = {"rivalId": p.user, "rivalName": p.userName}
|
||||
return {"userId": data["userId"], "userRivalData": userRivalData}
|
||||
|
||||
async def handle_get_user_rival_music_api_request(self, data: Dict) -> Dict:
|
||||
user_id = int(data["userId"])
|
||||
rival_id = int(data["rivalId"])
|
||||
@ -459,18 +479,25 @@ class ChuniBase:
|
||||
|
||||
# note that itertools.groupby will only work on sorted keys, which is already sorted by
|
||||
# the query in get_scores
|
||||
for music_id, details_iter in itertools.groupby(music_details, key=lambda x: x["musicId"]):
|
||||
for music_id, details_iter in itertools.groupby(
|
||||
music_details, key=lambda x: x["musicId"]
|
||||
):
|
||||
details: list[dict[Any, Any]] = [
|
||||
{"level": d["level"], "scoreMax": d["scoreMax"]}
|
||||
for d in details_iter
|
||||
{"level": d["level"], "scoreMax": d["scoreMax"]} for d in details_iter
|
||||
]
|
||||
|
||||
music_list.append({"musicId": music_id, "length": len(details), "userRivalMusicDetailList": details})
|
||||
music_list.append(
|
||||
{
|
||||
"musicId": music_id,
|
||||
"length": len(details),
|
||||
"userRivalMusicDetailList": details,
|
||||
}
|
||||
)
|
||||
returned_music_details_count += len(details)
|
||||
|
||||
if len(music_list) >= max_ct:
|
||||
break
|
||||
|
||||
|
||||
# if we returned fewer PBs than we originally asked for from the database, that means
|
||||
# we queried for the PBs of max_ct + 1 songs.
|
||||
if returned_music_details_count < len(rows):
|
||||
@ -485,7 +512,7 @@ class ChuniBase:
|
||||
"nextIndex": next_idx,
|
||||
"userRivalMusicList": music_list,
|
||||
}
|
||||
|
||||
|
||||
async def handle_get_user_favorite_item_api_request(self, data: Dict) -> Dict:
|
||||
user_id = int(data["userId"])
|
||||
next_idx = int(data["nextIndex"])
|
||||
@ -571,7 +598,9 @@ class ChuniBase:
|
||||
|
||||
async def handle_get_user_login_bonus_api_request(self, data: Dict) -> Dict:
|
||||
user_id = data["userId"]
|
||||
user_login_bonus = await self.data.item.get_all_login_bonus(user_id, self.version)
|
||||
user_login_bonus = await self.data.item.get_all_login_bonus(
|
||||
user_id, self.version
|
||||
)
|
||||
# ignore the loginBonus request if its disabled in config
|
||||
if user_login_bonus is None or not self.game_cfg.mods.use_login_bonus:
|
||||
return {"userId": user_id, "length": 0, "userLoginBonusList": []}
|
||||
@ -621,7 +650,7 @@ class ChuniBase:
|
||||
rows = await self.data.score.get_scores(
|
||||
user_id, limit=max_ct + 1, offset=next_idx
|
||||
)
|
||||
|
||||
|
||||
if rows is None or len(rows) == 0:
|
||||
return {
|
||||
"userId": user_id,
|
||||
@ -636,7 +665,9 @@ class ChuniBase:
|
||||
|
||||
# note that itertools.groupby will only work on sorted keys, which is already sorted by
|
||||
# the query in get_scores
|
||||
for _music_id, details_iter in itertools.groupby(music_details, key=lambda x: x["musicId"]):
|
||||
for _music_id, details_iter in itertools.groupby(
|
||||
music_details, key=lambda x: x["musicId"]
|
||||
):
|
||||
details: list[dict[Any, Any]] = []
|
||||
|
||||
for d in details_iter:
|
||||
@ -650,14 +681,14 @@ class ChuniBase:
|
||||
|
||||
if len(music_list) >= max_ct:
|
||||
break
|
||||
|
||||
|
||||
# if we returned fewer PBs than we originally asked for from the database, that means
|
||||
# we queried for the PBs of max_ct + 1 songs.
|
||||
if returned_music_details_count < len(rows):
|
||||
next_idx += max_ct
|
||||
else:
|
||||
next_idx = -1
|
||||
|
||||
|
||||
return {
|
||||
"userId": user_id,
|
||||
"length": len(music_list),
|
||||
@ -687,7 +718,9 @@ class ChuniBase:
|
||||
return bytes([ord(c) for c in src]).decode("utf-8")
|
||||
|
||||
async def handle_get_user_preview_api_request(self, data: Dict) -> Dict:
|
||||
profile = await self.data.profile.get_profile_preview(data["userId"], self.version)
|
||||
profile = await self.data.profile.get_profile_preview(
|
||||
data["userId"], self.version
|
||||
)
|
||||
if profile is None:
|
||||
return None
|
||||
profile_character = await self.data.item.get_character(
|
||||
@ -729,7 +762,9 @@ class ChuniBase:
|
||||
}
|
||||
|
||||
async def handle_get_user_recent_rating_api_request(self, data: Dict) -> Dict:
|
||||
recent_rating_list = await self.data.profile.get_profile_recent_rating(data["userId"])
|
||||
recent_rating_list = await self.data.profile.get_profile_recent_rating(
|
||||
data["userId"]
|
||||
)
|
||||
if recent_rating_list is None:
|
||||
return {
|
||||
"userId": data["userId"],
|
||||
@ -762,7 +797,7 @@ class ChuniBase:
|
||||
profile = await self.data.profile.get_profile_data(data["userId"], self.version)
|
||||
|
||||
if profile is None:
|
||||
return {"userId": data["userId"], "teamId": 0}
|
||||
return {"userId": data["userId"], "teamId": 0}
|
||||
|
||||
if profile and profile["teamId"]:
|
||||
# Get team by id
|
||||
@ -787,7 +822,7 @@ class ChuniBase:
|
||||
"teamId": team_id,
|
||||
"teamRank": team_rank,
|
||||
"teamName": team_name,
|
||||
"assaultTimeRate": 1, # TODO: Figure out assaultTime, which might be team point boost?
|
||||
"assaultTimeRate": 1, # TODO: Figure out assaultTime, which might be team point boost?
|
||||
"userTeamPoint": {
|
||||
"userId": data["userId"],
|
||||
"teamId": team_id,
|
||||
@ -796,7 +831,7 @@ class ChuniBase:
|
||||
"aggrDate": data["playDate"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
async def handle_get_team_course_setting_api_request(self, data: Dict) -> Dict:
|
||||
return {
|
||||
"userId": data["userId"],
|
||||
@ -805,7 +840,9 @@ class ChuniBase:
|
||||
"teamCourseSettingList": [],
|
||||
}
|
||||
|
||||
async def handle_get_team_course_setting_api_request_proto(self, data: Dict) -> Dict:
|
||||
async def handle_get_team_course_setting_api_request_proto(
|
||||
self, data: Dict
|
||||
) -> Dict:
|
||||
return {
|
||||
"userId": data["userId"],
|
||||
"length": 1,
|
||||
@ -820,11 +857,11 @@ class ChuniBase:
|
||||
"teamCourseMusicList": [
|
||||
{"track": 184, "type": 1, "level": 3, "selectLevel": -1},
|
||||
{"track": 184, "type": 1, "level": 3, "selectLevel": -1},
|
||||
{"track": 184, "type": 1, "level": 3, "selectLevel": -1}
|
||||
{"track": 184, "type": 1, "level": 3, "selectLevel": -1},
|
||||
],
|
||||
"teamCourseRankingInfoList": [],
|
||||
"recodeDate": "2099-12-31 11:59:99.0",
|
||||
"isPlayed": False
|
||||
"isPlayed": False,
|
||||
}
|
||||
],
|
||||
}
|
||||
@ -834,7 +871,7 @@ class ChuniBase:
|
||||
"userId": data["userId"],
|
||||
"length": 0,
|
||||
"nextIndex": -1,
|
||||
"teamCourseRuleList": []
|
||||
"teamCourseRuleList": [],
|
||||
}
|
||||
|
||||
async def handle_get_team_course_rule_api_request_proto(self, data: Dict) -> Dict:
|
||||
@ -849,7 +886,7 @@ class ChuniBase:
|
||||
"damageMiss": 1,
|
||||
"damageAttack": 1,
|
||||
"damageJustice": 1,
|
||||
"damageJusticeC": 1
|
||||
"damageJusticeC": 1,
|
||||
}
|
||||
],
|
||||
}
|
||||
@ -860,7 +897,7 @@ class ChuniBase:
|
||||
|
||||
if int(user_id) & 0x1000000000001 == 0x1000000000001:
|
||||
place_id = int(user_id) & 0xFFFC00000000
|
||||
|
||||
|
||||
self.logger.info("Guest play from place ID %d, ignoring.", place_id)
|
||||
return {"returnCode": "1"}
|
||||
|
||||
@ -882,7 +919,9 @@ class ChuniBase:
|
||||
)
|
||||
|
||||
if "userGameOption" in upsert:
|
||||
await self.data.profile.put_profile_option(user_id, upsert["userGameOption"][0])
|
||||
await self.data.profile.put_profile_option(
|
||||
user_id, upsert["userGameOption"][0]
|
||||
)
|
||||
|
||||
if "userGameOptionEx" in upsert:
|
||||
await self.data.profile.put_profile_option_ex(
|
||||
@ -929,33 +968,41 @@ class ChuniBase:
|
||||
for playlog in upsert["userPlaylogList"]:
|
||||
# convert the player names to utf-8
|
||||
if playlog["playedUserName1"] is not None:
|
||||
playlog["playedUserName1"] = self.read_wtf8(playlog["playedUserName1"])
|
||||
playlog["playedUserName1"] = self.read_wtf8(
|
||||
playlog["playedUserName1"]
|
||||
)
|
||||
if playlog["playedUserName2"] is not None:
|
||||
playlog["playedUserName2"] = self.read_wtf8(playlog["playedUserName2"])
|
||||
playlog["playedUserName2"] = self.read_wtf8(
|
||||
playlog["playedUserName2"]
|
||||
)
|
||||
if playlog["playedUserName3"] is not None:
|
||||
playlog["playedUserName3"] = self.read_wtf8(playlog["playedUserName3"])
|
||||
playlog["playedUserName3"] = self.read_wtf8(
|
||||
playlog["playedUserName3"]
|
||||
)
|
||||
await self.data.score.put_playlog(user_id, playlog, self.version)
|
||||
|
||||
if "userTeamPoint" in upsert:
|
||||
team_points = upsert["userTeamPoint"]
|
||||
try:
|
||||
for tp in team_points:
|
||||
if tp["teamId"] != '65535':
|
||||
if tp["teamId"] != "65535":
|
||||
# Fetch the current team data
|
||||
current_team = await self.data.profile.get_team_by_id(tp["teamId"])
|
||||
current_team = await self.data.profile.get_team_by_id(
|
||||
tp["teamId"]
|
||||
)
|
||||
|
||||
# Calculate the new teamPoint
|
||||
new_team_point = int(tp["teamPoint"]) + current_team["teamPoint"]
|
||||
new_team_point = (
|
||||
int(tp["teamPoint"]) + current_team["teamPoint"]
|
||||
)
|
||||
|
||||
# Prepare the data to update
|
||||
team_data = {
|
||||
"teamPoint": new_team_point
|
||||
}
|
||||
team_data = {"teamPoint": new_team_point}
|
||||
|
||||
# Update the team data
|
||||
await self.data.profile.update_team(tp["teamId"], team_data)
|
||||
except:
|
||||
pass # Probably a better way to catch if the team is not set yet (new profiles), but let's just pass
|
||||
pass # Probably a better way to catch if the team is not set yet (new profiles), but let's just pass
|
||||
if "userMapAreaList" in upsert:
|
||||
for map_area in upsert["userMapAreaList"]:
|
||||
await self.data.item.put_map_area(user_id, map_area)
|
||||
@ -973,22 +1020,28 @@ class ChuniBase:
|
||||
await self.data.item.put_login_bonus(
|
||||
user_id, self.version, login["presetId"], isWatched=True
|
||||
)
|
||||
|
||||
if "userRecentPlayerList" in upsert: # TODO: Seen in Air, maybe implement sometime
|
||||
|
||||
if (
|
||||
"userRecentPlayerList" in upsert
|
||||
): # TODO: Seen in Air, maybe implement sometime
|
||||
for rp in upsert["userRecentPlayerList"]:
|
||||
pass
|
||||
|
||||
for rating_type in {"userRatingBaseList", "userRatingBaseHotList", "userRatingBaseNextList"}:
|
||||
for rating_type in {
|
||||
"userRatingBaseList",
|
||||
"userRatingBaseHotList",
|
||||
"userRatingBaseNextList",
|
||||
}:
|
||||
if rating_type not in upsert:
|
||||
continue
|
||||
|
||||
|
||||
await self.data.profile.put_profile_rating(
|
||||
user_id,
|
||||
self.version,
|
||||
rating_type,
|
||||
upsert[rating_type],
|
||||
)
|
||||
|
||||
|
||||
# added in LUMINOUS
|
||||
if "userCMissionList" in upsert:
|
||||
for cmission in upsert["userCMissionList"]:
|
||||
@ -1003,7 +1056,9 @@ class ChuniBase:
|
||||
)
|
||||
|
||||
for progress in cmission["userCMissionProgressList"]:
|
||||
await self.data.item.put_cmission_progress(user_id, mission_id, progress)
|
||||
await self.data.item.put_cmission_progress(
|
||||
user_id, mission_id, progress
|
||||
)
|
||||
|
||||
if "userNetBattleData" in upsert:
|
||||
net_battle = upsert["userNetBattleData"][0]
|
||||
@ -1035,10 +1090,20 @@ class ChuniBase:
|
||||
added_ids = music_ids - keep_ids
|
||||
|
||||
for fav_id in deleted_ids:
|
||||
await self.data.item.delete_favorite_music(user_id, self.version, fav_id)
|
||||
|
||||
await self.data.item.delete_favorite_music(
|
||||
user_id, self.version, fav_id
|
||||
)
|
||||
|
||||
for fav_id in added_ids:
|
||||
await self.data.item.put_favorite_music(user_id, self.version, fav_id)
|
||||
|
||||
# added in CHUNITHM VERSE
|
||||
if "userUnlockChallengeList" in upsert:
|
||||
for unlock_challenge in upsert["userUnlockChallengeList"]:
|
||||
await self.data.item.put_unlock_challenge(
|
||||
user_id, self.version, unlock_challenge
|
||||
)
|
||||
|
||||
|
||||
return {"returnCode": "1"}
|
||||
|
||||
|
Reference in New Issue
Block a user