artemis/titles/idac/season2.py

3317 lines
123 KiB
Python
Raw Normal View History

2023-10-01 01:54:23 +00:00
from datetime import datetime, timedelta
import os
from random import choice, randint
2023-10-01 01:54:23 +00:00
from typing import Any, Dict, List
import json
import logging
import asyncio
2023-10-01 01:54:23 +00:00
from core.config import CoreConfig
2024-01-09 17:52:53 +00:00
from core.utils import Utils
2023-10-01 01:54:23 +00:00
from titles.idac.const import IDACConstants
from titles.idac.config import IDACConfig
from titles.idac.base import IDACBase
class IDACSeason2(IDACBase):
def __init__(self, core_cfg: CoreConfig, game_cfg: IDACConfig) -> None:
super().__init__(core_cfg, game_cfg)
self.version = IDACConstants.VER_IDAC_SEASON_2
# load timerelease numbers from config
self.timerelease_no = self.game_config.timerelease.timerelease_no
self.timerelease_avatar_gacha_no = (
self.game_config.timerelease.timerelease_avatar_gacha_no
)
# load the user configured play stamps (up to 3)
2023-10-01 01:54:23 +00:00
self.stamp_info = []
if self.game_config.stamp.enable:
for stamp in self.game_config.stamp.enabled_stamps:
if not os.path.exists(f"./titles/idac/data/stamp/{stamp}.json"):
2023-10-01 01:54:23 +00:00
self.logger.warning(f"Stamp {stamp} is enabled but does not exist!")
continue
2023-10-19 17:04:06 +00:00
with open(
f"./titles/idac/data/stamp/{stamp}.json", encoding="UTF-8"
2023-10-19 17:04:06 +00:00
) as f:
2023-10-01 01:54:23 +00:00
self.logger.debug(f"Loading stamp {stamp}")
2023-10-19 17:04:06 +00:00
self.stamp_info.append(self._fix_dates(json.load(f)))
2023-10-01 01:54:23 +00:00
# load the user configured time trials (only one)
2023-10-01 01:54:23 +00:00
self.timetrial_event = {}
self.timetrial_event_id = None
if self.game_config.timetrial.enable:
timetrial = self.game_config.timetrial.enabled_timetrial
if timetrial is not None:
if not os.path.exists(f"./titles/idac/data/timetrial/{timetrial}.json"):
self.logger.warning(
f"Timetrial {timetrial} is enabled but does not exist!"
)
else:
self.logger.debug(f"Loading timetrial {timetrial}")
2023-10-19 17:04:06 +00:00
with open(
f"./titles/idac/data/timetrial/{timetrial}.json",
encoding="UTF-8",
) as f:
self.timetrial_event = self._fix_dates(json.load(f))
2023-10-01 01:54:23 +00:00
# required for saving
2023-10-19 17:04:06 +00:00
self.timetrial_event_id = self.timetrial_event.get(
"timetrial_event_id"
)
2023-10-01 01:54:23 +00:00
# load the user configured round event (only one)
asyncio.create_task(self._load_round_event())
# load the user configured battle gifts (only one)
self.battle_gift_event = None
if self.game_config.battle_gift.enable:
battle_gift = self.game_config.battle_gift.enabled_battle_gift
if battle_gift is not None:
if not os.path.exists(
f"./titles/idac/data/battle_gift/{battle_gift}.json"
):
self.logger.warning(
f"Battle gift {battle_gift} is enabled but does not exist!"
)
else:
self.logger.debug(f"Loading battle gift {battle_gift}")
with open(
f"./titles/idac/data/battle_gift/{battle_gift}.json",
encoding="UTF-8",
) as f:
self.battle_gift_event = self._fix_dates(json.load(f))
async def _load_round_event(self):
self.round_event_id = 0
self.round_event = []
self.last_round_event_id = 0
self.last_round_event = []
self.last_round_event_ranking = []
if self.game_config.round_event.enable:
# Load current round event
round = self.game_config.round_event.enabled_round
if round is not None:
path = f"./titles/idac/data/rounds/season{self.version+1}/{round}.json"
if not os.path.exists(path):
self.logger.warning(f"Round info {round} is enabled but json file does not exist!")
else:
with open(path, encoding="UTF-8") as f:
self.logger.debug(f"Loading round info {round}...")
tmp = json.load(f)
self.round_event_id = await self.data.rounds._try_load_round_event(tmp["round_event_id"], self.version, tmp)
self.round_event.append(self._fix_dates(tmp))
self.logger.debug(f"Loaded round id for database: {self.round_event_id}...")
# Load last round event
round = self.game_config.round_event.last_round
if round is not None:
path = f"./titles/idac/data/rounds/season{self.version+1}/{round}.json"
if not os.path.exists(path):
self.logger.warning(f"Round info {round} is enabled but json file does not exist!")
else:
with open(path, encoding="UTF-8") as f:
self.logger.debug(f"Loading round info {round}...")
tmp = json.load(f)
self.last_round_event_id = await self.data.rounds._try_load_round_event(tmp["round_event_id"], self.version, tmp)
self.last_round_event.append(tmp)
self.logger.debug(f"Loaded round id for database: {self.last_round_event_id}...")
# Load top five of last round event
# class LastRoundEventRanking(BaseModel):
# round_rank: int
# round_point: int
# round_play_count: int
ranking = await self.data.rounds.get_round_top_five(self.last_round_event_id)
if ranking is not None:
rank_profile = {
"round_rank": 0,
"round_point": 0,
"round_play_count": 0,
"username": "DUMMY",
"country": 9,
"store": self.core_cfg.server.name,
"online_battle_rank": 0,
"mytitle_id": 0,
"mytitle_effect_id": 0,
"car_data": [],
"user_avatar": []
}
for user in ranking:
# get the user's profile
p = await self.data.profile.get_profile(user["user"], self.version)
user_data = p._asdict()
arcade = await self.data.arcade.get_arcade(user_data["store"])
user_data["store_name"] = (
self.core_cfg.server.name if arcade is None else arcade["name"]
)
rank_profile["username"] = user_data["username"]
rank_profile["country"] = user_data["country"]
rank_profile["store"] = user_data["store_name"]
rank_profile["mytitle_id"] = user_data["mytitle_id"]
rank_profile["mytitle_effect_id"] = user_data["mytitle_effect_id"]
# get the user's avatar
a = await self.data.profile.get_profile_avatar(user["user"])
avatar_data = a._asdict()
del avatar_data["id"]
del avatar_data["user"]
rank_profile["user_avatar"] = avatar_data
# get the user's rank
r = await self.data.profile.get_profile_rank(user_id, self.version)
rank_data = r._asdict()
del rank_data["id"]
del rank_data["user"]
del rank_data["version"]
rank_profile["online_battle_rank"] = rank_data["online_battle_rank"]
# get the user's car
cars = await self.data.item.get_cars(self.version, user_id, only_pickup=True)
fulltune_count = 0
total_car_parts_count = 0
car_data = []
for car in cars:
tmp = car._asdict()
del tmp["id"]
del tmp["user"]
del tmp["version"]
car_data.append(tmp)
rank_profile["car_data"] = car_data
# get round info
ri = await self.data.rounds.get_round_info_by_id(user["user"], self.last_round_event_id)
if ri is not None:
ri = ri._asdict()
rank_profile["round_rank"] = user["find_in_set_1"]
rank_profile["round_point"] = ri["point"]
rank_profile["round_play_count"] = ri["count"]
self.last_round_event_ranking.append(rank_profile)
2024-01-09 19:42:17 +00:00
async def handle_alive_get_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
# 1 = success, 0 = failed
"server_status": 1,
"force_reboot_time": int(datetime.now().timestamp()) - 86400,
}
def _fix_dates(self, input: dict):
"""
Fix "start_dt" and "end_dt" dates in a JSON file.
"""
output = {}
self.logger.debug(f"Fixing dates in {type(input)}")
for key, value in input.items():
if key in {"start_dt", "end_dt"}:
if isinstance(value, str):
value = int(datetime.strptime(value, "%Y-%m-%d").timestamp())
output[key] = value
return output
def _special_story_type(self, headers: Dict):
version = headers["device_version"]
ver_str = version.replace(".", "")[:3]
# 4 = touhou project, 5 = hatsune miku
return {
"150": 4,
"170": 5
}.get(ver_str, 0)
2023-10-01 01:54:23 +00:00
2024-01-09 19:42:17 +00:00
async def handle_boot_getconfigdata_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
"""
category:
1 = D Coin
3 = Car Dressup Token
5 = Avatar Dressup Token
6 = Tachometer
7 = Aura
8 = Aura Color
9 = Avatar Face
10 = Avatar Eye
11 = Avatar Mouth
12 = Avatar Hair
13 = Avatar Glasses
14 = Avatar Face accessories
15 = Avatar Body
18 = Avatar Background
21 = Chat Stamp
22 = Keychain
24 = Title
25 = FullTune Ticket
26 = Paper Cup
27 = BGM
28 = Drifting Text
31 = Start Menu BG
32 = Car Color/Paint
33 = Aura Level
34 = FullTune Ticket Fragment
35 = Underneon Lights
2023-10-01 01:54:23 +00:00
"""
version = headers["device_version"]
ver_str = version.replace(".", "")[:3]
2024-01-09 17:52:53 +00:00
if self.core_cfg.server.is_using_proxy:
2024-01-09 17:41:47 +00:00
domain_api_game = f"http://{self.core_cfg.server.hostname}/{ver_str}/"
2023-10-01 01:54:23 +00:00
else:
2024-01-09 17:52:53 +00:00
domain_api_game = f"http://{self.core_cfg.server.hostname}:{Utils.get_title_port(self.core_cfg)}/{ver_str}/"
2023-10-01 01:54:23 +00:00
# sets the special mode data if the version supports the special mode
special_mode_data = {}
special_story_type = self._special_story_type(headers)
if special_story_type != 0:
special_mode_data = {
"start_dt": int(
datetime.strptime("2023-01-01", "%Y-%m-%d").timestamp()
),
"end_dt": int(datetime.strptime("2029-01-01", "%Y-%m-%d").timestamp()),
"story_type": special_story_type
}
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"free_continue_enable": 1,
"free_continue_new": 1,
"free_continue_play": 1,
"difference_time_to_jp": 0,
# has to match the game asset version to show theory of street
"asset_version": "1",
"optional_version": "1",
"disconnect_offset": 0,
"boost_balance_version": "0",
"time_release_number": "0",
"play_stamp_enable": 1,
"play_stamp_bonus_coin": 1,
"gacha_chara_needs": 1,
"both_win_system_control": 0,
"subcard_system_congrol": 0,
2023-10-01 01:54:23 +00:00
"server_maintenance_start_hour": 0,
"server_maintenance_start_minutes": 0,
"server_maintenance_end_hour": 0,
"server_maintenance_end_minutes": 0,
"domain_api_game": domain_api_game,
2024-01-09 17:41:47 +00:00
"domain_matching": f"{domain_api_game}initiald-matching/",
2024-01-09 08:07:04 +00:00
"domain_echo1": f"{self.core_cfg.server.hostname}:{self.game_config.server.echo1}",
2024-01-09 17:41:47 +00:00
"domain_echo2": f"{self.core_cfg.server.hostname}:{self.game_config.server.echo1}",
2024-01-09 08:07:04 +00:00
"domain_ping": f"{self.core_cfg.server.hostname}",
"battle_gift_event_master": (
[self.battle_gift_event] if self.battle_gift_event else []
),
# online battle round event
"round_event": self.round_event,
"last_round_event": self.last_round_event,
"last_round_event_ranking": self.last_round_event_ranking,
2023-10-01 01:54:23 +00:00
"round_event_exp": [],
"stamp_info": self.stamp_info,
# 0 = use default data, 1+ = server version of timereleasedata response
"timerelease_no": self.timerelease_no,
2023-10-01 01:54:23 +00:00
# 0 = use default data, 1+ = server version of gachadata response
"timerelease_avatar_gacha_no": self.timerelease_avatar_gacha_no,
# takover reward from other games such as 1=IDZ and 3=SWDC
"takeover_reward": [
{
"takeover_reward_type": 0,
"takeover_reward_data": [
{"reward_no": 1, "reward_category": 1, "reward_type": 5000},
{"reward_no": 2, "reward_category": 25, "reward_type": 1},
],
},
{
"takeover_reward_type": 1,
"takeover_reward_data": [
{"reward_no": 1, "reward_category": 15, "reward_type": 82},
{"reward_no": 1, "reward_category": 15, "reward_type": 190},
{"reward_no": 2, "reward_category": 3, "reward_type": 2},
{"reward_no": 2, "reward_category": 5, "reward_type": 2},
{"reward_no": 3, "reward_category": 3, "reward_type": 3},
{"reward_no": 3, "reward_category": 5, "reward_type": 3},
{"reward_no": 4, "reward_category": 3, "reward_type": 5},
{"reward_no": 4, "reward_category": 5, "reward_type": 5},
{"reward_no": 5, "reward_category": 15, "reward_type": 104},
{"reward_no": 5, "reward_category": 15, "reward_type": 212},
],
},
{
"takeover_reward_type": 2,
"takeover_reward_data": [
{"reward_no": 1, "reward_category": 24, "reward_type": 4052},
{"reward_no": 2, "reward_category": 24, "reward_type": 4053},
{"reward_no": 3, "reward_category": 24, "reward_type": 4054},
{"reward_no": 4, "reward_category": 24, "reward_type": 4055},
{"reward_no": 5, "reward_category": 24, "reward_type": 4056},
{"reward_no": 6, "reward_category": 24, "reward_type": 4057},
{"reward_no": 7, "reward_category": 24, "reward_type": 4058},
],
},
{
"takeover_reward_type": 3,
"takeover_reward_data": [
{"reward_no": 1, "reward_category": 15, "reward_type": 81},
{"reward_no": 1, "reward_category": 15, "reward_type": 189},
{"reward_no": 2, "reward_category": 25, "reward_type": 1},
{"reward_no": 2, "reward_category": 15, "reward_type": 103},
{"reward_no": 2, "reward_category": 15, "reward_type": 211},
],
},
],
2023-10-01 01:54:23 +00:00
"subcard_judge": [
{
"condition_id": 1,
"lower_rank": 1,
"higher_rank": 7,
"condition_start": 17,
"condition_end": 20,
"calc": 3,
},
{
"condition_id": 2,
"lower_rank": 1,
"higher_rank": 15,
"condition_start": 10,
"condition_end": 10,
"calc": 20,
},
{
"condition_id": 3,
"lower_rank": 11,
"higher_rank": 15,
"condition_start": 80,
"condition_end": 89,
"calc": 7,
},
{
"condition_id": 3,
"lower_rank": 11,
"higher_rank": 15,
"condition_start": 90,
"condition_end": 100,
"calc": 10,
},
{
"condition_id": 3,
"lower_rank": 1,
"higher_rank": 15,
"condition_start": 0,
"condition_end": 40,
"calc": -100,
},
{
"condition_id": 1,
"lower_rank": 1,
"higher_rank": 15,
"condition_start": 21,
"condition_end": 24,
"calc": 7,
},
{
"condition_id": 1,
"lower_rank": 1,
"higher_rank": 15,
"condition_start": 25,
"condition_end": 25,
"calc": 10,
},
{
"condition_id": 3,
"lower_rank": 16,
"higher_rank": 20,
"condition_start": 70,
"condition_end": 89,
"calc": 6,
},
{
"condition_id": 3,
"lower_rank": 16,
"higher_rank": 20,
"condition_start": 90,
"condition_end": 100,
"calc": 12,
},
{
"condition_id": 3,
"lower_rank": 16,
"higher_rank": 20,
"condition_start": 0,
"condition_end": 50,
"calc": -100,
},
],
"special_promote": [
{"counter": 50, "online_rank_id": 8},
{"counter": 200, "online_rank_id": 16},
{"counter": 255, "online_rank_id": 21},
2023-10-01 01:54:23 +00:00
],
"matching_id": 0,
2023-10-01 01:54:23 +00:00
"matching_group": [
{"group_id": 1, "group_percent": 30},
{"group_id": 2, "group_percent": 50},
{"group_id": 3, "group_percent": 100},
2023-10-01 01:54:23 +00:00
],
"timetrial_disp_date": int(
datetime.strptime("2023-10-01", "%Y-%m-%d").timestamp()
),
# price for every car
"buy_car_need_cash": 5000,
# number of buyable shop/customization time limits
"time_extension_limit": 5,
2023-10-01 01:54:23 +00:00
"collabo_id": 0,
"driver_debut_end_date": int(
datetime.strptime("2029-01-01", "%Y-%m-%d").timestamp()
),
"online_battle_param1": 0,
"online_battle_param2": 0,
"online_battle_param3": 0,
"online_battle_param4": 0,
"online_battle_param5": 0,
"online_battle_param6": 2,
"online_battle_param7": 0,
"online_battle_param8": 3900,
"theory_open_version": "1.30.00",
"theory_close_version": "9.99.99",
2024-04-15 18:22:45 +00:00
# unlocks the version specific special mode
"special_mode_data": special_mode_data,
2023-10-01 01:54:23 +00:00
"timetrial_event_data": self.timetrial_event,
"number_lottery_data": [
{
"m_number_lottery_win_number_no": 10,
"m_number_lottery_schedule_no": 1,
"win_number": 0,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 11,
"m_number_lottery_schedule_no": 1,
"win_number": 1111,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 12,
"m_number_lottery_schedule_no": 1,
"win_number": 2222,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 13,
"m_number_lottery_schedule_no": 1,
"win_number": 3333,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 14,
"m_number_lottery_schedule_no": 1,
"win_number": 4444,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 15,
"m_number_lottery_schedule_no": 1,
"win_number": 5555,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 16,
"m_number_lottery_schedule_no": 1,
"win_number": 6666,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 17,
"m_number_lottery_schedule_no": 1,
"win_number": 7777,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 18,
"m_number_lottery_schedule_no": 1,
"win_number": 8888,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
{
"m_number_lottery_win_number_no": 19,
"m_number_lottery_schedule_no": 1,
"win_number": 9999,
"reward_category": 34,
"reward_type": 1,
"end_dt": 0,
},
],
2023-10-01 01:54:23 +00:00
}
2024-01-09 19:42:17 +00:00
async def handle_boot_bookkeep_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
pass
2024-01-09 19:42:17 +00:00
async def handle_boot_getgachadata_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
"""
Reward category types:
9: Face
10: Eye
11: Mouth
12: Hair
13: Glasses
14: Face accessories
15: Body
18: Background
"""
2023-10-19 17:04:06 +00:00
with open("./titles/idac/data/avatarGacha.json", encoding="UTF-8") as f:
2023-10-01 01:54:23 +00:00
avatar_gacha_data = json.load(f)
# avatar_gacha_data = {
# "status_code": "0",
# "avatar_gacha_data": [
# {
# "avatar_gacha_id": 0,
# "avatar_gacha_nm": "Standard",
# "gacha_type": 0,
# "save_filename": "0",
# "use_ticket_cnt": 1,
# "start_dt": int(
# datetime.strptime("2019-01-01", "%Y-%m-%d").timestamp()
# ),
# "end_dt": int(
# datetime.strptime("2029-01-01", "%Y-%m-%d").timestamp()
# ),
# "gacha_reward": [
# {
# "reward_id": 117,
# "reward_type": 118,
# "reward_category": 18,
# "rate": 1000,
# "pickup_flag": 0,
# },
# ],
# }
# ],
# }
self.logger.debug(
f'Available avatar gacha items: {len(avatar_gacha_data["avatar_gacha_data"][0]["gacha_reward"])}'
)
return avatar_gacha_data
2024-01-09 19:42:17 +00:00
async def handle_boot_gettimereleasedata_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
"""
timerelease chapter:
2024-06-12 22:08:23 +00:00
1 = Story: 1, 2, 3, 4, 5, 6, 7, 8, 9, 19 (Chapter 10), (29 Chapter 11)
2023-10-01 01:54:23 +00:00
2 = MF Ghost: 10, 11, 12, 13, 14, 15
3 = Bunta: 15, 16, 17, 18, 20, 21, 21, 22
2024-06-12 22:08:23 +00:00
4 = Touch Project Special Event: 23, 24, 25, 26, 27, 28
5 = Hatsune Miku Special Event: 36, 37, 38
2023-10-01 01:54:23 +00:00
"""
path = "./titles/idac/data/"
# 1.00.00 is default
device_version_data = headers.get("device_version", "1.00.00")
device_version = int(device_version_data.replace(".", "")[:-2])
timerelease_filename = f"timeRelease_v{device_version:04d}"
timerelease_path = f"{path}{timerelease_filename}.json"
# if the file doesn't exist, try to find the next lowest version
if not os.path.exists(timerelease_path):
while device_version > 100:
device_version -= 1
timerelease_filename = f"timeRelease_v{device_version:04d}"
timerelease_path = f"{path}{timerelease_filename}.json"
# if the file exists, break out of the loop
if os.path.exists(timerelease_path):
break
self.logger.debug(f"Using time release file: {timerelease_filename}")
# load the time release data
with open(f"{path}{timerelease_filename}.json") as f:
time_release_data = json.load(f)
return time_release_data
2024-01-09 19:42:17 +00:00
async def handle_advertise_getrankingdata_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
best_data = []
for last_update in data.get("last_update_date"):
course_id = last_update.get("course_id")
2024-01-09 19:42:17 +00:00
ranking = await self.data.item.get_time_trial_ranking_by_course(
2023-10-01 01:54:23 +00:00
self.version, course_id
)
ranking_data = []
for i, rank in enumerate(ranking):
user_id = rank["user"]
# get the username, country and store from the profile
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
arcade = await self.data.arcade.get_arcade(profile["store"])
if arcade is None:
arcade = {}
arcade["name"] = self.core_cfg.server.name
2023-10-01 01:54:23 +00:00
# should never happen
if profile is None:
continue
ranking_data.append(
{
"course_id": course_id,
"rank": i + 1,
"username": profile["username"],
"value": rank["goal_time"],
# gat the store name from the profile
"store": arcade["name"],
2023-10-01 01:54:23 +00:00
# get the country id from the profile, 9 is JPN
"country": profile["country"],
2023-10-01 01:54:23 +00:00
"style_car_id": rank["style_car_id"],
# convert the datetime to a timestamp
2023-10-01 01:54:23 +00:00
"play_dt": int(rank["play_dt"].timestamp()),
"section_time_1": rank["section_time_1"],
"section_time_2": rank["section_time_2"],
"section_time_3": rank["section_time_3"],
"section_time_4": rank["section_time_4"],
"mission": rank["mission"],
}
)
best_data.append(
{
"course_id": course_id,
"ranking_data": ranking_data,
}
)
return {
"status_code": "0",
"national_best_data": best_data,
"shop_best_data": best_data,
"rank_management_flag": 0,
}
def _is_valid_version(self, db_version: str, cl_version: str) -> bool:
if len(db_version) < 7 or len(cl_version) < 7:
return False
# convert the trings to int and compare
db_version = int(db_version.replace(".", "")[:7])
cl_version = int(cl_version.replace(".", "")[:7])
return cl_version >= db_version
2023-10-01 01:54:23 +00:00
2024-01-09 19:42:17 +00:00
async def handle_login_checklock_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = data["id"]
access_code = data["accesscode"]
is_new_player = 0
2023-10-01 01:54:23 +00:00
# check that the user_id from access_code matches the user_id
2024-01-22 21:35:43 +00:00
if user_id == await self.data.card.get_user_id_from_card(access_code):
lock_result = 1
# check if an IDAC profile already exists
2024-01-09 19:42:17 +00:00
p = await self.data.profile.get_profile(user_id, self.version)
is_new_player = 1 if p is None else 0
db_version = p["device_version"] if p is not None else "1.00.00"
cl_version = headers["device_version"]
# check if the client version is valid
if not self._is_valid_version(db_version, cl_version):
lock_result = 2
else:
lock_result = 0
user_id = ""
2023-10-01 01:54:23 +00:00
# other: in use
return {
"status_code": "0",
# 0 = already in use, 1 = good, 2 = too new
"lock_result": lock_result,
2023-10-01 01:54:23 +00:00
"lock_date": int(datetime.now().timestamp()),
"daily_play": 1,
"session": f"{user_id}",
"shared_security_key": "a",
"session_procseq": "a",
"new_player": is_new_player,
"server_status": 1,
}
2024-01-09 19:42:17 +00:00
async def handle_login_unlock_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"lock_result": 1,
}
2024-01-09 19:42:17 +00:00
async def handle_login_relock_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"lock_result": 1,
"lock_date": int(datetime.now().timestamp()),
}
2024-01-09 19:42:17 +00:00
async def handle_login_guestplay_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
# TODO
pass
2024-01-09 19:42:17 +00:00
async def _generate_story_data(self, user_id: int) -> Dict:
stories = await self.data.item.get_stories(user_id)
2023-10-01 01:54:23 +00:00
story_data = []
for s in stories:
chapter_id = s["chapter"]
2024-01-09 19:42:17 +00:00
episodes = await self.data.item.get_story_episodes(user_id, chapter_id)
2023-10-01 01:54:23 +00:00
episode_data = []
for e in episodes:
episode_id = e["episode"]
2024-01-09 19:42:17 +00:00
difficulties = await self.data.item.get_story_episode_difficulties(
2023-10-01 01:54:23 +00:00
user_id, episode_id
)
difficulty_data = []
for d in difficulties:
difficulty_data.append(
{
"difficulty": d["difficulty"],
"play_count": d["play_count"],
"clear_count": d["clear_count"],
"play_status": d["play_status"],
"play_score": d["play_score"],
}
)
episode_data.append(
{
"episode": e["episode"],
"play_status": e["play_status"],
"difficulty_data": difficulty_data,
}
)
story_data.append(
{
"story_type": s["story_type"],
"chapter": s["chapter"],
"loop_count": s["loop_count"],
"episode_data": episode_data,
}
)
return story_data
async def _generate_special_data(self, user_id: int, headers: Dict) -> Dict:
# 4 = touhou project, 5 = hatsune miku
2024-03-12 17:20:32 +00:00
specials = await self.data.item.get_best_challenges_by_vs_type(
user_id, story_type=self._special_story_type(headers)
2024-03-12 17:20:32 +00:00
)
2023-10-01 01:54:23 +00:00
special_data = []
for s in specials:
special_data.append(
{
"story_type": s["story_type"],
"vs_type": s["vs_type"],
"max_clear_lv": s["max_clear_lv"],
"last_play_lv": s["last_play_lv"],
# change to last_play_course_id?
"last_play_course_id": s["course_id"],
}
)
return special_data
2024-01-09 19:42:17 +00:00
async def _generate_challenge_data(self, user_id: int) -> Dict:
2023-10-01 01:54:23 +00:00
# challenge mode (Bunta challenge only right now)
2024-01-09 19:42:17 +00:00
challenges = await self.data.item.get_best_challenges_by_vs_type(
2023-10-01 01:54:23 +00:00
user_id, story_type=3
)
challenge_data = []
for c in challenges:
challenge_data.append(
{
"story_type": c["story_type"],
"vs_type": c["vs_type"],
"max_clear_lv": c["max_clear_lv"],
"last_play_lv": c["last_play_lv"],
# change to last_play_course_id?
"last_play_course_id": c["course_id"],
"play_count": c["play_count"],
}
)
return challenge_data
2024-01-09 19:42:17 +00:00
async def _save_stock_data(self, user_id: int, stock_data: Dict):
2023-10-01 01:54:23 +00:00
updated_stock_data = {}
for k, v in stock_data.items():
if v != "":
updated_stock_data[k] = v
if updated_stock_data:
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_stock(
2023-10-01 01:54:23 +00:00
user_id, self.version, updated_stock_data
)
2024-03-12 17:20:32 +00:00
async def _update_vs_info(self, user_id: int, battle_mode: int, data: Dict) -> Dict:
vs_info = await self.data.item.get_vs_info_by_mode(user_id, battle_mode)
2023-11-20 04:42:28 +00:00
if vs_info is not None:
2024-01-06 14:01:14 +00:00
vs_info = vs_info._asdict()
2024-01-08 02:38:35 +00:00
del vs_info["id"]
del vs_info["user"]
2023-11-20 04:40:32 +00:00
vs_info["invalid"] = vs_info["invalid"] + data.get("result")
2024-03-12 17:20:32 +00:00
vs_info["str_now"] = (
vs_info["str_now"] + data.get("win_flg")
if data.get("win_flg") == 1
else 0
)
vs_info["str"] = (
vs_info["str"]
if vs_info["str"] > vs_info["str_now"]
else vs_info["str_now"]
)
2023-11-20 04:40:32 +00:00
vs_info["lose_now"] += 1 if data.get("win_flg") == 0 else 0
vs_info["vs_history"] = data.get("vs_history")
2023-11-20 04:40:32 +00:00
vs_info["break_count"] += data.get("break_count")
vs_info["break_penalty_flag"] = data.get("break_penalty_flag")
2024-03-12 17:20:32 +00:00
await self.data.item.put_vs_info(user_id, battle_mode, vs_info)
2024-01-06 14:01:14 +00:00
vs_info["vs_cnt"] = 0
vs_info["vs_win"] = 0
vs_info["vsinfo_course_data"] = []
2024-03-12 17:20:32 +00:00
vs_courses_info = await self.data.item.get_vs_course_infos_by_mode(
user_id, battle_mode
)
2023-11-20 04:40:32 +00:00
course_not_exists = True
2024-03-12 17:20:32 +00:00
2024-01-06 14:01:14 +00:00
if vs_courses_info is not None:
for course in vs_courses_info:
course = course._asdict()
2024-01-08 02:39:31 +00:00
del course["id"]
del course["user"]
2024-01-08 02:38:35 +00:00
2024-01-06 14:01:14 +00:00
if course["course_id"] == data.get("course_id"):
course["vs_cnt"] += 1
course["vs_win"] += data.get("win_flg")
vs_info["vs_cnt"] += course["vs_cnt"]
vs_info["vs_win"] += course["vs_win"]
2024-03-12 17:20:32 +00:00
await self.data.item.put_vs_course_info(
user_id, battle_mode, course
)
2024-01-06 14:01:14 +00:00
course_not_exists = False
else:
vs_info["vs_cnt"] += course["vs_cnt"]
vs_info["vs_win"] += course["vs_win"]
2024-03-12 17:20:32 +00:00
vs_info["vsinfo_course_data"].append(course)
2023-11-20 04:40:32 +00:00
if course_not_exists:
course = {}
course["course_id"] = data.get("course_id")
course["vs_cnt"] = 1
course["vs_win"] = data.get("win_flg")
2024-01-06 14:01:14 +00:00
vs_info["vs_cnt"] += course["vs_cnt"]
vs_info["vs_win"] += course["vs_win"]
2023-11-20 04:40:32 +00:00
vs_info["vsinfo_course_data"].append(course)
2024-03-12 17:20:32 +00:00
await self.data.item.put_vs_course_info(user_id, battle_mode, course)
2023-11-20 04:40:32 +00:00
else:
vs_info = {
"battle_mode": battle_mode,
# "vs_cnt": 1,
# "vs_win": data.get("win_flg"),
2023-11-20 04:40:32 +00:00
"invalid": data.get("result"),
"str": data.get("win_flg"),
"str_now": data.get("win_flg"),
"lose_now": 1 if data.get("win_flg") == 0 else 0,
"vs_history": data.get("vs_history"),
2023-11-20 04:40:32 +00:00
"break_count": data.get("break_count"),
2023-11-20 04:50:23 +00:00
"break_penalty_flag": data.get("break_penalty_flag"),
# "vsinfo_course_data": [
# {
# "course_id": data.get("course_id"),
# "vs_cnt": 1,
# "vs_win": data.get("win_flg")
# }
# ],
2024-01-06 14:01:14 +00:00
}
2024-03-12 17:20:32 +00:00
await self.data.item.put_vs_info(user_id, battle_mode, vs_info)
2024-01-06 14:01:14 +00:00
course_info = {
"course_id": data.get("course_id"),
"vs_cnt": 1,
2024-03-12 17:20:32 +00:00
"vs_win": data.get("win_flg"),
2023-11-20 04:40:32 +00:00
}
2024-03-12 17:20:32 +00:00
await self.data.item.put_vs_course_info(user_id, battle_mode, course_info)
2024-01-06 14:01:14 +00:00
vs_info["vs_cnt"] = 1
vs_info["vs_win"] = data.get("win_flg")
vs_info["vsinfo_course_data"] = []
vs_info["vsinfo_course_data"].append(course_info)
2024-03-12 17:20:32 +00:00
2023-11-20 04:40:32 +00:00
vs_info["course_select_priority"] = data.get("course_select_priority")
return vs_info
async def _update_round_info(self, user_id: int, round_event_id: int, point: int, win: int) -> Dict:
# get the round info data from database
round_info = []
ri = await self.data.rounds.get_round_info_by_id(user_id, round_event_id)
if ri is not None:
tmp = ri._asdict()
del tmp["id"]
# calculate new round points and info
tmp["point"] = 0 if tmp["point"] + point < 1 else tmp["point"] + point
tmp["count"] += 1
tmp["win"] += win
tmp["play_dt"] = datetime.now()
# update players round info
await self.data.rounds.put_round_event(user_id, round_event_id, tmp)
del tmp["play_dt"]
# get players new round ranking
r = await self.data.rounds.get_round_rank_by_id(user_id, round_event_id)
round_ranking = r._asdict()
tmp["rank"] = round_ranking["find_in_set_1"] if tmp["point"] > 0 else 0
# TODO: get players historical earned points
tmp["total_round_point"] = 0
round_info.append(tmp)
else:
# new player of now-going round event
tmp = {}
tmp["point"] = 0 if point < 1 else point
tmp["count"] = 1
tmp["win"] = win
tmp["play_dt"] = datetime.now()
await self.data.rounds.put_round_event(user_id, round_event_id, tmp)
del tmp["play_dt"]
r = await self.data.rounds.get_round_rank_by_id(user_id, round_event_id)
round_ranking = r._asdict()
tmp["rank"] = round_ranking["find_in_set_1"] if tmp["point"] > 0 else 0
# TODO: get players historical earned points
tmp["total_round_point"] = 0
round_info.append(tmp)
return round_info
def _choose_gift_id(self) -> Dict:
gift_data = self.battle_gift_event["gift_data"]
# calculate the total_rate based on the first_distribution_rate
total_rate = sum(gift["first_distribution_rate"] for gift in gift_data)
# randomly choose a number between 1 and the total rate
rand_num = randint(1, total_rate)
cumulative_rate = 0
for gift in gift_data:
# if the random number is less than the cumulative rate, return the gift
cumulative_rate += gift["first_distribution_rate"]
if rand_num <= cumulative_rate:
return gift
2024-01-09 19:42:17 +00:00
async def handle_user_getdata_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = int(headers["session"])
# get the user's profile, can never be None
2024-01-09 19:42:17 +00:00
p = await self.data.profile.get_profile(user_id, self.version)
2023-10-01 01:54:23 +00:00
user_data = p._asdict()
2024-01-09 19:42:17 +00:00
arcade = await self.data.arcade.get_arcade(user_data["store"])
2023-10-01 01:54:23 +00:00
del user_data["id"]
del user_data["user"]
del user_data["version"]
user_data["id"] = user_id
user_data["store_name"] = (
self.core_cfg.server.name if arcade is None else arcade["name"]
)
2023-10-01 01:54:23 +00:00
user_data["last_play_date"] = int(user_data["last_play_date"].timestamp())
user_data["create_date"] = int(user_data["create_date"].timestamp())
# get the user's rank
2024-01-09 19:42:17 +00:00
r = await self.data.profile.get_profile_rank(user_id, self.version)
2023-10-01 01:54:23 +00:00
rank_data = r._asdict()
del rank_data["id"]
del rank_data["user"]
del rank_data["version"]
# add the mode_rank_data to the user_data
user_data["mode_rank_data"] = rank_data
# get the user's avatar
2024-01-09 19:42:17 +00:00
a = await self.data.profile.get_profile_avatar(user_id)
2023-10-01 01:54:23 +00:00
avatar_data = a._asdict()
del avatar_data["id"]
del avatar_data["user"]
# get the user's stock
2024-01-09 19:42:17 +00:00
s = await self.data.profile.get_profile_stock(user_id, self.version)
2023-10-01 01:54:23 +00:00
stock_data = s._asdict()
del stock_data["id"]
del stock_data["user"]
del stock_data["version"]
# get the user's config
2024-01-09 19:42:17 +00:00
c = await self.data.profile.get_profile_config(user_id)
2023-10-01 01:54:23 +00:00
config_data = c._asdict()
del config_data["id"]
del config_data["user"]
config_data["id"] = config_data.pop("config_id")
# get the user's ticket
2024-01-09 19:42:17 +00:00
tickets: list = await self.data.item.get_tickets(user_id)
2023-10-01 01:54:23 +00:00
"""
ticket_id:
3 = Car Dressup Points
5 = Avatar Dressup Points
25 = Full Tune Tickets
34 = Full Tune Fragments
"""
ticket_data = []
for ticket in tickets:
ticket_data.append(
{
"ticket_id": ticket["ticket_id"],
"ticket_cnt": ticket["ticket_cnt"],
}
)
# get the users'd round data
round_info = []
ri = await self.data.rounds.get_round_info_by_id(user_id, self.round_event_id)
if ri is not None:
r = await self.data.rounds.get_round_rank_by_id(user_id, self.round_event_id)
round_ranking = r._asdict()
tmp = ri._asdict()
del tmp["id"]
del tmp["user"]
del tmp["round_id"]
del tmp["play_dt"]
tmp["rank"] = round_ranking["find_in_set_1"]
# TODO: calculate this
tmp["total_round_point"] = 0
round_info.append(tmp)
2023-10-01 01:54:23 +00:00
# get the user's course, required for the "course proeficiency"
2024-01-09 19:42:17 +00:00
courses = await self.data.item.get_courses(user_id)
2023-10-01 01:54:23 +00:00
course_data = []
for course in courses:
course_data.append(
{
"id": 0, # no clue, always 0?
"course_id": course["course_id"],
"run_counts": course["run_counts"],
# "course proeficiency" in exp points
"skill_level_exp": course["skill_level_exp"],
}
)
# get the profile theory data
theory_data = {}
2024-01-09 19:42:17 +00:00
theory = await self.data.profile.get_profile_theory(user_id, self.version)
2023-10-01 01:54:23 +00:00
if theory is not None:
theory_data = theory._asdict()
del theory_data["id"]
del theory_data["user"]
del theory_data["version"]
# get the users theory course data
theory_course_data = []
2024-01-09 19:42:17 +00:00
theory_courses = await self.data.item.get_theory_courses(user_id)
2023-10-01 01:54:23 +00:00
for course in theory_courses:
tmp = course._asdict()
del tmp["id"]
del tmp["user"]
tmp["update_dt"] = int(tmp["update_dt"].timestamp())
theory_course_data.append(tmp)
# get the users theory partner data
theory_partner_data = []
2024-01-09 19:42:17 +00:00
theory_partners = await self.data.item.get_theory_partners(user_id)
2023-10-01 01:54:23 +00:00
for partner in theory_partners:
tmp = partner._asdict()
del tmp["id"]
del tmp["user"]
theory_partner_data.append(tmp)
# get the users theory running pram data
theory_running_pram_data = []
2024-01-09 19:42:17 +00:00
theory_running = await self.data.item.get_theory_running(user_id)
2023-10-01 01:54:23 +00:00
for running in theory_running:
tmp = running._asdict()
del tmp["id"]
del tmp["user"]
theory_running_pram_data.append(tmp)
# get the users vs info data
vs_info_data = []
2024-03-12 17:20:32 +00:00
vs_info = await self.data.item.get_vs_infos(user_id)
2024-01-06 14:01:14 +00:00
if vs_info is not None:
for vs in vs_info:
vs = vs._asdict()
2024-03-12 17:20:32 +00:00
vs_courses_infos = await self.data.item.get_vs_course_infos_by_mode(
user_id, vs["battle_mode"]
)
2024-01-06 14:01:14 +00:00
total_vs_win = 0
total_vs_cnt = 0
courses_info = []
if vs_courses_infos is not None:
for course in vs_courses_infos:
2024-01-06 14:01:14 +00:00
tmp = course._asdict()
del tmp["id"]
del tmp["user"]
del tmp["battle_mode"]
2024-03-12 17:20:32 +00:00
2024-01-06 14:01:14 +00:00
total_vs_win += tmp["vs_win"]
total_vs_cnt += tmp["vs_cnt"]
2024-03-12 17:20:32 +00:00
2024-01-06 14:01:14 +00:00
courses_info.append(tmp)
vs_info_data.append(
{
"battle_mode": vs["battle_mode"],
"vs_cnt": total_vs_cnt,
"vs_win": total_vs_win,
"invalid": vs["invalid"],
"str": vs["str"],
"str_now": vs["str_now"],
"lose_now": vs["lose_now"],
"vs_history": vs["vs_history"],
2024-01-06 14:01:14 +00:00
"course_select_priority": 0,
"break_count": vs["break_count"],
"break_penalty_flag": vs["break_penalty_flag"],
2024-01-06 14:01:14 +00:00
"vsinfo_course_data": courses_info,
}
)
2023-10-01 01:54:23 +00:00
# get the user's car
2024-01-09 19:42:17 +00:00
cars = await self.data.item.get_cars(self.version, user_id, only_pickup=True)
2023-10-01 01:54:23 +00:00
fulltune_count = 0
total_car_parts_count = 0
car_data = []
for car in cars:
tmp = car._asdict()
del tmp["id"]
del tmp["user"]
del tmp["version"]
car_data.append(tmp)
# tune_level of 16 means fully tuned, so add 1 to fulltune_count
if car["tune_level"] >= 16:
fulltune_count += 1
# add the number of car parts to total_car_parts_count?
# total_car_parts_count += tmp["total_car_parts_count"]
car_data.append(tmp)
# update user profile car count
user_data["have_car_cnt"] = len(car_data)
# get the user's play stamps
2024-01-09 19:42:17 +00:00
stamps = await self.data.item.get_stamps(user_id)
2023-10-01 01:54:23 +00:00
stamp_event_data = []
for stamp in stamps:
tmp = stamp._asdict()
del tmp["id"]
del tmp["user"]
now = datetime.now()
# create timestamp for today at 1am
this_day = now.replace(hour=1, minute=0, second=0, microsecond=0)
# check if this_day is greater than or equal to create_date_daily
if this_day >= tmp["create_date_daily"]:
# reset the daily stamp
tmp["create_date_daily"] = now
tmp["daily_bonus"] = 0
# create a timestamp for this monday at 1am
this_monday = now - timedelta(days=now.weekday())
this_monday = this_monday.replace(hour=1, minute=0, second=0, microsecond=0)
# check if this_monday is greater than or equal to create_date_weekly
if this_monday >= tmp["create_date_weekly"]:
# reset the weekly stamp
tmp["create_date_weekly"] = now
tmp["weekly_bonus"] = 0
# update the play stamp in the database
2024-01-09 19:42:17 +00:00
await self.data.item.put_stamp(user_id, tmp)
2023-10-01 01:54:23 +00:00
del tmp["create_date_daily"]
del tmp["create_date_weekly"]
stamp_event_data.append(tmp)
# get the user's timetrial event data
timetrial_event_data = {}
2024-03-12 17:20:32 +00:00
timetrial = await self.data.item.get_timetrial_event(
user_id, self.timetrial_event_id
)
2023-10-01 01:54:23 +00:00
if timetrial is not None:
timetrial_event_data = {
"timetrial_event_id": timetrial["timetrial_event_id"],
"point": timetrial["point"],
}
# check if the battle gift event is active
if self.battle_gift_event:
# get the users battle gifts, for the current active battle gift event
battle_gifts = await self.data.item.get_battle_gifts(
user_id, self.battle_gift_event.get("battle_gift_event_id")
)
if battle_gifts:
# just return all aquired gifts
battle_gift_data = [
{
"first_distribution_flag": 0,
"gift_data": [
{
"gift_id": gift["gift_id"],
# 1 = acquired
"gift_get_status": gift["gift_status"],
}
for gift in battle_gifts
],
}
]
else:
# get a random gift from the active battle gift event
gift_id = self._choose_gift_id()["gift_id"]
# save the battle_gift inside the database
await self.data.item.put_battle_gift(
user_id,
{
"battle_gift_event_id": self.battle_gift_event.get(
"battle_gift_event_id"
),
"gift_id": gift_id,
"gift_status": 1, # aquired
},
)
battle_gift_data = [
{
# trigger the first gift animation
"first_distribution_flag": 1,
"gift_data": [
{
# return a random selected gift_id
"gift_id": gift_id,
# set the status to 2 = new gift
"gift_get_status": 2,
}
],
}
]
# get the tips from the database
tips = await self.data.profile.get_profile_tips(user_id, self.version)
# if there are no tips, create a new one
if tips is None:
await self.data.profile.put_profile_tips(user_id, self.version, {})
# get the tips from the database
tips = await self.data.profile.get_profile_tips(user_id, self.version)
tips_info = tips._asdict()
del tips_info["id"]
del tips_info["user"]
del tips_info["version"]
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"user_base_data": user_data,
"avatar_data": avatar_data,
"pick_up_car_data": car_data,
2024-01-09 19:42:17 +00:00
"story_data": await self._generate_story_data(user_id),
2023-10-01 01:54:23 +00:00
"vsinfo_data": vs_info_data,
"stock_data": stock_data,
"mission_data": {
"id": 0,
"achieve_flag": 0,
"received_flag": 0,
"update_dt": int(datetime.now().timestamp() - 86400),
},
"weekly_mission_data": [],
"course_data": course_data,
"toppatu_event_data": {
"id": 0,
"event_id": 0,
"count1": 0,
"count2": 0,
"count3": 0,
"accept_flag": 0,
},
"event_data": {
"id": 0,
"active_event_id": 0,
"dialog_show_date": int(datetime.now().timestamp() - 86400),
"show_start_dialog_flag": 1,
"show_progress_dialog_flag": 1,
"show_end_dialog_flag": 1,
"end_event_id": 0,
},
"rewards_data": {},
"login_bonus_data": {
"gacha_id": 0,
"gacha_item_id": 0,
"category": 0,
"type": 0,
},
"frozen_data": {"frozen_status": 2},
"penalty_data": {"penalty_flag": 0, "penalty_2_level": 0},
"config_data": config_data,
# gift_get_status 2 = new gift, 1 = acquired
# first_distribution related are useless since this is all handled by server
"battle_gift_data": battle_gift_data,
2023-10-01 01:54:23 +00:00
"ticket_data": ticket_data,
"round_event": round_info,
2023-10-01 01:54:23 +00:00
"last_round_event": [],
"past_round_event": [],
"total_round_point": 0,
"stamp_event_data": stamp_event_data,
"avatar_gacha_lottery_data": {"avatar_gacha_id": 0},
"fulltune_count": fulltune_count,
"total_car_parts_count": total_car_parts_count,
"car_layout_count": [],
"car_style_count": [],
"car_use_count": [],
"maker_use_count": [],
"story_course": [{"course_id": 0, "count": 1}],
"driver_debut": {
# "play_count": 5,
# "daily_play": 5,
# "last_play_dt": datetime.now().timestamp() - 86400,
# "use_start_date": datetime.now().timestamp() - 86400,
# "use_end_date": datetime.now().timestamp() + 86400,
# "use_dt": datetime.now().timestamp(),
# "ticket_cnt": 1,
# "ticket_get_bit": (2 ** 5) - 1,
},
2023-10-01 01:54:23 +00:00
"theory_data": theory_data,
"theory_course_data": theory_course_data,
"theory_partner_data": theory_partner_data,
"theory_running_pram_data": theory_running_pram_data,
"special_mode_data": await self._generate_special_data(user_id, headers),
2024-01-09 19:42:17 +00:00
"challenge_mode_data": await self._generate_challenge_data(user_id),
2023-10-01 01:54:23 +00:00
"season_rewards_data": [],
"timetrial_event_data": timetrial_event_data,
"special_mode_hint_data": {"story_type": 0, "hint_display_flag": 0},
"tips_info": tips_info,
2023-10-01 01:54:23 +00:00
}
2024-03-12 17:20:32 +00:00
async def handle_timetrial_getbestrecordpreta_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
for car_id in data["car_ids"]:
pass
course_mybest_data = []
2024-03-12 17:20:32 +00:00
courses = await self.data.item.get_time_trial_user_best_courses(
self.version, user_id
)
2023-10-01 01:54:23 +00:00
for course in courses:
course_mybest_data.append(
{
"course_id": course["course_id"],
# local rank, store rank, worldwide rank?
"rank": 1,
# no clue
"member": 10000,
# goal_time in ms
"value": course["goal_time"],
# total number of entries per course?
"total": 10,
"store": self.core_cfg.server.name,
# use car_id from request?
"car_id": 0,
"style_car_id": course["style_car_id"],
"play_dt": course["play_dt"].timestamp(),
"section_time_1": course["section_time_1"],
"section_time_2": course["section_time_2"],
"section_time_3": course["section_time_3"],
"section_time_4": course["section_time_4"],
# no clue
"mission": course["mission"],
}
)
course_pickup_car_best_data = []
2024-01-09 19:42:17 +00:00
courses = await self.data.item.get_time_trial_courses(self.version)
2023-10-01 01:54:23 +00:00
for course in courses:
car_list = []
2024-01-09 19:42:17 +00:00
best_cars = await self.data.item.get_time_trial_best_cars_by_course(
self.version, course["course_id"], user_id
2023-10-01 01:54:23 +00:00
)
for i, car in enumerate(best_cars):
2023-10-01 01:54:23 +00:00
car_list.append(
{
"rank": i + 1,
2023-10-01 01:54:23 +00:00
# no clue
"member": user_id,
"value": car["goal_time"],
"store": self.core_cfg.server.name,
# use car_id from request?
"car_id": 0,
"style_car_id": car["style_car_id"],
"play_dt": car["play_dt"].timestamp(),
"section_time_1": car["section_time_1"],
"section_time_2": car["section_time_2"],
"section_time_3": car["section_time_3"],
"section_time_4": car["section_time_4"],
"mission": car["mission"],
}
)
course_pickup_car_best_data.append(
{
"course_id": course["course_id"],
"car_list": car_list,
}
)
return {
"status_code": "0",
"course_mybest_data": course_mybest_data,
"course_pickup_car_best_data": course_pickup_car_best_data,
}
2024-03-12 17:20:32 +00:00
async def handle_timetrial_getbestrecordprerace_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
course_id = data["course_id"]
for car in data["car_ids"]:
# TODO: get the best record for this car
style_car_id = car["style_car_id"]
2023-10-01 01:54:23 +00:00
# Not sure if this is actually correct
2024-01-09 19:42:17 +00:00
ranking = await self.data.item.get_time_trial_ranking_by_course(
self.version, course_id
)
course_best_data = []
for i, rank in enumerate(ranking):
car_user_id = rank["user"]
# get the username, country and store from the profile
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(car_user_id, self.version)
arcade = await self.data.arcade.get_arcade(profile["store"])
if arcade is None:
arcade = {}
arcade["name"] = self.core_cfg.server.name
# should never happen
if profile is None:
continue
course_best_data.append(
{
"course_id": course_id,
"rank": i + 1,
"member": car_user_id,
"value": rank["goal_time"],
"store": arcade["name"],
# use car_id from request?
"car_id": 0,
"style_car_id": rank["style_car_id"],
"play_dt": rank["play_dt"].timestamp(),
"section_time_1": rank["section_time_1"],
"section_time_2": rank["section_time_2"],
"section_time_3": rank["section_time_3"],
"section_time_4": rank["section_time_4"],
"mission": rank["mission"],
}
)
2024-01-09 19:42:17 +00:00
best_cars = await self.data.item.get_time_trial_best_cars_by_course(
self.version, course_id
)
car_list = []
for i, rank in enumerate(best_cars):
car_user_id = rank["user"]
# get the username, country and store from the profile
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(car_user_id, self.version)
arcade = await self.data.arcade.get_arcade(profile["store"])
if arcade is None:
arcade = {}
arcade["name"] = self.core_cfg.server.name
# should never happen
if profile is None:
continue
car_list.append(
{
"rank": i + 1,
# no clue
"member": car_user_id,
"value": rank["goal_time"],
"store": arcade["name"],
# use car_id from request?
"car_id": 0,
"style_car_id": rank["style_car_id"],
"play_dt": rank["play_dt"].timestamp(),
"section_time_1": rank["section_time_1"],
"section_time_2": rank["section_time_2"],
"section_time_3": rank["section_time_3"],
"section_time_4": rank["section_time_4"],
"mission": rank["mission"],
}
)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"course_car_best_data": [{"course_id": course_id, "car_list": car_list}],
2023-10-01 01:54:23 +00:00
"course_best_data": course_best_data,
}
2024-01-09 19:42:17 +00:00
async def handle_user_createaccount_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
car_data: Dict = data.pop("car_obj")
parts_data: List = car_data.pop("parts_list")
avatar_data: Dict = data.pop("avatar_obj")
config_data: Dict = data.pop("config_obj")
rank_data: Dict = data.pop("mode_rank_data")
stock_data: Dict = data.pop("takeover_stock_obj")
takeover_ticket_list: List = data.pop("takeover_ticket")
# not required?
use_ticket = data.pop("use_ticket")
# save profile in database
data["store"] = headers.get("a_store", 0)
data["country"] = headers.get("a_country", 0)
data["device_version"] = headers.get("device_version", "1.50.00")
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(user_id, self.version, data)
2023-10-01 01:54:23 +00:00
# save rank data in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_rank(user_id, self.version, rank_data)
2023-10-01 01:54:23 +00:00
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save tickets in database
for ticket in takeover_ticket_list:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
config_data["config_id"] = config_data.pop("id")
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_config(user_id, config_data)
await self.data.profile.put_profile_avatar(user_id, avatar_data)
2023-10-01 01:54:23 +00:00
# save car data and car parts in database
car_data["parts_list"] = parts_data
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, car_data)
2023-10-01 01:54:23 +00:00
2024-05-20 19:17:44 +00:00
# create the tips row, so that all default tips are populated
await self.data.profile.put_profile_tips(user_id, self.version, {})
2023-10-01 01:54:23 +00:00
return {"status_code": "0"}
2024-01-09 19:42:17 +00:00
async def handle_user_updatelogin_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
pass
2024-01-09 19:42:17 +00:00
async def handle_timetrial_getcarbest_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
pass
2024-01-09 19:42:17 +00:00
async def handle_factory_avatargacharesult_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
use_ticket_cnt = data["use_ticket_cnt"]
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# get the user's ticket
2024-01-09 19:42:17 +00:00
tickets: list = await self.data.item.get_tickets(user_id)
2023-10-01 01:54:23 +00:00
ticket_list = []
for ticket in tickets:
# avatar tickets
if ticket["ticket_id"] == 5:
ticket_data = {
"ticket_id": ticket["ticket_id"],
"ticket_cnt": ticket["ticket_cnt"] - use_ticket_cnt,
}
# update the ticket in the database
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket_data)
2023-10-01 01:54:23 +00:00
ticket_list.append(ticket_data)
continue
ticket_list.append(
{
"ticket_id": ticket["ticket_id"],
"ticket_cnt": ticket["ticket_cnt"],
}
)
return {"status_code": "0", "ticket_data": ticket_list}
2024-01-09 19:42:17 +00:00
async def handle_factory_savefavoritecar_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
# save favorite cars in database
for car in data["pickup_on_car_ids"]:
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, car)
2023-10-01 01:54:23 +00:00
for car in data["pickup_off_car_ids"]:
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{"style_car_id": car["style_car_id"], "pickup_seq": 0},
)
return {"status_code": "0"}
2024-01-09 19:42:17 +00:00
async def handle_factory_updatemultiplecustomizeresult_request(
2023-10-01 01:54:23 +00:00
self, data: Dict, headers: Dict
):
user_id = headers["session"]
car_list = data.pop("car_list")
ticket_data: List = data.pop("ticket_data")
# unused
total_car_parts_count = data.pop("total_car_parts_count")
# save tickets in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
for car in car_list:
# save car data and car parts in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, car)
2023-10-01 01:54:23 +00:00
return {"status_code": "0"}
2024-03-12 17:20:32 +00:00
async def handle_factory_updatecustomizeresult_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
parts_data: List = data.pop("parts_list")
ticket_data: List = data.pop("ticket_data")
# save tickets in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
# save car data in database
data["parts_list"] = parts_data
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, data)
2023-10-01 01:54:23 +00:00
return {"status_code": "0"}
2024-01-09 19:42:17 +00:00
async def handle_factory_getcardata_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
2024-01-09 19:42:17 +00:00
cars = await self.data.item.get_cars(self.version, user_id)
2023-10-01 01:54:23 +00:00
car_data = []
for car in cars:
tmp = car._asdict()
del tmp["id"]
del tmp["user"]
del tmp["version"]
car_data.append(tmp)
return {
"status_code": "0",
"car_data": car_data,
}
2024-01-09 19:42:17 +00:00
async def handle_factory_renamebefore_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
pass
2024-01-09 19:42:17 +00:00
async def handle_factory_buycarresult_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
parts_data: List = data.pop("parts_list")
pickup_on_list: List = data.pop("pickup_on_car_ids")
pickup_off_list: List = data.pop("pickup_off_car_ids")
style_car_id = data.get("style_car_id")
# get the pickup_seq for the new car
pickup_seq = 0
# save favorite cars in database
for car in pickup_on_list:
# if the new car is a favorite get the new pickup_seqn for later
if car["style_car_id"] == style_car_id:
pickup_seq = car["pickup_seq"]
else:
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, car)
2023-10-01 01:54:23 +00:00
data["pickup_seq"] = pickup_seq
cash = data.pop("cash")
total_cash = data.pop("total_cash")
# save the new cash in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(
2023-10-01 01:54:23 +00:00
user_id, self.version, {"total_cash": total_cash, "cash": cash}
)
# full tune ticket
use_ticket = data.pop("use_ticket")
if use_ticket:
# get the user's tickets, full tune ticket id is 25
2024-01-09 19:42:17 +00:00
ticket = await self.data.item.get_ticket(user_id, ticket_id=25)
2023-10-01 01:54:23 +00:00
# update the ticket in the database
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(
2023-10-01 01:54:23 +00:00
user_id,
{
"ticket_id": ticket["ticket_id"],
"ticket_cnt": ticket["ticket_cnt"] - 1,
},
)
# also set the tune_level to 16 (fully tuned)
data["tune_level"] = 16
# save car data and car parts in database
data["parts_list"] = parts_data
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, data)
2023-10-01 01:54:23 +00:00
for car in pickup_off_list:
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{"style_car_id": car["style_car_id"], "pickup_seq": 0},
)
# get the user's car
2024-01-09 19:42:17 +00:00
cars = await self.data.item.get_cars(self.version, user_id)
2023-10-01 01:54:23 +00:00
fulltune_count = 0
total_car_parts_count = 0
for car in cars:
# tune_level of 16 means fully tuned, so add 1 to fulltune_count
if car["tune_level"] >= 16:
fulltune_count += 1
# add the number of car parts to total_car_parts_count
# total_car_parts_count += car["total_car_parts_count"]
# get the user's ticket
2024-01-09 19:42:17 +00:00
tickets = await self.data.item.get_tickets(user_id)
2023-10-01 01:54:23 +00:00
ticket_data = []
for ticket in tickets:
ticket_data.append(
{
"ticket_id": ticket["ticket_id"],
"ticket_cnt": ticket["ticket_cnt"],
}
)
return {
"status_code": "0",
"ticket_data": ticket_data,
"fulltune_count": fulltune_count,
"total_car_parts_count": total_car_parts_count,
"car_layout_count": [],
"car_style_count": [],
}
2024-01-09 19:42:17 +00:00
async def handle_factory_renameresult_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
new_username = data.get("username")
# save new username in database
if new_username:
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(user_id, self.version, data)
2023-10-01 01:54:23 +00:00
return {"status_code": "0"}
2024-03-12 17:20:32 +00:00
async def handle_factory_updatecustomizeavatar_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
avatar_data: Dict = data.pop("avatar_obj")
stock_data: Dict = data.pop("stock_obj")
# update the stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save avatar data and avatar parts in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_avatar(user_id, avatar_data)
2023-10-01 01:54:23 +00:00
return {"status_code": "0"}
2024-03-12 17:20:32 +00:00
async def handle_factory_updatecustomizeuser_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
# update the stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# update profile data and config in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(user_id, self.version, data)
2023-10-01 01:54:23 +00:00
return {"status_code": "0"}
2024-01-09 19:42:17 +00:00
async def handle_user_updatestampinfo_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stamp_event_data = data.pop("stamp_event_data")
for stamp in stamp_event_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_stamp(user_id, stamp)
2023-10-01 01:54:23 +00:00
return {"status_code": "0"}
2024-03-12 17:20:32 +00:00
async def handle_user_updatetimetrialresult_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
ticket_data: List = data.pop("ticket_data")
reward_dist_data: Dict = data.pop("reward_dist_obj")
driver_debut_data = data.pop("driver_debut_obj")
rank_data: Dict = data.pop("mode_rank_obj")
# time trial event points
event_point = data.pop("event_point")
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save tickets in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
# save mode rank data in database
rank_data.update(reward_dist_data)
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_rank(user_id, self.version, rank_data)
2023-10-01 01:54:23 +00:00
# get the profile data, update total_play and daily_play, and save it
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
2023-10-01 01:54:23 +00:00
total_play = profile["total_play"] + 1
# update profile
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"total_play": total_play,
"last_play_date": datetime.now(),
"aura_id": data.pop("aura_id"),
"aura_color_id": data.pop("aura_color_id"),
"aura_line_id": data.pop("aura_line_id"),
"cash": data.pop("cash"),
"total_cash": data.pop("total_cash"),
"dressup_point": data.pop("dressup_point"),
"avatar_point": data.pop("avatar_point"),
"mileage": data.pop("mileage"),
},
)
# get the use_count and story_use_count of the used car
style_car_id = data.get("style_car_id")
car_mileage = data.pop("car_mileage")
2024-02-09 15:48:39 +00:00
used_car = await self.data.item.get_car(user_id, self.version, style_car_id)
used_car = used_car._asdict()
2023-10-01 01:54:23 +00:00
# increase the use_count and story_use_count of the used car
used_car["use_count"] += 1
used_car["timetrial_use_count"] += 1
used_car["car_mileage"] = car_mileage
# save the used car in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, used_car)
2023-10-01 01:54:23 +00:00
# skill_level_exp is the "course proeficiency" and is saved
# in the course table
course_id = data.get("course_id")
run_counts = 1
skill_level_exp = data.pop("skill_level_exp")
# get the course data
2024-01-09 19:42:17 +00:00
course = await self.data.item.get_course(user_id, course_id)
2023-10-01 01:54:23 +00:00
if course:
# update run_counts
run_counts = course["run_counts"] + 1
2024-01-09 19:42:17 +00:00
await self.data.item.put_course(
2023-10-01 01:54:23 +00:00
user_id,
{
"course_id": course_id,
"run_counts": run_counts,
"skill_level_exp": skill_level_exp,
},
)
goal_time = data.get("goal_time")
# grab the ranking data and count the numbers of rows with a faster time
# than the current goal_time
2024-01-09 19:42:17 +00:00
course_rank = await self.data.item.get_time_trial_ranking_by_course(
2023-10-01 01:54:23 +00:00
self.version, course_id, limit=None
)
course_rank = len([r for r in course_rank if r["goal_time"] < goal_time]) + 1
2024-01-09 19:42:17 +00:00
car_course_rank = await self.data.item.get_time_trial_ranking_by_course(
2023-10-01 01:54:23 +00:00
self.version, course_id, style_car_id, limit=None
)
car_course_rank = (
len([r for r in car_course_rank if r["goal_time"] < goal_time]) + 1
)
# only update the time if its better than the best time and also not 0
if data.get("goal_time") > 0:
# get the current best goal time
best_time_trial = (
2024-01-09 19:42:17 +00:00
await self.data.item.get_time_trial_user_best_time_by_course_car(
2023-10-01 01:54:23 +00:00
self.version, user_id, course_id, style_car_id
)
)
if (
best_time_trial is None
or data.get("goal_time") < best_time_trial["goal_time"]
):
# now finally save the time trial with updated timestamp
data["play_dt"] = datetime.now()
2024-01-09 19:42:17 +00:00
await self.data.item.put_time_trial(self.version, user_id, data)
2023-10-01 01:54:23 +00:00
# update the timetrial event points
2024-01-09 19:42:17 +00:00
await self.data.item.put_timetrial_event(
2023-10-19 17:04:06 +00:00
user_id, self.timetrial_event_id, event_point
)
2023-10-01 01:54:23 +00:00
# update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips(
user_id,
self.version,
{"timetrial_play_count": tips["timetrial_play_count"] + 1},
)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"course_rank": course_rank,
"course_car_rank": car_course_rank,
"location_course_store_rank": course_rank,
"car_use_count": [],
"maker_use_count": [],
"timetrial_event_data": {
"timetrial_event_id": self.timetrial_event_id,
"point": event_point,
2023-10-19 17:04:06 +00:00
},
2023-10-01 01:54:23 +00:00
}
2024-01-09 19:42:17 +00:00
async def handle_user_updatestoryresult_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
ticket_data: List = data.pop("ticket_data")
reward_dist_data: Dict = data.pop("reward_dist_obj")
driver_debut_data = data.pop("driver_debut_obj")
rank_data: Dict = data.pop("mode_rank_obj")
# stamp_event_data = data.pop("stamp_event_data")
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save tickets in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
# save mode rank data in database
rank_data.update(reward_dist_data)
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_rank(user_id, self.version, rank_data)
2023-10-01 01:54:23 +00:00
# save the current story progress in database
max_loop = data.get("chapter_loop_max")
chapter_id = data.get("chapter")
episode_id = data.get("episode")
difficulty = data.get("difficulty")
play_status = data.get("play_status")
# get the current loop from the database
2024-01-09 19:42:17 +00:00
story_data = await self.data.item.get_story(user_id, chapter_id)
2023-10-01 01:54:23 +00:00
# 1 = active, 2+ = cleared?
loop_count = 1
if story_data:
loop_count = story_data["loop_count"]
# if the played difficulty is smaller than loop_count you cannot clear
# (play_status = 2) the episode otherwise the following difficulties
# won't earn any EXP?
if difficulty < loop_count:
play_status = 1
# if the episode has already been cleared, set the play_status to 2
# so it won't be set to unplayed (play_status = 1)
2024-01-09 19:42:17 +00:00
episode_data = await self.data.item.get_story_episode(user_id, episode_id)
2023-10-01 01:54:23 +00:00
if episode_data:
if play_status < episode_data["play_status"]:
play_status = 2
# save the current episode progress in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_story_episode(
2023-10-01 01:54:23 +00:00
user_id,
chapter_id,
{
"episode": episode_id,
"play_status": play_status,
},
)
if loop_count < max_loop and data.get("chapter_clear") == 1:
# increase the loop count
loop_count += 1
# for the current chapter set all episode play_status back to 1
2024-01-09 19:42:17 +00:00
await self.data.item.put_story_episode_play_status(user_id, chapter_id, 1)
2023-10-01 01:54:23 +00:00
2024-01-09 19:42:17 +00:00
await self.data.item.put_story(
2023-10-01 01:54:23 +00:00
user_id,
{
"story_type": data.get("story_type"),
"chapter": chapter_id,
"loop_count": loop_count,
},
)
# save the current episode difficulty progress in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_story_episode_difficulty(
2023-10-01 01:54:23 +00:00
user_id,
episode_id,
{
"difficulty": difficulty,
"play_count": 1, # no idea where this comes from
"clear_count": 1, # no idea where this comes from
"play_status": data.get("play_status"),
"play_score": data.get("play_score"),
},
)
# get the use_count and story_use_count of the used car
style_car_id = data.get("style_car_id")
car_mileage = data.get("car_mileage")
2024-02-09 15:48:39 +00:00
used_car = await self.data.item.get_car(user_id, self.version, style_car_id)
used_car = used_car._asdict()
2023-10-01 01:54:23 +00:00
# increase the use_count and story_use_count of the used car
used_car["use_count"] += 1
used_car["story_use_count"] += 1
used_car["car_mileage"] = car_mileage
# save the used car in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, used_car)
2023-10-01 01:54:23 +00:00
# get the profile data, update total_play and daily_play, and save it
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
2023-10-01 01:54:23 +00:00
total_play = profile["total_play"] + 1
# save user profile in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"total_play": total_play,
"last_play_date": datetime.now(),
"mileage": data.pop("mileage"),
"cash": data.pop("cash"),
"total_cash": data.pop("total_cash"),
"dressup_point": data.pop("dressup_point"),
"avatar_point": data.pop("avatar_point"),
"aura_id": data.pop("aura_id"),
"aura_color_id": data.pop("aura_color_id"),
"aura_line_id": data.pop("aura_line_id"),
},
)
# update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips(
user_id, self.version, {"story_play_count": tips["story_play_count"] + 1}
)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
2024-01-09 19:42:17 +00:00
"story_data": await self._generate_story_data(user_id),
2023-10-01 01:54:23 +00:00
"car_use_count": [],
"maker_use_count": [],
}
2024-03-12 17:20:32 +00:00
async def handle_user_updatespecialmoderesult_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
ticket_data: List = data.pop("ticket_data")
reward_dist_data: Dict = data.pop("reward_dist_obj")
driver_debut_data = data.pop("driver_debut_obj")
rank_data: Dict = data.pop("mode_rank_obj")
# unused
hint_display_flag: int = data.pop("hint_display_flag")
# get the vs use count from database and update it
style_car_id = data.pop("style_car_id")
2024-01-09 19:42:17 +00:00
car_data = await self.data.item.get_car(user_id, self.version, style_car_id)
story_use_count = car_data["story_use_count"] + 1
2023-10-01 01:54:23 +00:00
# save car data in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"style_car_id": style_car_id,
"car_mileage": data.pop("car_mileage"),
"story_use_count": story_use_count,
2023-10-01 01:54:23 +00:00
},
)
# get the profile data, update total_play and daily_play, and save it
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
2023-10-01 01:54:23 +00:00
total_play = profile["total_play"] + 1
# save user profile in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"total_play": total_play,
"last_play_date": datetime.now(),
"mileage": data.pop("mileage"),
"cash": data.pop("cash"),
"total_cash": data.pop("total_cash"),
"dressup_point": data.pop("dressup_point"),
"avatar_point": data.pop("avatar_point"),
"aura_id": data.pop("aura_id"),
"aura_color_id": data.pop("aura_color_id"),
"aura_line_id": data.pop("aura_line_id"),
},
)
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save ticket data in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
# save mode_rank and reward_dist data in database
rank_data.update(reward_dist_data)
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_rank(user_id, self.version, rank_data)
2023-10-01 01:54:23 +00:00
# finally save the special mode with story_type=4 in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_challenge(user_id, data)
2023-10-01 01:54:23 +00:00
# update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips(
user_id,
self.version,
{"special_play_count": tips["special_play_count"] + 1},
)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"special_mode_data": await self._generate_special_data(user_id, headers),
2023-10-01 01:54:23 +00:00
"car_use_count": [],
"maker_use_count": [],
}
2024-03-12 17:20:32 +00:00
async def handle_user_updatechallengemoderesult_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
ticket_data: List = data.pop("ticket_data")
reward_dist_data: Dict = data.pop("reward_dist_obj")
driver_debut_data = data.pop("driver_debut_obj")
rank_data: Dict = data.pop("mode_rank_obj")
# get the vs use count from database and update it
style_car_id = data.get("style_car_id")
2024-01-09 19:42:17 +00:00
car_data = await self.data.item.get_car(user_id, self.version, style_car_id)
story_use_count = car_data["story_use_count"] + 1
2023-10-01 01:54:23 +00:00
# save car data in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"style_car_id": style_car_id,
"car_mileage": data.pop("car_mileage"),
"story_use_count": story_use_count,
2023-10-01 01:54:23 +00:00
},
)
# get the profile data, update total_play and daily_play, and save it
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
2023-10-01 01:54:23 +00:00
total_play = profile["total_play"] + 1
# save user profile in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"total_play": total_play,
"last_play_date": datetime.now(),
"mileage": data.pop("mileage"),
"cash": data.pop("cash"),
"total_cash": data.pop("total_cash"),
"dressup_point": data.pop("dressup_point"),
"avatar_point": data.pop("avatar_point"),
"aura_id": data.pop("aura_id"),
"aura_color_id": data.pop("aura_color_id"),
"aura_line_id": data.pop("aura_line_id"),
},
)
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save ticket data in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
# save mode_rank and reward_dist data in database
rank_data.update(reward_dist_data)
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_rank(user_id, self.version, rank_data)
2023-10-01 01:54:23 +00:00
# get the challenge mode data from database
2024-01-09 19:42:17 +00:00
challenge_data = await self.data.item.get_challenge(
2023-10-01 01:54:23 +00:00
user_id, data.get("vs_type"), data.get("play_difficulty")
)
if challenge_data:
# update play count
play_count = challenge_data["play_count"] + 1
data["play_count"] = play_count
# finally save the challenge mode with story_type=3 in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_challenge(user_id, data)
2023-10-01 01:54:23 +00:00
# update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips(
user_id,
self.version,
{"challenge_play_count": tips["challenge_play_count"] + 1},
)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
2024-03-12 14:14:03 +00:00
"challenge_mode_data": await self._generate_challenge_data(user_id),
2023-10-01 01:54:23 +00:00
"car_use_count": [],
"maker_use_count": [],
}
2024-03-12 17:20:32 +00:00
async def _generate_time_trial_data(
self, season_id: int, user_id: int
) -> List[Dict]:
# get the season time trial data from database
timetrial_data = []
2024-01-09 19:42:17 +00:00
courses = await self.data.item.get_courses(user_id)
if courses is None or len(courses) == 0:
return {"status_code": "0", "timetrial_data": timetrial_data}
for course in courses:
# grab the course id and course proeficiency
course_id = course["course_id"]
skill_level_exp = course["skill_level_exp"]
# get the best time for the current course for the current user
2024-01-09 19:42:17 +00:00
best_trial = await self.data.item.get_time_trial_best_ranking_by_course(
2023-10-19 17:04:06 +00:00
season_id, user_id, course_id
)
if not best_trial:
continue
goal_time = best_trial["goal_time"]
# get the rank for the current course
2024-01-09 19:42:17 +00:00
course_rank = await self.data.item.get_time_trial_ranking_by_course(
season_id, course_id, limit=None
)
2023-10-19 17:04:06 +00:00
course_rank = (
len([r for r in course_rank if r["goal_time"] < goal_time]) + 1
)
timetrial_data.append(
{
"style_car_id": best_trial["style_car_id"],
"course_id": course_id,
"skill_level_exp": skill_level_exp,
"goal_time": goal_time,
"rank": course_rank,
"rank_dt": int(best_trial["play_dt"].timestamp()),
2023-10-19 17:04:06 +00:00
}
)
return timetrial_data
2024-01-09 19:42:17 +00:00
async def handle_user_getpastseasontadata_request(self, data: Dict, headers: Dict):
user_id = headers["session"]
season_id = data.get("season_id")
# so to get the season 1 data just subtract 1 from the season id
2024-03-12 17:20:32 +00:00
past_timetrial_data = await self._generate_time_trial_data(
season_id - 1, user_id
)
# TODO: get the current season timetrial data somehow, because after requesting
# GetPastSeasonTAData the game will NOT request GetTAData?!
return {
"status_code": "0",
"season_id": season_id,
"past_season_timetrial_data": past_timetrial_data,
}
def handle_user_getpastseasonrounddata_request(self, data: Dict, headers: Dict):
user_id = headers["session"]
season_id = data.get("season_id")
# so to get the season 1 data just subtract 1 from the season id
past_timetrial_data = self._generate_time_trial_data(season_id - 1, user_id)
2024-03-12 17:20:32 +00:00
return {
"status_code": "0",
"season_id": season_id,
2024-03-12 17:20:32 +00:00
"past_season_round_event_data": [
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "DAC稼働記念 1stラウンド",
"round_id": 0,
},
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "シーズン1 2ndラウンド",
"round_id": 1,
},
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "シーズン1 3rdラウンド",
"round_id": 2,
},
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "シーズン1 4thラウンド",
"round_id": 3,
},
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "シーズン1 5thラウンド",
"round_id": 4,
},
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "シーズン1 6thラウンド",
"round_id": 5,
},
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "シーズン1 7thラウンド",
"round_id": 6,
},
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "シーズン1 8thラウンド",
"round_id": 7,
},
{
"count": 0,
"win": 0,
"rank": 0,
"area_rank": 0,
"point": 0,
"total_round_point": 0,
"round_name": "シーズン1 9thラウンド",
"round_id": 8,
},
],
}
2024-03-12 17:20:32 +00:00
2024-01-09 19:42:17 +00:00
async def handle_user_gettadata_request(self, data: Dict, headers: Dict):
user_id = headers["session"]
2024-01-09 19:42:17 +00:00
timetrial_data = await self._generate_time_trial_data(self.version, user_id)
# TODO: get the past season timetrial data somehow, because after requesting
# GetTAData the game will NOT request GetPastSeasonTAData?!
return {
"status_code": "0",
"timetrial_data": timetrial_data,
# "past_season_timetrial_data": timetrial_data,
}
2024-01-09 19:42:17 +00:00
async def handle_user_updatecartune_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
# full tune ticket
use_ticket = data.pop("use_ticket")
if use_ticket:
# get the user's tickets, full tune ticket id is 25
2024-01-09 19:42:17 +00:00
ticket = await self.data.item.get_ticket(user_id, ticket_id=25)
2023-10-01 01:54:23 +00:00
# update the ticket in the database
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(
2023-10-01 01:54:23 +00:00
user_id,
{
"ticket_id": ticket["ticket_id"],
"ticket_cnt": ticket["ticket_cnt"] - 1,
},
)
# also set the tune_level to 16 (fully tuned)
data["tune_level"] = 16
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, data)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
2024-01-09 19:42:17 +00:00
"story_data": await self._generate_story_data(user_id),
2023-10-01 01:54:23 +00:00
"car_use_count": [],
"maker_use_count": [],
}
2024-01-09 19:42:17 +00:00
async def handle_log_saveplaylog_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
pass
2024-01-09 19:42:17 +00:00
async def handle_log_saveendlog_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
pass
2024-01-09 19:42:17 +00:00
async def handle_user_updatemoderesult_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
config_data: Dict = data.pop("config_obj")
stock_data: Dict = data.pop("stock_obj")
ticket_data: List = data.pop("ticket_data")
reward_dist_data: Dict = data.pop("reward_dist_obj")
# not required?
mode_id = data.pop("mode_id")
standby_play_flag = data.pop("standby_play_flag")
# save the tips list in database
2023-10-01 01:54:23 +00:00
tips_list = data.pop("tips_list")
await self.data.profile.put_profile_tips(
user_id, self.version, {"tips_list": tips_list}
)
2023-10-01 01:54:23 +00:00
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save tickets in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
# save rank dist data in database
2024-03-12 17:20:32 +00:00
await self.data.profile.put_profile_rank(
user_id, self.version, reward_dist_data
)
2023-10-01 01:54:23 +00:00
# update profile data and config in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(user_id, self.version, data)
2023-10-01 01:54:23 +00:00
config_data["config_id"] = config_data.pop("id")
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_config(user_id, config_data)
2023-10-01 01:54:23 +00:00
return {"status_code": "0", "server_status": 1}
2024-01-09 19:42:17 +00:00
async def _generate_theory_rival_data(
2023-10-01 01:54:23 +00:00
self, user_list: list, course_id: int, req_user_id: int
) -> list:
rival_data = []
for user_id in user_list:
# if not enough players are available just use the data from the req_user
if user_id == -1:
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(req_user_id, self.version)
2023-10-01 01:54:23 +00:00
profile = profile._asdict()
# set the name to CPU
profile["username"] = f""
# also reset stamps to default
profile["country"] = 9
profile["store"] = 0
2023-10-01 01:54:23 +00:00
profile["stamp_key_assign_0"] = 0
profile["stamp_key_assign_1"] = 1
profile["stamp_key_assign_2"] = 2
profile["stamp_key_assign_3"] = 3
profile["mytitle_id"] = 0
else:
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
2023-10-01 01:54:23 +00:00
2024-03-12 17:20:32 +00:00
rank = await self.data.profile.get_profile_rank(
profile["user"], self.version
)
2023-10-01 01:54:23 +00:00
avatars = [
{
"sex": 0,
"face": 1,
"eye": 1,
"mouth": 1,
"hair": 1,
"glasses": 0,
"face_accessory": 0,
"body": 1,
"body_accessory": 0,
"behind": 0,
"bg": 1,
"effect": 0,
"special": 0,
},
{
"sex": 0,
"face": 1,
"eye": 1,
"mouth": 1,
"hair": 19,
"glasses": 0,
"face_accessory": 0,
"body": 2,
"body_accessory": 0,
"behind": 0,
"bg": 1,
"effect": 0,
"special": 0,
},
{
"sex": 1,
"face": 91,
"eye": 265,
"mouth": 13,
"hair": 369,
"glasses": 0,
"face_accessory": 0,
"body": 113,
"body_accessory": 0,
"behind": 0,
"bg": 1,
"effect": 0,
"special": 0,
},
{
"sex": 1,
"face": 91,
"eye": 265,
"mouth": 13,
"hair": 387,
"glasses": 0,
"face_accessory": 0,
"body": 114,
"body_accessory": 0,
"behind": 0,
"bg": 1,
"effect": 0,
"special": 0,
},
]
if user_id == -1:
# get a random avatar from the list and some random car from all users
avatar = choice(avatars)
2024-01-09 19:42:17 +00:00
car = await self.data.item.get_random_car(self.version)
2023-10-01 01:54:23 +00:00
else:
2024-01-09 19:42:17 +00:00
avatar = await self.data.profile.get_profile_avatar(profile["user"])
2024-03-12 17:20:32 +00:00
car = await self.data.item.get_random_user_car(
profile["user"], self.version
)
2023-10-01 01:54:23 +00:00
parts_list = []
for part in car["parts_list"]:
parts_list.append(part["parts"])
2024-01-09 19:42:17 +00:00
course = await self.data.item.get_theory_course(profile["user"], course_id)
2023-10-01 01:54:23 +00:00
powerhose_lv = 0
if course:
powerhose_lv = course["powerhouse_lv"]
2024-01-09 19:42:17 +00:00
theory_running = await self.data.item.get_theory_running_by_course(
2023-10-01 01:54:23 +00:00
profile["user"], course_id
)
# normally it's 127 after the first play so we set it to 128
attack = 128
defense = 128
safety = 128
runaway = 128
trick_flag = 0
if theory_running and user_id != -1:
attack = theory_running["attack"]
defense = theory_running["defense"]
safety = theory_running["safety"]
runaway = theory_running["runaway"]
trick_flag = theory_running["trick_flag"]
# get the time trial ranking medal
eval_id = 0
2024-01-09 19:42:17 +00:00
time_trial = await self.data.item.get_time_trial_best_ranking_by_course(
2023-10-01 01:54:23 +00:00
self.version, profile["user"], course_id
)
if time_trial:
eval_id = time_trial["eval_id"]
2024-01-09 19:42:17 +00:00
arcade = await self.data.arcade.get_arcade(profile["store"])
if arcade is None:
arcade = {}
arcade["name"] = self.core_cfg.server.name
2023-10-01 01:54:23 +00:00
rival_data.append(
{
"id": profile["user"],
"name": profile["username"],
"grade": rank["grade"],
# only needed for power match
"powerhouseLv": powerhose_lv,
"mytitleId": profile["mytitle_id"],
"country": profile["country"],
2023-10-01 01:54:23 +00:00
"auraId": profile["aura_id"],
"auraColor": profile["aura_color_id"],
"auraLine": profile["aura_line_id"],
# not sure?
"roundRanking": 0,
"storeName": arcade["name"],
2023-10-01 01:54:23 +00:00
"sex": avatar["sex"],
"face": avatar["face"],
"eye": avatar["eye"],
"mouth": avatar["mouth"],
"hair": avatar["hair"],
"glasses": avatar["glasses"],
"faceAccessory": avatar["face_accessory"],
"body": avatar["body"],
"bodyAccessory": avatar["body_accessory"],
"behind": avatar["behind"],
"bg": avatar["bg"],
"effect": avatar["effect"],
"special": avatar["special"],
"styleCarId": car["style_car_id"],
"color": car["color"],
"bureau": car["bureau"],
"kana": car["kana"],
"sNo": car["s_no"],
"lNo": car["l_no"],
"tuneLv": car["tune_level"],
"carFlag": car["car_flag"],
"tunePoint": car["tune_point"],
"infinityTune": car["infinity_tune"],
"tuneParts": car["tune_parts"],
"partsList": parts_list,
"partsCount": car["equip_parts_count"],
"stamp0": profile["stamp_key_assign_0"],
"stamp1": profile["stamp_key_assign_1"],
"stamp2": profile["stamp_key_assign_2"],
"stamp3": profile["stamp_key_assign_3"],
"attack": attack,
"defense": defense,
"safety": safety,
"runaway": runaway,
"trickFlg": trick_flag,
# time trial ranking medal
"taEval": eval_id,
}
)
return rival_data
2024-01-09 19:42:17 +00:00
async def handle_theory_matching_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
course_id = data.pop("course_id")
# no idea why thats needed?
grade = data.pop("grade")
# number of auto_matches and power_matches, official values are:
count_auto_match = 9
count_power_match = 3
# required for the power_match list?
powerhose_lv = data.pop("powerhouse_lv")
# get random profiles for auto match
2024-01-09 19:42:17 +00:00
profiles = await self.data.profile.get_different_random_profiles(
2023-10-01 01:54:23 +00:00
user_id, self.version, count=count_auto_match
)
user_list = [profile["user"] for profile in profiles]
# if user_list is not count_auto_match long, fill it up with -1
while len(user_list) < count_auto_match:
user_list.append(-1)
2024-03-12 17:20:32 +00:00
auto_match = await self._generate_theory_rival_data(
user_list, course_id, user_id
)
2023-10-01 01:54:23 +00:00
# get profiles with the same powerhouse_lv for power match
2024-01-09 19:42:17 +00:00
theory_courses = await self.data.item.get_theory_course_by_powerhouse_lv(
2023-10-01 01:54:23 +00:00
user_id, course_id, powerhose_lv, count=count_power_match
)
user_list = [course["user"] for course in theory_courses]
# if user_list is not count_power_match long, fill it up with -1
while len(user_list) < count_power_match:
user_list.append(-1)
2024-03-12 17:20:32 +00:00
power_match = await self._generate_theory_rival_data(
user_list, course_id, user_id
)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"server_status": 1,
"rival_data": {
"auto_match": auto_match,
"power_match": power_match,
},
}
2024-01-09 19:42:17 +00:00
async def handle_user_updatetheoryresult_request(self, data: Dict, headers: Dict):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
ticket_data: List = data.pop("ticket_data")
reward_dist_data: Dict = data.pop("reward_dist_obj")
rank_data: Dict = data.pop("mode_rank_obj")
driver_debut_data: Dict = data.pop("driver_debut_obj")
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save tickets in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
# save rank dist data in database
rank_data.update(reward_dist_data)
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_rank(user_id, self.version, rank_data)
2023-10-01 01:54:23 +00:00
# save the profile theory data in database
play_count = 1
play_count_multi = 1
win_count = 0
win_count_multi = 0
2024-01-09 19:42:17 +00:00
theory_data = await self.data.profile.get_profile_theory(user_id, self.version)
2023-10-01 01:54:23 +00:00
if theory_data:
play_count = theory_data["play_count"] + 1
play_count_multi = theory_data["play_count_multi"] + 1
win_count = theory_data["win_count"]
win_count_multi = theory_data["win_count_multi"]
# check all advantages and see if one of them is larger than 0
# if so, we won
if (
data.get("advantage_1") > 0
or data.get("advantage_2") > 0
or data.get("advantage_3") > 0
or data.get("advantage_4") > 0
):
win_count += 1
win_count_multi += 1
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_theory(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"play_count": play_count,
"play_count_multi": play_count_multi,
"partner_id": data.get("partner_id"),
"partner_progress": data.get("partner_progress"),
"partner_progress_score": data.get("partner_progress_score"),
"practice_start_rank": data.get("practice_start_rank"),
"general_flag": data.get("general_flag"),
"vs_history": data.get("vs_history"),
# no idea?
"vs_history_multi": data.get("vs_history"),
"win_count": win_count,
"win_count_multi": win_count_multi,
},
)
# save theory course in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_theory_course(
2023-10-01 01:54:23 +00:00
user_id,
{
"course_id": data.get("course_id"),
"max_victory_grade": data.get("max_victory_grade"),
# always add 1?
"run_count": 1,
"powerhouse_lv": data.get("powerhouse_lv"),
"powerhouse_exp": data.get("powerhouse_exp"),
# not sure if the played_powerhouse_lv is the same as powerhouse_lv
"played_powerhouse_lv": data.get("powerhouse_lv"),
},
)
# save the theory partner in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_theory_partner(
2023-10-01 01:54:23 +00:00
user_id,
{
"partner_id": data.get("partner_id"),
"fellowship_lv": data.get("fellowship_lv"),
"fellowship_exp": data.get("fellowship_exp"),
},
)
# save the theory running in database?
2024-01-09 19:42:17 +00:00
await self.data.item.put_theory_running(
2023-10-01 01:54:23 +00:00
user_id,
{
"course_id": data.get("course_id"),
"attack": data.get("attack"),
"defense": data.get("defense"),
"safety": data.get("safety"),
"runaway": data.get("runaway"),
"trick_flag": data.get("trick_flag"),
},
)
# get the use_count and theory_use_count of the used car
style_car_id = data.get("style_car_id")
car_mileage = data.get("car_mileage")
2024-02-09 15:48:39 +00:00
used_car = await self.data.item.get_car(user_id, self.version, style_car_id)
used_car = used_car._asdict()
2023-10-01 01:54:23 +00:00
# increase the use_count and theory_use_count of the used car
used_car["use_count"] += 1
used_car["theory_use_count"] += 1
used_car["car_mileage"] = car_mileage
# save the used car in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, used_car)
2023-10-01 01:54:23 +00:00
# get the profile data, update total_play and daily_play, and save it
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
2023-10-01 01:54:23 +00:00
total_play = profile["total_play"] + 1
# save the profile in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"total_play": total_play,
"last_play_date": datetime.now(),
"mileage": data.get("mileage"),
"aura_id": data.get("aura_id"),
"aura_color_id": data.get("aura_color_id"),
"aura_line_id": data.get("aura_line_id"),
"cash": data.get("cash"),
"total_cash": data.get("total_cash"),
"dressup_point": data.get("dressup_point"),
"avatar_point": data.get("avatar_point"),
},
)
# update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips(
user_id, self.version, {"theory_play_count": tips["theory_play_count"] + 1}
)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"played_powerhouse_lv": data.get("powerhouse_lv"),
"car_use_count": [],
"maker_use_count": [],
"play_count": play_count,
"play_count_multi": play_count_multi,
"win_count": win_count,
"win_count_multi": win_count_multi,
}
2024-01-09 19:42:17 +00:00
async def handle_timetrial_getbestrecordprebattle_request(
self, data: Dict, headers: Dict
):
user_id = headers["session"]
course_pickup_car_best_data = []
2024-01-09 19:42:17 +00:00
courses = await self.data.item.get_time_trial_courses(self.version)
for course in courses:
car_list = []
2024-01-09 19:42:17 +00:00
best_cars = await self.data.item.get_time_trial_best_cars_by_course(
self.version, course["course_id"], user_id
)
for i, car in enumerate(best_cars):
car_list.append(
{
"rank": i + 1,
# no clue
"member": user_id,
"value": car["goal_time"],
"store": self.core_cfg.server.name,
# use car_id from request?
"car_id": 0,
"style_car_id": car["style_car_id"],
"play_dt": car["play_dt"].timestamp(),
"section_time_1": car["section_time_1"],
"section_time_2": car["section_time_2"],
"section_time_3": car["section_time_3"],
"section_time_4": car["section_time_4"],
"mission": car["mission"],
}
)
course_pickup_car_best_data.append(
{
"course_id": course["course_id"],
"car_list": car_list,
}
)
return {
"status_code": "0",
"course_pickup_car_best_data": course_pickup_car_best_data,
}
2024-01-09 19:42:17 +00:00
async def handle_user_updateonlinebattle_request(self, data: Dict, headers: Dict):
#TODO: voiding cheaters' result. which will need to analysis historical battle results returned by the game.
return {
"status_code": "0",
"bothwin_penalty": 1,
}
async def handle_user_updateonlinebattleresult_request(
self, data: Dict, headers: Dict
):
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
ticket_data: List = data.pop("ticket_data")
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
reward_dist_data: Dict = data.pop("reward_dist_obj")
rank_data: Dict = data.pop("mode_rank_obj")
# save rank dist data in database
rank_data.update(reward_dist_data)
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_rank(user_id, self.version, rank_data)
driver_debut_data = data.pop("driver_debut_obj")
# get the use_count and net_vs_use_count of the used car
style_car_id = data.get("style_car_id")
car_mileage = data.pop("car_mileage")
2024-02-09 15:48:39 +00:00
used_car = await self.data.item.get_car(user_id, self.version, style_car_id)
used_car = used_car._asdict()
# increase the use_count and net_vs_use_count of the used car
used_car["use_count"] += 1
used_car["net_vs_use_count"] += 1
used_car["car_mileage"] = car_mileage
# save the used car in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, used_car)
# get the profile data, update total_play and daily_play, and save it
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
total_play = profile["total_play"] + 1
# save the profile in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(
user_id,
self.version,
{
"total_play": total_play,
"last_play_date": datetime.now(),
"mileage": data.pop("mileage"),
"aura_id": data.pop("aura_id"),
"aura_color_id": data.pop("aura_color_id"),
"aura_line_id": data.pop("aura_line_id"),
"cash": data.pop("cash"),
"total_cash": data.pop("total_cash"),
"dressup_point": data.pop("dressup_point"),
"avatar_point": data.pop("avatar_point"),
},
)
vs_info = await self._update_vs_info(
user_id, IDACConstants.BATTLE_MODE_ONLINE, data
)
# update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips(
user_id,
self.version,
{"online_battle_play_count": tips["online_battle_play_count"] + 1},
)
round_info = await self._update_round_info(user_id, self.round_event_id, data.pop("round_point"), data.pop("win_flg"))
return {
"status_code": "0",
"vsinfo_data": vs_info,
"round_event": round_info,
"car_use_count": [],
"maker_use_count": [],
}
2024-03-12 17:20:32 +00:00
async def handle_user_updatestorebattleresult_request(
self, data: Dict, headers: Dict
):
2023-10-01 01:54:23 +00:00
user_id = headers["session"]
stock_data: Dict = data.pop("stock_obj")
ticket_data: List = data.pop("ticket_data")
reward_dist_data: Dict = data.pop("reward_dist_obj")
rank_data: Dict = data.pop("mode_rank_obj")
driver_debut_data: Dict = data.pop("driver_debut_obj")
# save the received battle gift in database, hopefully that works
2023-10-01 01:54:23 +00:00
battle_gift_event_id = data.pop("battle_gift_event_id")
gift_id = data.pop("gift_id")
await self.data.item.put_battle_gift(
user_id,
{
"battle_gift_event_id": battle_gift_event_id,
"gift_id": gift_id,
"gift_status": 1, # aquired
},
)
2023-10-01 01:54:23 +00:00
# save stock data in database
2024-01-09 19:42:17 +00:00
await self._save_stock_data(user_id, stock_data)
2023-10-01 01:54:23 +00:00
# save tickets in database
for ticket in ticket_data:
2024-01-09 19:42:17 +00:00
await self.data.item.put_ticket(user_id, ticket)
2023-10-01 01:54:23 +00:00
# save rank dist data in database
rank_data.update(reward_dist_data)
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile_rank(user_id, self.version, rank_data)
2023-10-01 01:54:23 +00:00
# get the use_count and net_vs_use_count of the used car
style_car_id = data.get("style_car_id")
car_mileage = data.pop("car_mileage")
2024-02-09 15:48:39 +00:00
used_car = await self.data.item.get_car(user_id, self.version, style_car_id)
used_car = used_car._asdict()
2023-10-01 01:54:23 +00:00
# increase the use_count and net_vs_use_count of the used car
used_car["use_count"] += 1
used_car["vs_use_count"] += 1
2023-10-01 01:54:23 +00:00
used_car["car_mileage"] = car_mileage
# save the used car in database
2024-01-09 19:42:17 +00:00
await self.data.item.put_car(user_id, self.version, used_car)
2023-10-01 01:54:23 +00:00
# get the profile data, update total_play and daily_play, and save it
2024-01-09 19:42:17 +00:00
profile = await self.data.profile.get_profile(user_id, self.version)
2023-10-01 01:54:23 +00:00
total_play = profile["total_play"] + 1
# save the profile in database
2024-01-09 19:42:17 +00:00
await self.data.profile.put_profile(
2023-10-01 01:54:23 +00:00
user_id,
self.version,
{
"total_play": total_play,
"last_play_date": datetime.now(),
"mileage": data.pop("mileage"),
"aura_id": data.pop("aura_id"),
"aura_color_id": data.pop("aura_color_id"),
"aura_line_id": data.pop("aura_line_id"),
"cash": data.pop("cash"),
"total_cash": data.pop("total_cash"),
"dressup_point": data.pop("dressup_point"),
"avatar_point": data.pop("avatar_point"),
},
)
# save vs_info in database
2024-03-12 17:20:32 +00:00
vs_info = await self._update_vs_info(
user_id, IDACConstants.BATTLE_MODE_OFFLINE, data
)
2023-10-01 01:54:23 +00:00
# update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips(
user_id,
self.version,
{"store_battle_play_count": tips["store_battle_play_count"] + 1},
)
2023-10-01 01:54:23 +00:00
return {
"status_code": "0",
"vsinfo_data": vs_info,
"car_use_count": [],
"maker_use_count": [],
}
async def handle_factory_numberlotterybefore_request(self, data: Dict, headers: Dict):
user_id = headers["session"]
win_list = []
lottery_count = 0
# retrieve the lottery data for the user
l = await self.data.factory.get_lottery(user_id, self.version)
if l:
# check if create_data is younger than 24 hours
if datetime.now() - l["create_date"] < timedelta(days=1):
lottery_count = l["lottery_count"]
saved_value = int(l["saved_value"])
# check each of the first 10 bits in saved_value
for number in range(10):
if saved_value & 1:
# if the least significant bit is 1, add to the win_list
win_list.append({
"m_number_lottery_schedule_no": 1,
"win_number": number * 1111
})
# right shift saved_value to check the next bit
saved_value >>= 1
return {
"status_code": "0",
"lottery_info": {
"lottery_count": lottery_count,
"win_list": win_list
}
}
async def handle_factory_numberlotteryresult_request(self, data: Dict, headers: Dict):
user_id = headers["session"]
win_number = data.pop("win_number")
lottery_count = data.pop("lottery_count")
style_car_id = data.pop("style_car_id")
license_no = data.pop("l_no")
is_end = data.pop("isEnd")
ticket_data = data.pop("ticket_data")
# retrieve the lottery data for the user
l = await self.data.factory.get_lottery(user_id, self.version)
create_date = l["create_date"] if l else datetime.now()
saved_value = l["saved_value"] if l else 0
if win_number != 10000:
# calculate the bit position to set based on the win_number
shifted = win_number // 1111
saved_value += 1 << shifted
# update the create_date timestamp when the last create_date is older than 24 hours
if l and datetime.now() - l["create_date"] > timedelta(days=1):
create_date = datetime.now()
# update the lottery data with the new saved_value and lottery_count
await self.data.factory.put_lottery(user_id, self.version, saved_value, lottery_count, create_date)
if license_no != 10000 and is_end == 1:
# ithe lottery is ended, save car data
await self.data.item.put_car(user_id, self.version, {
"style_car_id": style_car_id,
"l_no": license_no
})
# save each ticket data
for ticket in ticket_data:
await self.data.item.put_ticket(user_id, ticket)
# save remaining profile data
await self.data.profile.put_profile(user_id, self.version, data)
return {
"status_code": "0"
}