327 lines
12 KiB
Python
327 lines
12 KiB
Python
from typing import Any, List, Dict
|
|
from datetime import datetime, timedelta
|
|
import json
|
|
|
|
from core.config import CoreConfig
|
|
from titles.wacca.lilyr import WaccaLilyR
|
|
from titles.wacca.config import WaccaConfig
|
|
from titles.wacca.const import WaccaConstants
|
|
|
|
from titles.wacca.handlers import *
|
|
|
|
|
|
class WaccaReverse(WaccaLilyR):
|
|
def __init__(self, cfg: CoreConfig, game_cfg: WaccaConfig) -> None:
|
|
super().__init__(cfg, game_cfg)
|
|
self.version = WaccaConstants.VER_WACCA_REVERSE
|
|
|
|
self.season = 3
|
|
|
|
self.OPTIONS_DEFAULTS["set_nav_id"] = 310001
|
|
self.allowed_stages = [
|
|
(3014, 14),
|
|
(3013, 13),
|
|
(3012, 12),
|
|
(3011, 11),
|
|
(3010, 10),
|
|
(3009, 9),
|
|
(3008, 8),
|
|
(3007, 7),
|
|
(3006, 6),
|
|
(3005, 5),
|
|
(3004, 4),
|
|
(3003, 3),
|
|
(3002, 2),
|
|
(3001, 1),
|
|
# Touhou
|
|
(210001, 0),
|
|
(210002, 0),
|
|
(210003, 0),
|
|
# Final spurt
|
|
(310001, 0),
|
|
(310002, 0),
|
|
(310003, 0),
|
|
# boss remix
|
|
(310004, 0),
|
|
(310005, 0),
|
|
(310006, 0),
|
|
]
|
|
|
|
def handle_user_status_login_request(self, data: Dict) -> Dict:
|
|
resp = super().handle_user_status_login_request(data)
|
|
resp["params"].append([])
|
|
return resp
|
|
|
|
def handle_user_status_getDetail_request(self, data: Dict) -> Dict:
|
|
req = UserStatusGetDetailRequest(data)
|
|
resp = UserStatusGetDetailResponseV4()
|
|
|
|
profile = self.data.profile.get_profile(req.userId)
|
|
if profile is None:
|
|
self.logger.warning(f"Unknown profile {req.userId}")
|
|
return resp.make()
|
|
|
|
self.logger.info(f"Get detail for profile {req.userId}")
|
|
user_id = profile["user"]
|
|
|
|
profile_scores = self.data.score.get_best_scores(user_id)
|
|
profile_items = self.data.item.get_items(user_id)
|
|
profile_song_unlocks = self.data.item.get_song_unlocks(user_id)
|
|
profile_options = self.data.profile.get_options(user_id)
|
|
profile_favorites = self.data.profile.get_favorite_songs(user_id)
|
|
profile_gates = self.data.profile.get_gates(user_id)
|
|
profile_bingo = self.data.profile.get_bingo(user_id)
|
|
profile_trophies = self.data.item.get_trophies(user_id)
|
|
profile_tickets = self.data.item.get_tickets(user_id)
|
|
|
|
if profile["gate_tutorial_flags"] is not None:
|
|
for x in profile["gate_tutorial_flags"]:
|
|
resp.gateTutorialFlags.append(GateTutorialFlag(x[0], x[1]))
|
|
|
|
if profile["vip_expire_time"] is None:
|
|
resp.userStatus.vipExpireTime = 0
|
|
|
|
else:
|
|
resp.userStatus.vipExpireTime = int(profile["vip_expire_time"].timestamp())
|
|
|
|
if profile["always_vip"] or self.game_config.mods.always_vip:
|
|
resp.userStatus.vipExpireTime = int(
|
|
(self.srvtime + timedelta(days=31)).timestamp()
|
|
)
|
|
|
|
resp.songUpdateTime = int(profile["last_login_date"].timestamp())
|
|
resp.lastSongInfo = LastSongDetail(
|
|
profile["last_song_id"],
|
|
profile["last_song_difficulty"],
|
|
profile["last_folder_order"],
|
|
profile["last_folder_id"],
|
|
profile["last_song_order"],
|
|
)
|
|
resp.songPlayStatus = [resp.lastSongInfo.lastSongId, 1]
|
|
|
|
resp.userStatus.userId = profile["id"]
|
|
resp.userStatus.username = profile["username"]
|
|
resp.userStatus.xp = profile["xp"]
|
|
resp.userStatus.danLevel = profile["dan_level"]
|
|
resp.userStatus.danType = profile["dan_type"]
|
|
resp.userStatus.wp = profile["wp"]
|
|
resp.userStatus.useCount = profile["login_count"]
|
|
resp.userStatus.loginDays = profile["login_count_days"]
|
|
resp.userStatus.loginConsecutiveDays = profile["login_count_days_consec"]
|
|
resp.userStatus.loginsToday = profile["login_count_today"]
|
|
resp.userStatus.rating = profile["rating"]
|
|
|
|
if self.game_config.mods.infinite_wp:
|
|
resp.userStatus.wp = 999999
|
|
|
|
for fav in profile_favorites:
|
|
resp.favorites.append(fav["song_id"])
|
|
|
|
if profile["friend_view_1"] is not None:
|
|
pass
|
|
if profile["friend_view_2"] is not None:
|
|
pass
|
|
if profile["friend_view_3"] is not None:
|
|
pass
|
|
|
|
resp.seasonalPlayModeCounts.append(
|
|
PlayModeCounts(self.season, 1, profile["playcount_single"])
|
|
)
|
|
resp.seasonalPlayModeCounts.append(
|
|
PlayModeCounts(self.season, 2, profile["playcount_multi_vs"])
|
|
)
|
|
resp.seasonalPlayModeCounts.append(
|
|
PlayModeCounts(self.season, 3, profile["playcount_multi_coop"])
|
|
)
|
|
resp.seasonalPlayModeCounts.append(
|
|
PlayModeCounts(self.season, 4, profile["playcount_stageup"])
|
|
)
|
|
resp.seasonalPlayModeCounts.append(
|
|
PlayModeCounts(self.season, 5, profile["playcount_time_free"])
|
|
)
|
|
|
|
# For some fucking reason if this isn't here time play is disabled
|
|
resp.seasonalPlayModeCounts.append(PlayModeCounts(0, 1, 1))
|
|
|
|
for opt in profile_options:
|
|
resp.options.append(UserOption(opt["opt_id"], opt["value"]))
|
|
|
|
if profile_bingo is not None:
|
|
resp.bingoStatus = BingoDetail(profile_bingo["page_number"])
|
|
for x in profile_bingo["page_progress"]:
|
|
resp.bingoStatus.pageStatus.append(BingoPageStatus(x[0], x[1], x[2]))
|
|
|
|
for gate in self.game_config.gates.enabled_gates:
|
|
added_gate = False
|
|
|
|
for user_gate in profile_gates:
|
|
if user_gate["gate_id"] == gate:
|
|
resp.gateInfo.append(
|
|
GateDetailV2(
|
|
user_gate["gate_id"],
|
|
user_gate["page"],
|
|
user_gate["progress"],
|
|
user_gate["loops"],
|
|
int(user_gate["last_used"].timestamp()),
|
|
user_gate["mission_flag"],
|
|
)
|
|
)
|
|
|
|
resp.seasonInfo.cumulativeGatePts += user_gate["total_points"]
|
|
|
|
added_gate = True
|
|
break
|
|
|
|
if not added_gate:
|
|
resp.gateInfo.append(GateDetailV2(gate))
|
|
|
|
for unlock in profile_song_unlocks:
|
|
for x in range(1, unlock["highest_difficulty"] + 1):
|
|
resp.userItems.songUnlocks.append(
|
|
SongUnlock(
|
|
unlock["song_id"], x, 0, int(unlock["acquire_date"].timestamp())
|
|
)
|
|
)
|
|
|
|
for song in profile_scores:
|
|
resp.seasonInfo.cumulativeScore += song["score"]
|
|
|
|
clear_cts = SongDetailClearCounts(
|
|
song["play_ct"],
|
|
song["clear_ct"],
|
|
song["missless_ct"],
|
|
song["fullcombo_ct"],
|
|
song["allmarv_ct"],
|
|
)
|
|
|
|
grade_cts = SongDetailGradeCountsV2(
|
|
song["grade_d_ct"],
|
|
song["grade_c_ct"],
|
|
song["grade_b_ct"],
|
|
song["grade_a_ct"],
|
|
song["grade_aa_ct"],
|
|
song["grade_aaa_ct"],
|
|
song["grade_s_ct"],
|
|
song["grade_ss_ct"],
|
|
song["grade_sss_ct"],
|
|
song["grade_master_ct"],
|
|
song["grade_sp_ct"],
|
|
song["grade_ssp_ct"],
|
|
song["grade_sssp_ct"],
|
|
)
|
|
|
|
deets = BestScoreDetailV2(song["song_id"], song["chart_id"])
|
|
deets.clearCounts = clear_cts
|
|
deets.clearCountsSeason = clear_cts
|
|
deets.gradeCounts = grade_cts
|
|
deets.score = song["score"]
|
|
deets.bestCombo = song["best_combo"]
|
|
deets.lowestMissCtMaybe = song["lowest_miss_ct"]
|
|
deets.rating = song["rating"]
|
|
|
|
resp.scores.append(deets)
|
|
|
|
for trophy in profile_trophies:
|
|
resp.userItems.trophies.append(
|
|
TrophyItem(
|
|
trophy["trophy_id"],
|
|
trophy["season"],
|
|
trophy["progress"],
|
|
trophy["badge_type"],
|
|
)
|
|
)
|
|
|
|
if self.game_config.mods.infinite_tickets:
|
|
for x in range(5):
|
|
resp.userItems.tickets.append(TicketItem(x, 106002, 0))
|
|
else:
|
|
for ticket in profile_tickets:
|
|
if ticket["expire_date"] is None:
|
|
expire = int((self.srvtime + timedelta(days=30)).timestamp())
|
|
else:
|
|
expire = int(ticket["expire_date"].timestamp())
|
|
|
|
resp.userItems.tickets.append(
|
|
TicketItem(ticket["id"], ticket["ticket_id"], expire)
|
|
)
|
|
|
|
if profile_items:
|
|
for item in profile_items:
|
|
try:
|
|
if item["type"] == WaccaConstants.ITEM_TYPES["icon"]:
|
|
resp.userItems.icons.append(
|
|
IconItem(
|
|
item["item_id"],
|
|
1,
|
|
item["use_count"],
|
|
int(item["acquire_date"].timestamp()),
|
|
)
|
|
)
|
|
|
|
elif item["type"] == WaccaConstants.ITEM_TYPES["navigator"]:
|
|
resp.userItems.navigators.append(
|
|
NavigatorItem(
|
|
item["item_id"],
|
|
1,
|
|
int(item["acquire_date"].timestamp()),
|
|
item["use_count"],
|
|
item["use_count"],
|
|
)
|
|
)
|
|
|
|
else:
|
|
itm_send = GenericItemSend(
|
|
item["item_id"], 1, int(item["acquire_date"].timestamp())
|
|
)
|
|
|
|
if item["type"] == WaccaConstants.ITEM_TYPES["title"]:
|
|
resp.userItems.titles.append(itm_send)
|
|
|
|
elif item["type"] == WaccaConstants.ITEM_TYPES["user_plate"]:
|
|
resp.userItems.plates.append(itm_send)
|
|
|
|
elif item["type"] == WaccaConstants.ITEM_TYPES["touch_effect"]:
|
|
resp.userItems.touchEffect.append(itm_send)
|
|
|
|
elif item["type"] == WaccaConstants.ITEM_TYPES["note_color"]:
|
|
resp.userItems.noteColors.append(itm_send)
|
|
|
|
elif item["type"] == WaccaConstants.ITEM_TYPES["note_sound"]:
|
|
resp.userItems.noteSounds.append(itm_send)
|
|
|
|
except Exception:
|
|
self.logger.error(
|
|
f"{__name__} Failed to load item {item['item_id']} for user {profile['user']}"
|
|
)
|
|
|
|
resp.seasonInfo.level = profile["xp"]
|
|
resp.seasonInfo.wpObtained = profile["wp_total"]
|
|
resp.seasonInfo.wpSpent = profile["wp_spent"]
|
|
resp.seasonInfo.titlesObtained = len(resp.userItems.titles)
|
|
resp.seasonInfo.iconsObtained = len(resp.userItems.icons)
|
|
resp.seasonInfo.noteColorsObtained = len(resp.userItems.noteColors)
|
|
resp.seasonInfo.noteSoundsObtained = len(resp.userItems.noteSounds)
|
|
resp.seasonInfo.platesObtained = len(resp.userItems.plates)
|
|
|
|
return resp.make()
|
|
|
|
def handle_user_status_create_request(self, data: Dict) -> Dict:
|
|
req = UserStatusCreateRequest(data)
|
|
resp = super().handle_user_status_create_request(data)
|
|
|
|
self.data.item.put_item(
|
|
req.aimeId, WaccaConstants.ITEM_TYPES["navigator"], 310001
|
|
) # Added reverse
|
|
self.data.item.put_item(
|
|
req.aimeId, WaccaConstants.ITEM_TYPES["navigator"], 310002
|
|
) # Added reverse
|
|
|
|
self.data.item.put_item(
|
|
req.aimeId, WaccaConstants.ITEM_TYPES["touch_effect"], 312000
|
|
) # Added reverse
|
|
self.data.item.put_item(
|
|
req.aimeId, WaccaConstants.ITEM_TYPES["touch_effect"], 312001
|
|
) # Added reverse
|
|
|
|
return resp
|