Merge branch 'master' into idac

This commit is contained in:
Dniel97
2026-06-14 21:36:13 +02:00
36 changed files with 653 additions and 168 deletions
@@ -15,6 +15,9 @@ from titles.idac.service.season2.advertise_service import IDACSeason2AdvertiseSe
class IDACSeason2AdvertiseController:
RequestAdvertiseGetRankingData = RequestSeason2AdvertiseGetRankingData
ResponseAdvertiseGetRankingData = ResponseSeason2AdvertiseGetRankingData
def __init__(
self,
core_cfg: CoreConfig,
@@ -35,13 +38,13 @@ class IDACSeason2AdvertiseController:
async def handle_get_ranking_data_request(
self, data: Dict, headers: Dict
) -> ResponseSeason2AdvertiseGetRankingData:
req = RequestSeason2AdvertiseGetRankingData.model_validate(data)
req = self.RequestAdvertiseGetRankingData.model_validate(data)
req_headers = RequestSeason2Headers.model_validate(headers)
national_best_data = await self.advertise_service.get_national_best_data(
req.last_update_date
)
return ResponseSeason2AdvertiseGetRankingData(
return self.ResponseAdvertiseGetRankingData(
national_best_data=national_best_data
)
@@ -6,10 +6,15 @@ from core.config import CoreConfig
from titles.idac.config import IDACServerConfig
from titles.idac.const import IDACConstants
from titles.idac.gameconfig.season2_config import IDACSeason2Config
from titles.idac.model.season2.alive_model import ResponseSeason2AliveGet
from titles.idac.model.season2.alive_model import (
RequestSeason2AliveGet,
ResponseSeason2AliveGet,
)
from titles.idac.model.season2.common_model import RequestSeason2Headers
class IDACSeason2AliveController:
ReuqestAliveGet = RequestSeason2AliveGet
ResponseAliveGet = ResponseSeason2AliveGet
def __init__(
@@ -25,6 +30,9 @@ class IDACSeason2AliveController:
self.version = IDACConstants.VER_IDAC_SEASON_2
async def handle_get_request(self, data: Dict, headers: Dict) -> ResponseAliveGet:
req = self.ReuqestAliveGet.model_validate(data)
req_headers = RequestSeason2Headers.model_validate(headers)
return self.ResponseAliveGet(
server_status=1,
force_reboot_time=int(datetime.now().timestamp()) - 86400,
@@ -16,16 +16,23 @@ from titles.idac.const import (
)
from titles.idac.gameconfig.season2_config import IDACSeason2Config
from titles.idac.model.common_model import ResponseGeneric, Reward
from titles.idac.model.season2.boot_model import (
ResponseSeason2BootGetConfigData,
ResponseSeason2BootGetGachaData,
ResponseSeason2BootGetTimeReleaseData,
)
from titles.idac.model.season2.boot_model import *
from titles.idac.model.season2.common_model import RequestSeason2Headers
class IDACSeason2BootController:
RequestBootBookkeeping = RequestSeason2BootBookkeeping
ResponseBootBookkeeping = ResponseSeason2BootBookkeeping
RequestBootGetGachaData = RequestSeason2BootGetGachaData
ResponseBootGetGachaData = ResponseSeason2BootGetGachaData
RequestBootGetConfigData = RequestSeason2BootGetConfigData
ResponseBootGetConfigData = ResponseSeason2BootGetConfigData
RequestBootGetTimeReleaseData = RequestSeason2BootGetTimeReleaseData
ResponseBootGetTimeReleaseData = ResponseSeason2BootGetTimeReleaseData
def __init__(
self,
core_cfg: CoreConfig,
@@ -85,36 +92,36 @@ class IDACSeason2BootController:
if self.game_cfg.last_round_info:
self.last_round_event = [self.game_cfg.last_round_info]
def _headers_to_version(self, headers: Dict) -> int:
version = headers.get("device_version", "1.00.00")
return int(version.replace(".", "")[:-2])
def _special_story_type(self, headers: Dict) -> StoryTypeEnum:
ver = self._headers_to_version(headers)
def _headers_to_version(self, headers: RequestSeason2Headers) -> int:
return int(headers.device_version.replace(".", "")[:-2])
def _special_story_type(self, version: int) -> StoryTypeEnum:
return {
150: StoryTypeEnum.TOUHOU_1ST,
170: StoryTypeEnum.MIKU,
}.get(ver, 0)
}.get(version, 0)
async def handle_get_config_data_request(
self, data: Dict, headers: Dict
) -> ResponseSeason2BootGetConfigData:
ver_str = self._headers_to_version(headers)
) -> ResponseBootGetConfigData:
req = self.RequestBootGetGachaData.model_validate(data)
req_headers = RequestSeason2Headers.model_validate(headers)
ver = self._headers_to_version(req_headers)
# TODO: properly set the domain name
hostname = "sega-initiald.net"
if self.core_cfg.server.is_using_proxy:
domain_api_game = f"http://{hostname}/{ver_str}/"
domain_api_game = f"http://{hostname}/{ver}/"
else:
domain_api_game = (
f"http://{hostname}:{Utils.get_title_port(self.core_cfg)}/{ver_str}/"
f"http://{hostname}:{Utils.get_title_port(self.core_cfg)}/{ver}/"
)
# sets the special mode data if the version supports the special mode
special_mode_data = None
special_story_type = self._special_story_type(headers)
special_story_type = self._special_story_type(ver)
if special_story_type != StoryTypeEnum.NONE:
special_mode_data = ResponseSeason2BootGetConfigData.SpecialModeData(
start_dt=datetime(2023, 1, 1),
@@ -123,18 +130,18 @@ class IDACSeason2BootController:
)
battle_gift_event = []
if ver_str in self.battle_gift_event:
battle_gift_event_data = self.battle_gift_event.get(ver_str, {})
if ver in self.battle_gift_event:
battle_gift_event_data = self.battle_gift_event.get(ver, {})
# check if battle gift event time is valid
start_dt = battle_gift_event_data.start_dt
end_dt = battle_gift_event_data.end_dt
if start_dt < datetime.now() < end_dt:
battle_gift_event = [battle_gift_event_data]
stamp_info: list[ResponseSeason2BootGetConfigData.StampInfo] = []
if ver_str in self.stamp_info:
stamp_info_data = self.stamp_info.get(ver_str, [])
if ver in self.stamp_info:
stamp_info_data = self.stamp_info.get(ver, [])
# check if stamp event time is valid
start_dt = self.game_cfg.stamp.open_dt
end_dt = self.game_cfg.stamp.close_dt
@@ -234,7 +241,6 @@ class IDACSeason2BootController:
domain_echo2=f"{hostname}:{self.server_cfg.echo2}",
domain_ping=f"{hostname}",
battle_gift_event_master=battle_gift_event,
# 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,
@@ -250,18 +256,24 @@ class IDACSeason2BootController:
theory_open_version="1.40.00",
# unlocks the version specific special mode
special_mode_data=special_mode_data,
timetrial_event_data=self.timetrial_event.get(ver_str, None),
timetrial_event_data=self.timetrial_event.get(ver, None),
number_lottery_data=number_lottery_data,
)
async def handle_bookkeep_request(
self, data: Dict, headers: Dict
) -> ResponseGeneric:
return ResponseGeneric()
req = self.RequestBootBookkeeping.model_validate(data)
req_headers = RequestSeason2Headers.model_validate(headers)
return self.ResponseBootBookkeeping()
async def handle_get_gacha_data_request(
self, data: Dict, headers: Dict
) -> ResponseSeason2BootGetGachaData:
) -> ResponseBootGetGachaData:
req = self.RequestBootGetGachaData.model_validate(data)
req_headers = RequestSeason2Headers.model_validate(headers)
# TODO: add support for multiple seasons (maybe even multiple vesions of the same season?)
with open("./titles/idac/data/avatarGacha.json", encoding="UTF-8") as f:
avatar_gacha_data = f.read()
@@ -271,7 +283,10 @@ class IDACSeason2BootController:
async def handle_get_timerelease_data_request(
self, data: Dict, headers: Dict
) -> ResponseSeason2BootGetTimeReleaseData:
) -> ResponseBootGetTimeReleaseData:
req = self.RequestBootGetTimeReleaseData.model_validate(data)
req_headers = RequestSeason2Headers.model_validate(headers)
"""
timerelease chapter:
1 = Story: 1, 2, 3, 4, 5, 6, 7, 8, 9, 19 (Chapter 10), 29 (Chapter 11)
@@ -283,10 +298,9 @@ class IDACSeason2BootController:
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])
ver = self._headers_to_version(req_headers)
timerelease_filename = f"timeRelease_v{device_version:04d}"
timerelease_filename = f"timeRelease_v{ver:04d}"
timerelease_path = f"{path}{timerelease_filename}.json"
# if the file doesn't exist, try to find the next lowest version
@@ -305,7 +319,7 @@ class IDACSeason2BootController:
with open(f"{path}{timerelease_filename}.json", encoding="utf-8") as f:
time_release_data = f.read()
resp = ResponseSeason2BootGetTimeReleaseData.model_validate_json(
resp = self.ResponseBootGetTimeReleaseData.model_validate_json(
time_release_data
)
@@ -30,6 +30,7 @@ from titles.idac.model.season2.time_trial_model import TrialDto
from titles.idac.model.season2.user_model import *
from titles.idac.service.season2.arcade_service import IDACSeason2ArcadeService
from titles.idac.service.season2.factory_service import IDACSeason2FactoryService
from titles.idac.service.season2.round_service import IDACSeason2RoundService
from titles.idac.service.season2.time_trial_service import IDACSeason2TimeTrialService
from titles.idac.service.season2.user_service import IDACSeason2UserService
@@ -62,6 +63,9 @@ class IDACSeason2UserController:
RequestUserGetPastSeasonTAData = RequestSeason2UserGetPastSeasonTAData
ResponseUserGetPastSeasonTAData = ResponseSeason2UserGetPastSeasonTAData
RequestUserGetPastSeasonRoundData = RequestSeason2UserGetPastSeasonRoundData
ResponseUserGetPastSeasonRoundData = ResponseSeason2UserGetPastSeasonRoundData
RequestUserGetTAData = RequestSeason2UserGetTAData
ResponseUserGetTAData = ResponseSeason2UserGetTAData
@@ -89,6 +93,7 @@ class IDACSeason2UserController:
user_service: IDACSeason2UserService,
time_trial_service: IDACSeason2TimeTrialService,
factory_service: IDACSeason2FactoryService,
round_service: IDACSeason2RoundService,
) -> None:
self.core_cfg = core_cfg
self.sever_cfg = server_cfg
@@ -102,6 +107,7 @@ class IDACSeason2UserController:
self.user_service = user_service
self.time_trial_service = time_trial_service
self.factory_service = factory_service
self.round_service = round_service
def _headers_to_version(self, headers: RequestSeason2UserHeaders) -> int:
version = headers.device_version
@@ -367,7 +373,9 @@ class IDACSeason2UserController:
stamp_dto.daily_bonus = 0
# find the monday of the current week at 12am
start_of_this_monday = start_of_today - timedelta(days=start_of_today.weekday())
start_of_this_monday = start_of_today - timedelta(
days=start_of_today.weekday()
)
# if their last weekly stamp was before this monday, reset the weekly stamp
if stamp_dto.create_date_weekly < start_of_this_monday:
@@ -484,6 +492,27 @@ class IDACSeason2UserController:
past_season_timetrial_data=past_season_timetrial_data,
)
async def handle_get_past_season_round_data_request(
self, data: Dict, headers: Dict
) -> ResponseUserGetPastSeasonRoundData:
req_headers = RequestSeason2UserHeaders.model_validate(headers)
req = self.RequestUserGetPastSeasonRoundData.model_validate(data)
user_id = req_headers.session
# season 1 starts with 1, but our db expects 0 for season 1
season_id = req.season_id - 1
past_season_round_event_data = (
await self.round_service.generate_season_round_event_data(
user_id, season_id
)
)
return self.ResponseUserGetPastSeasonRoundData(
season_id=req.season_id,
past_season_round_event_data=past_season_round_event_data,
)
async def handle_update_login_request(
self, data: Dict, headers: Dict
) -> ResponseUserUpdateLogin:
@@ -985,8 +1014,9 @@ class IDACSeason2UserController:
user_id, VSInfoBattleModeEnum.INSTORE, req
)
vsinfo_data = await self.user_service.get_profile_vs_info_by_mode(
user_id, VSInfoBattleModeEnum.INSTORE
# update tips play count
await self.user_service.update_tips_play_count(
user_id, TipsGameModeEnum.STORE_BATTLE
)
# get the user's car list
@@ -1001,9 +1031,8 @@ class IDACSeason2UserController:
vs_use_count=True,
)
# update tips play count
await self.user_service.update_tips_play_count(
user_id, TipsGameModeEnum.STORE_BATTLE
vsinfo_data = await self.user_service.get_profile_vs_info_by_mode(
user_id, VSInfoBattleModeEnum.INSTORE
)
car_use_count = self.factory_service.calculate_car_use_count(car_dto_list)
@@ -1036,6 +1065,12 @@ class IDACSeason2UserController:
await self.user_service.update_profile_vs_info(
user_id, VSInfoBattleModeEnum.ONLINE, req
)
# update tips play count
await self.user_service.update_tips_play_count(
user_id, TipsGameModeEnum.ONLINE_BATTLE
)
vsinfo_data = await self.user_service.get_profile_vs_info_by_mode(
user_id, VSInfoBattleModeEnum.ONLINE
)
@@ -1053,11 +1088,6 @@ class IDACSeason2UserController:
net_vs_use_count=True,
)
# update tips play count
await self.user_service.update_tips_play_count(
user_id, TipsGameModeEnum.ONLINE_BATTLE
)
car_use_count = self.factory_service.calculate_car_use_count(car_dto_list)
maker_use_count = self.factory_service.calculate_maker_use_count(car_dto_list)
@@ -6,10 +6,17 @@ from titles.idac.gameconfig.season3_config import IDACSeason3Config
from titles.idac.controller.season2.advertise_controller import (
IDACSeason2AdvertiseController,
)
from titles.idac.model.season3.advertise_model import (
RequestSeason3AdvertiseGetRankingData,
ResponseSeason3AdvertiseGetRankingData,
)
from titles.idac.service.season3.advertise_service import IDACSeason3AdvertiseService
class IDACSeason3AdvertiseController(IDACSeason2AdvertiseController):
RequestAdvertiseGetRankingData = RequestSeason3AdvertiseGetRankingData
ResponseAdvertiseGetRankingData = ResponseSeason3AdvertiseGetRankingData
def __init__(
self,
core_cfg: CoreConfig,
@@ -4,9 +4,13 @@ from titles.idac.config import IDACServerConfig
from titles.idac.const import IDACConstants
from titles.idac.controller.season2.alive_controller import IDACSeason2AliveController
from titles.idac.gameconfig.season3_config import IDACSeason3Config
from titles.idac.model.season3.alive_model import RequestSeason3AliveGet, ResponseSeason3AliveGet
class IDACSeason3AliveController(IDACSeason2AliveController):
ReuqestAliveGet = RequestSeason3AliveGet
ResponseAliveGet = ResponseSeason3AliveGet
def __init__(
self,
core_cfg: CoreConfig,
@@ -7,12 +7,20 @@ from titles.idac.config import IDACServerConfig
from titles.idac.const import IDACConstants, StoryTypeEnum
from titles.idac.controller.season2.boot_controller import IDACSeason2BootController
from titles.idac.gameconfig.season3_config import IDACSeason3Config
from titles.idac.model.season3.boot_model import ResponseSeason3BootGetConfigData
from titles.idac.model.season3.boot_model import *
from titles.idac.model.season3.common_model import RequestSeason3Headers
class IDACSeason3BootController(IDACSeason2BootController):
RequestBootBookkeeping = RequestSeason3BootBookkeeping
ResponseBootBookkeeping = ResponseSeason3BootBookkeeping
RequestBootGetGachaData = RequestSeason3BootGetGachaData
ResponseBootGetConfigData = ResponseSeason3BootGetConfigData
RequestBootGetTimeReleaseData = RequestSeason3BootGetTimeReleaseData
ResponseBootGetTimeReleaseData = ResponseSeason3BootGetTimeReleaseData
def __init__(
self,
core_cfg: CoreConfig,
@@ -25,12 +33,10 @@ class IDACSeason3BootController(IDACSeason2BootController):
self.version = IDACConstants.VER_IDAC_SEASON_3
def _special_story_type(self, headers: Dict) -> StoryTypeEnum:
ver = self._headers_to_version(headers)
def _special_story_type(self, version: int) -> StoryTypeEnum:
return {
210: StoryTypeEnum.HOT_VERSION,
}.get(ver, 0)
}.get(version, 0)
async def handle_get_config_data_request(
self, data: Dict, headers: Dict
@@ -6,9 +6,7 @@ from core.config import CoreConfig
from titles.idac.config import IDACServerConfig
from titles.idac.const import IDACConstants
from titles.idac.gameconfig.season3_config import IDACSeason3Config
from titles.idac.model.season2.common_model import RequestSeason2UserHeaders
from titles.idac.model.season3.common_model import *
from titles.idac.model.season3.result_model import *
from titles.idac.model.season3.team_model import *
from titles.idac.service.season3.team_service import IDACSeason3TeamService
from titles.idac.service.season3.user_service import IDACSeason3UserService
@@ -36,7 +34,7 @@ class IDACSeason3TeamController:
async def handle_create_team_request(
self, data: Dict, headers: Dict
) -> ResponseSeason3CreateTeam:
req_headers = RequestSeason2UserHeaders.model_validate(headers)
req_headers = RequestSeason3UserHeaders.model_validate(headers)
req = RequestSeason3CreateTeam.model_validate(data)
user_id = req_headers.session
@@ -5,11 +5,11 @@ from titles.idac.config import IDACServerConfig
from titles.idac.const import IDACConstants
from titles.idac.controller.season2.user_controller import IDACSeason2UserController
from titles.idac.gameconfig.season3_config import IDACSeason3Config
from titles.idac.model.season2.common_model import RequestSeason2UserHeaders
from titles.idac.model.season3.common_model import RequestSeason3UserHeaders
from titles.idac.model.season3.user_model import *
from titles.idac.service.season2.factory_service import IDACSeason2FactoryService
from titles.idac.service.season3.arcade_service import IDACSeason3ArcadeService
from titles.idac.service.season3.factory_service import IDACSeason3FactoryService
from titles.idac.service.season3.round_service import IDACSeason3RoundService
from titles.idac.service.season3.team_service import IDACSeason3TeamService
from titles.idac.service.season3.time_trial_service import IDACSeason3TimeTrialService
from titles.idac.service.season3.user_service import IDACSeason3UserService
@@ -54,7 +54,8 @@ class IDACSeason3UserController(IDACSeason2UserController):
arcade_service: IDACSeason3ArcadeService,
user_service: IDACSeason3UserService,
time_trial_service: IDACSeason3TimeTrialService,
factory_service: IDACSeason2FactoryService,
factory_service: IDACSeason3FactoryService,
round_service: IDACSeason3RoundService,
team_service: IDACSeason3TeamService,
) -> None:
super().__init__(
@@ -65,13 +66,14 @@ class IDACSeason3UserController(IDACSeason2UserController):
user_service,
time_trial_service,
factory_service,
round_service,
)
self.version = IDACConstants.VER_IDAC_SEASON_3
self.team_service = team_service
def _special_story_type(self, headers: RequestSeason2UserHeaders) -> StoryTypeEnum:
def _special_story_type(self, headers: RequestSeason3UserHeaders) -> StoryTypeEnum:
ver = self._headers_to_version(headers)
return {210: StoryTypeEnum.HOT_VERSION}.get(ver, StoryTypeEnum.NONE)
@@ -103,12 +105,16 @@ class IDACSeason3UserController(IDACSeason2UserController):
if not claimed_rewards:
team_id = team_info.team_id
# get past league info
last_league_info = await self.team_service.get_past_league_info(team_id, user_id)
last_league_info = await self.team_service.get_past_league_info(
team_id, user_id
)
# generate league rewards based on the last league
league_rewards = self.team_service.generate_league_rewards(last_league_info)
league_rewards = self.team_service.generate_league_rewards(
last_league_info
)
# claim rewards for the user to prevent duplicate claiming
await self.team_service.update_past_league_rewards(user_id, team_id)
@@ -205,7 +211,7 @@ class IDACSeason3UserController(IDACSeason2UserController):
async def handle_update_theory_result_request(
self, data: Dict, headers: Dict
) -> ResponseUserUpdateTheoryResult:
req_headers = RequestSeason2UserHeaders.model_validate(headers)
req_headers = RequestSeason3UserHeaders.model_validate(headers)
req = self.RequestUserUpdateTheoryResult.model_validate(data)
resp: ResponseSeason3UserUpdateTheoryResult = (
@@ -228,7 +234,7 @@ class IDACSeason3UserController(IDACSeason2UserController):
async def handle_update_challenge_mode_result_request(
self, data: Dict, headers: Dict
) -> ResponseUserUpdateChallengeModeResult:
req_headers = RequestSeason2UserHeaders.model_validate(headers)
req_headers = RequestSeason3UserHeaders.model_validate(headers)
req = self.RequestUserUpdateChallengeModeResult.model_validate(data)
resp: ResponseSeason3UserUpdateChallengeModeResult = (
@@ -251,7 +257,7 @@ class IDACSeason3UserController(IDACSeason2UserController):
async def handle_update_store_battle_result_request(
self, data: Dict, headers: Dict
) -> ResponseUserUpdateStoreBattleResult:
req_headers = RequestSeason2UserHeaders.model_validate(headers)
req_headers = RequestSeason3UserHeaders.model_validate(headers)
req = self.RequestUserUpdateStoreBattleResult.model_validate(data)
resp: ResponseSeason3UserUpdateStoreBattleResult = (
@@ -274,7 +280,7 @@ class IDACSeason3UserController(IDACSeason2UserController):
async def handle_update_online_battle_result_request(
self, data: Dict, headers: Dict
) -> ResponseUserUpdateOnlineBattleResult:
req_headers = RequestSeason2UserHeaders.model_validate(headers)
req_headers = RequestSeason3UserHeaders.model_validate(headers)
req = self.RequestUserUpdateOnlineBattleResult.model_validate(data)
resp: ResponseSeason3UserUpdateOnlineBattleResult = (
+3 -1
View File
@@ -1,7 +1,9 @@
from datetime import datetime
from titles.idac.model.common_model import RequestGeneric, ResponseGeneric
RequestSeason2AliveGet = RequestGeneric
class RequestSeason2AliveGet(RequestGeneric):
pass
class ResponseSeason2AliveGet(ResponseGeneric):
+100 -2
View File
@@ -5,7 +5,8 @@ from titles.idac.const import CollaboEnum, StoryTypeEnum
from titles.idac.model.common_model import *
RequestSeason2BootGetGachaData = RequestGeneric
class RequestSeason2BootGetGachaData(RequestGeneric):
pass
class ResponseSeason2BootGetGachaData(ResponseGeneric):
@@ -29,7 +30,100 @@ class ResponseSeason2BootGetGachaData(ResponseGeneric):
avatar_gacha_data: list[AvatarGachaData]
RequestSeason2BootGetTimeReleaseData = RequestGeneric
class PlayTimezone(DtoModel):
zone: int
count: int
class RequestSeason2BootBookkeeping(RequestGeneric):
class ModeInfo(DtoModel):
class SelectCourse(DtoModel):
course_id: int
course_day: int
select_count: int
mode_id: int
play_count: int
first_count: int
continue_count: int
select_course: list[SelectCourse]
random: int
class NetworkError(DtoModel):
eth0_down: int
netrace_success: int
netrace_error: int
re_matching: int
com_down: int
api_connect_error: int
subcard_judge: int
cheat1: int
cheat2: int
class BoardInfo(DtoModel):
allnet_cert_date: datetime
board_id: str
class Playtime(DtoModel):
class TimeHistogram(DtoModel):
histogram_id: int
count: int
operating_time: int
play_total_time: int
play_total_count: int
interval: list[PlayTimezone]
longest_time: int
shortest_time: int
factory_time: int
factory_count: int
aime_play_total_time: int
aime_play_avg_time: int
time_histogram: list[TimeHistogram]
class CreditInfo(DtoModel):
total_coin: int
coin_credit: int
service_credit: int
total_credit: int
aime_first_regist: int
free_play: int
aime_credit: int
guest_credit: int
buy_car_credit: int
aime_play_first: int
aime_play_continue: int
guest_play_first: int
guest_play_continue: int
use_continue_ticket: int
get_continue_ticket: int
buy_car_count: int
use_car_ticket: int
get_car_ticket: int
class Error10History(DtoModel):
mode_id: int
error_date: int
error_text: str
bookkeep_clear: datetime
network_error: NetworkError
board_info: BoardInfo
mode_info: list[ModeInfo]
play_timezone: list[PlayTimezone]
playtime: Playtime
credit_info: CreditInfo
error10_history: Error10History
ping_data: list[PlayTimezone]
loss_data: list[PlayTimezone]
class ResponseSeason2BootBookkeeping(ResponseGeneric):
pass
class RequestSeason2BootGetTimeReleaseData(RequestGeneric):
pass
class ResponseSeason2BootGetTimeReleaseData(ResponseGeneric):
@@ -106,6 +200,10 @@ class ResponseSeason2BootGetTimeReleaseData(ResponseGeneric):
parts_list: list[PartsList]
class RequestSeason2BootGetConfigData(RequestGeneric):
pass
class ResponseSeason2BootGetConfigData(ResponseGeneric):
class BattleGiftEventMaster(DtoModel):
class BattleGiftData(DtoModel):
+22 -11
View File
@@ -103,7 +103,8 @@ class RequestSeason2FactorySaveFavoriteCar(RequestGeneric):
pickup_off_car_ids: list[PickupOffCar]
ResponseSeason2FactorySaveFavoriteCar = ResponseGeneric
class ResponseSeason2FactorySaveFavoriteCar(ResponseGeneric):
pass
class RequestSeason2FactoryUpdateCustomizeResult(RequestGeneric):
@@ -120,7 +121,8 @@ class RequestSeason2FactoryUpdateCustomizeResult(RequestGeneric):
ticket_data: list[Ticket]
ResponseSeason2FactoryUpdateCustomizeResult = ResponseGeneric
class ResponseSeason2FactoryUpdateCustomizeResult(ResponseGeneric):
pass
class RequestSeason2FactoryUpdateMultipleCustomizeResult(RequestGeneric):
@@ -140,7 +142,8 @@ class RequestSeason2FactoryUpdateMultipleCustomizeResult(RequestGeneric):
ticket_data: list[Ticket]
ResponseSeason2FactoryUpdateMultipleCustomizeResult = ResponseGeneric
class ResponseSeason2FactoryUpdateMultipleCustomizeResult(ResponseGeneric):
pass
class RequestSeason2FactoryUpdateCustomizeUser(RequestGeneric):
@@ -161,7 +164,8 @@ class RequestSeason2FactoryUpdateCustomizeUser(RequestGeneric):
stock_obj: StockData
ResponseSeason2FactoryUpdateCustomizeUser = ResponseGeneric
class ResponseSeason2FactoryUpdateCustomizeUser(ResponseGeneric):
pass
class RequestSeason2FactoryUpdateCustomizeAvatar(RequestGeneric):
@@ -169,21 +173,26 @@ class RequestSeason2FactoryUpdateCustomizeAvatar(RequestGeneric):
avatar_obj: AvatarData
ResponseSeason2FactoryUpdateCustomizeAvatar = ResponseGeneric
class ResponseSeason2FactoryUpdateCustomizeAvatar(ResponseGeneric):
pass
RequestSeason2FactoryRenameBefore = RequestGeneric
class RequestSeason2FactoryRenameBefore(RequestGeneric):
pass
ResponseSeason2FactoryRenameBefore = ResponseGeneric
class ResponseSeason2FactoryRenameBefore(ResponseGeneric):
pass
class RequestSeason2FactoryRenameResult(RequestGeneric):
username: str
ResponseSeason2FactoryRenameResult = ResponseGeneric
class ResponseSeason2FactoryRenameResult(ResponseGeneric):
pass
RequestSeason2FactoryGetCarData = RequestGeneric
class RequestSeason2FactoryGetCarData(RequestGeneric):
pass
class ResponseSeason2FactoryGetCarData(ResponseGeneric):
@@ -221,7 +230,8 @@ class ResponseSeason2FactoryGetCarData(ResponseGeneric):
car_data: list[FactoryCarData]
RequestSeason2FactoryNumberLotteryBefore = RequestGeneric
class RequestSeason2FactoryNumberLotteryBefore(RequestGeneric):
pass
class ResponseSeason2FactoryNumberLotteryBefore(ResponseGeneric):
@@ -249,4 +259,5 @@ class RequestSeason2FactoryNumberLotteryResult(RequestGeneric):
ticket_data: list[Ticket]
ResponseSeason2FactoryNumberLotteryResult = ResponseGeneric
class ResponseSeason2FactoryNumberLotteryResult(ResponseGeneric):
pass
+4 -2
View File
@@ -77,7 +77,8 @@ class RequestSeason2LogSavePlayLog(RequestGeneric):
match_error_info_arr: list[MatchErrorInfo]
ResponseSeason2LogSavePlayLog = ResponseGeneric
class ResponseSeason2LogSavePlayLog(ResponseGeneric):
pass
class RequestSeason2LogSaveEndLog(RequestGeneric):
@@ -109,4 +110,5 @@ class RequestSeason2LogSaveEndLog(RequestGeneric):
rename_cnt: int
ResponseSeason2LogSaveEndLog = ResponseGeneric
class ResponseSeason2LogSaveEndLog(ResponseGeneric):
pass
+4 -2
View File
@@ -40,14 +40,16 @@ class ResponseSeason2LoginCheckLock(ResponseGeneric):
takeover_data: list[TakeoverData]
RequestSeason2LoginUnLock = RequestGeneric
class RequestSeason2LoginUnLock(RequestGeneric):
pass
class ResponseSeason2LoginUnLock(ResponseGeneric):
lock_result: LockResultEnum
RequestSeason2LoginReLock = RequestGeneric
class RequestSeason2LoginReLock(RequestGeneric):
pass
class ResponseSeason2LoginReLock(ResponseGeneric):
-38
View File
@@ -1,38 +0,0 @@
from titles.idac.model.common_model import *
class RequestSeason2UserUpdateTimeTrialResult(RequestGeneric):
goal_time: int
section_time_1: int
section_time_2: int
section_time_3: int
section_time_4: int
style_car_id: int
car_mileage: int
course_id: int
skill_level_exp: int
mission: int
mileage: int
eval_id: int
event_point: int
stock_obj: StockData
aura_id: int
aura_color_id: int
aura_line_id: int
cash: int
total_cash: int
dressup_point: int
avatar_point: int
ticket_data: list[Ticket]
reward_dist_obj: RewardDist
driver_debut_obj: DriverDebut
mode_rank_obj: ModeRank
class ResponseSeason2UserUpdateTimeTrialResult(ResponseGeneric):
course_rank: int
course_car_rank: int
location_course_store_rank: int
car_use_count: list[CarUseCount]
maker_use_count: list[MakerUseCount]
timetrial_event_data: TimetrialEventData_2
+1
View File
@@ -4,6 +4,7 @@ from titles.idac.model.common_model import DtoModel
class RoundInfoDto(DtoModel):
id: int
round_id_in_json: int
name: str
start_dt: datetime
@@ -85,9 +85,10 @@ class ResponseSeason2TimeTrialGetBestRecordPreBattle(ResponseGeneric):
course_pickup_car_best_data: list[CourseBestCarData]
RequestSeason2TimeTrialGetBestRecordPreTA = (
class RequestSeason2TimeTrialGetBestRecordPreTA(
RequestSeason2TimeTrialGetBestRecordPreBattle
)
):
pass
class ResponseSeason2TimeTrialGetBestRecordPreTA(ResponseGeneric):
+16 -3
View File
@@ -199,10 +199,21 @@ class SeasonTimetrialData(DtoModel):
rank: int = 0
rank_dt: datetime = datetime.fromtimestamp(0, tz=timezone.utc)
class SeasonTimetrialDto(SeasonTimetrialData):
eval_id: int = 0
class SeasonRoundEventDto(DtoModel):
count: int = 0
win: int = 0
rank: int = 0
point: int = 0
total_round_point: int
round_name: str
round_id: int
class StoryDataDto(DtoModel):
class EpisodeDto(DtoModel):
class DifficultyDto(DtoModel):
@@ -538,7 +549,8 @@ class RequestSeason2UserUpdateLogin(RequestGeneric):
season_rewards_id_arr: list[RewardsId]
ResponseSeason2UserUpdateLogin = ResponseGeneric
class ResponseSeason2UserUpdateLogin(ResponseGeneric):
pass
class ProfileResult(DtoModel):
@@ -687,7 +699,7 @@ class RequestSeason2UserGetPastSeasonRoundData(RequestGeneric):
class ResponseSeason2UserGetPastSeasonRoundData(ResponseGeneric):
class PastSeasonRoundEventData(BaseModel):
class PastSeasonRoundEventData(DtoModel):
count: int
win: int
rank: int
@@ -878,4 +890,5 @@ class RequestSeason2UserUpdateStampInfo(BaseModel):
stamp_event_data: list[Season2StampEvent]
ResponseSeason2UserUpdateStampInfo = ResponseGeneric
class ResponseSeason2UserUpdateStampInfo(ResponseGeneric):
pass
@@ -0,0 +1,10 @@
from titles.idac.model.season2.advertise_model import RequestSeason2AdvertiseGetRankingData, ResponseSeason2AdvertiseGetRankingData
class RequestSeason3AdvertiseGetRankingData(RequestSeason2AdvertiseGetRankingData):
pass
class ResponseSeason3AdvertiseGetRankingData(ResponseSeason2AdvertiseGetRankingData):
pass
+12
View File
@@ -0,0 +1,12 @@
from titles.idac.model.season2.alive_model import (
RequestSeason2AliveGet,
ResponseSeason2AliveGet,
)
class RequestSeason3AliveGet(RequestSeason2AliveGet):
pass
class ResponseSeason3AliveGet(ResponseSeason2AliveGet):
pass
+21 -1
View File
@@ -1,5 +1,9 @@
from titles.idac.model.common_model import *
from titles.idac.model.season2.boot_model import ResponseSeason2BootGetConfigData
from titles.idac.model.season2.boot_model import *
class RequestSeason3BootGetGachaData(RequestSeason2BootGetGachaData):
pass
class ResponseSeason3BootGetConfigData(ResponseSeason2BootGetConfigData):
@@ -15,3 +19,19 @@ class ResponseSeason3BootGetConfigData(ResponseSeason2BootGetConfigData):
league_rewards: list[LeagueRewards] = []
league_flag: int = 0 # 0 = open league?
class RequestSeason3BootBookkeeping(RequestSeason2BootBookkeeping):
pass
class ResponseSeason3BootBookkeeping(ResponseSeason2BootBookkeeping):
pass
class RequestSeason3BootGetTimeReleaseData(RequestSeason2BootGetTimeReleaseData):
pass
class ResponseSeason3BootGetTimeReleaseData(ResponseSeason2BootGetTimeReleaseData):
pass
+24
View File
@@ -0,0 +1,24 @@
from titles.idac.model.season2.boot_model import ResponseSeason2BootGetConfigData
from titles.idac.model.season3.boot_model import ResponseSeason3BootGetConfigData
class StampInfoConfig(ResponseSeason2BootGetConfigData.StampInfo):
pass
class TimetrialConfig(ResponseSeason2BootGetConfigData.TimetrialEventData):
pass
class BattleGiftConfig(ResponseSeason2BootGetConfigData.BattleGiftEventMaster):
pass
class RoundConfig(ResponseSeason2BootGetConfigData.RoundEvent_2):
pass
class LeagueRewardConfig(
ResponseSeason3BootGetConfigData.LeagueRewards,
):
pass
+121
View File
@@ -0,0 +1,121 @@
from titles.idac.model.season2.factory_model import *
class RequestSeason3FactoryAvatarGachaResult(RequestSeason2FactoryAvatarGachaResult):
pass
class ResponseSeason3FactoryAvatarGachaResult(ResponseSeason2FactoryAvatarGachaResult):
pass
class RequestSeason3FactoryBuyCarResult(RequestSeason2FactoryBuyCarResult):
pass
class ResponseSeason3FactoryBuyCarResult(ResponseSeason2FactoryBuyCarResult):
pass
class RequestSeason3FactorySaveFavoriteCar(RequestSeason2FactorySaveFavoriteCar):
pass
class ResponseSeason3FactorySaveFavoriteCar(ResponseSeason2FactorySaveFavoriteCar):
pass
class RequestSeason3FactoryUpdateCustomizeResult(
RequestSeason2FactoryUpdateCustomizeResult
):
pass
class ResponseSeason3FactoryUpdateCustomizeResult(
ResponseSeason2FactoryUpdateCustomizeResult
):
pass
class RequestSeason3FactoryUpdateMultipleCustomizeResult(
RequestSeason2FactoryUpdateMultipleCustomizeResult
):
pass
class ResponseSeason3FactoryUpdateMultipleCustomizeResult(
ResponseSeason2FactoryUpdateMultipleCustomizeResult
):
pass
class RequestSeason3FactoryUpdateCustomizeUser(
RequestSeason2FactoryUpdateCustomizeUser
):
pass
class ResponseSeason3FactoryUpdateCustomizeUser(
ResponseSeason2FactoryUpdateCustomizeUser
):
pass
class RequestSeason3FactoryUpdateCustomizeAvatar(
RequestSeason2FactoryUpdateCustomizeAvatar
):
pass
class ResponseSeason3FactoryUpdateCustomizeAvatar(
ResponseSeason2FactoryUpdateCustomizeAvatar
):
pass
class RequestSeason3FactoryRenameBefore(RequestSeason2FactoryRenameBefore):
pass
class ResponseSeason3FactoryRenameBefore(ResponseSeason2FactoryRenameBefore):
pass
class RequestSeason3FactoryRenameResult(RequestSeason2FactoryRenameResult):
pass
class ResponseSeason3FactoryRenameResult(ResponseSeason2FactoryRenameResult):
pass
class RequestSeason3FactoryGetCarData(RequestSeason2FactoryGetCarData):
pass
class ResponseSeason3FactoryGetCarData(ResponseSeason2FactoryGetCarData):
pass
class RequestSeason3FactoryNumberLotteryBefore(
RequestSeason2FactoryNumberLotteryBefore
):
pass
class ResponseSeason3FactoryNumberLotteryBefore(
ResponseSeason2FactoryNumberLotteryBefore
):
pass
class RequestSeason3FactoryNumberLotteryResult(
RequestSeason2FactoryNumberLotteryResult
):
pass
class ResponseSeason3FactoryNumberLotteryResult(
ResponseSeason2FactoryNumberLotteryResult
):
pass
+17
View File
@@ -0,0 +1,17 @@
from titles.idac.model.season2.log_model import *
class RequestSeason3LogSavePlayLog(RequestSeason2LogSavePlayLog):
pass
class ResponseSeason3LogSavePlayLog(ResponseSeason2LogSavePlayLog):
pass
class RequestSeason3LogSaveEndLog(RequestSeason2LogSaveEndLog):
pass
class ResponseSeason3LogSaveEndLog(ResponseSeason2LogSaveEndLog):
pass
+33
View File
@@ -0,0 +1,33 @@
from titles.idac.model.season2.login_model import *
class RequestSeason3LoginCheckLock(RequestSeason2LoginCheckLock):
pass
class ResponseSeason3LoginCheckLock(ResponseSeason2LoginCheckLock):
pass
class RequestSeason3LoginUnLock(RequestSeason2LoginUnLock):
pass
class ResponseSeason3LoginUnLock(ResponseSeason2LoginUnLock):
pass
class RequestSeason3LoginReLock(RequestSeason2LoginReLock):
pass
class ResponseSeason3LoginReLock(ResponseSeason2LoginReLock):
pass
class RequestSeason3LoginGuestPlay(RequestSeason2LoginGuestPlay):
pass
class ResponseSeason3LoginGuestPlay(ResponseSeason2LoginGuestPlay):
pass
-15
View File
@@ -1,15 +0,0 @@
from titles.idac.model.common_model import *
from titles.idac.model.season2.result_model import *
from titles.idac.model.season3.common_model import *
class RequestSeason3UserUpdateTimeTrialResult(
RequestSeason2UserUpdateTimeTrialResult, Season3UpdateRequestTeam
):
pass
class ResponseSeason3UserUpdateTimeTrialResult(
ResponseSeason2UserUpdateTimeTrialResult, Season3UpdateResultTeam
):
pass
+3 -1
View File
@@ -7,7 +7,9 @@ from titles.idac.model.season2.theory_model import (
Season2PowerMatch,
)
RequestSeason3TheoryMatching = RequestSeason2TheoryMatching
class RequestSeason3TheoryMatching(RequestSeason2TheoryMatching):
pass
class Season3PowerMatch(Season2PowerMatch):
@@ -0,0 +1,37 @@
from titles.idac.model.season2.time_trial_model import *
class RequestSeason3TimeTrialGetBestRecordPreRace(
RequestSeason2TimeTrialGetBestRecordPreRace
):
pass
class ResponseSeason3TimeTrialGetBestRecordPreRace(
ResponseSeason2TimeTrialGetBestRecordPreRace
):
pass
class RequestSeason3TimeTrialGetBestRecordPreBattle(
RequestSeason2TimeTrialGetBestRecordPreBattle
):
pass
class ResponseSeason3TimeTrialGetBestRecordPreBattle(
ResponseSeason2TimeTrialGetBestRecordPreBattle
):
pass
class RequestSeason3TimeTrialGetBestRecordPreTA(
RequestSeason2TimeTrialGetBestRecordPreTA
):
pass
class ResponseSeason3TimeTrialGetBestRecordPreTA(
ResponseSeason2TimeTrialGetBestRecordPreTA
):
pass
+6 -3
View File
@@ -33,7 +33,9 @@ class RequestSeason3UserUpdateLogin(RequestSeason2UserUpdateLogin):
league_rewards_id_arr: list[RequestSeason2UserUpdateLogin.RewardsId]
ResponseSeason3UserUpdateLogin = ResponseSeason2UserUpdateLogin
class ResponseSeason3UserUpdateLogin(ResponseSeason2UserUpdateLogin):
pass
class RequestSeason3UserUpdateTimeTrialResult(
RequestSeason2UserUpdateTimeTrialResult, Season3UpdateRequestTeam
@@ -119,8 +121,9 @@ class ResponseSeason3UserUpdateOnlineBattleResult(
pass
class RequestSeason2UserUpdateStampInfo(RequestSeason2UserUpdateStampInfo):
class RequestSeason3UserUpdateStampInfo(RequestSeason2UserUpdateStampInfo):
stamp_event_data: list[Season3StampEvent]
ResponseSeason3UserUpdateStampInfo = RequestSeason2UserUpdateStampInfo
class ResponseSeason3UserUpdateStampInfo(RequestSeason2UserUpdateStampInfo):
pass
+31 -15
View File
@@ -42,19 +42,17 @@ class IDACRoundDb(BaseData):
return self.mapper.round_info_to_dto(round_info_db)
async def get_all_previous_round_info(
self, season: int, current_round_id: int
self, season: int, current_round_id: Optional[int] = None
) -> list[RoundInfoDto]:
sql = (
select(RoundInfoDb)
.where(
and_(
RoundInfoDb.season == season,
RoundInfoDb.round_id_in_json < current_round_id,
)
)
.where(RoundInfoDb.season == season)
.order_by(RoundInfoDb.round_id_in_json.asc())
)
if current_round_id is not None:
sql = sql.where(RoundInfoDb.round_id_in_json < current_round_id)
result = await self.execute(sql)
round_info_db = result.scalars().all()
@@ -121,23 +119,41 @@ class IDACRoundDb(BaseData):
user_round_with_rank_list
)
async def get_user_round_info(
async def get_user_round_info_with_ranking(
self, aime_id: int, round_id: int
) -> Optional[UserRoundInfoDto]:
sql = select(UserRoundInfoDb).where(
and_(
UserRoundInfoDb.user == aime_id,
UserRoundInfoDb.round_id == round_id,
) -> Optional[UserRoundInfoWithRankDto]:
ranked_round_query = (
select(
UserRoundInfoDb,
func.rank()
.over(order_by=[UserRoundInfoDb.point.desc(), UserRoundInfoDb.play_dt])
.label("rank"),
)
.where(UserRoundInfoDb.round_id == round_id)
.subquery()
)
# Final query: Select from the subquery and filter for the specific user
sql = select(ranked_round_query).where(ranked_round_query.c.user == aime_id)
result = await self.execute(sql)
user_round_info = result.scalars().one_or_none()
user_round_info = result.one_or_none()
if user_round_info is None:
return None
return self.mapper.user_round_info_to_dto(user_round_info)
# model_validate will easily map the subquery columns and the "rank" label
return self.mapper.user_round_info_with_rank_to_dto(user_round_info)
async def get_total_round_point(self, round_id: int) -> int:
sql = select(func.sum(UserRoundInfoDb.point)).where(
UserRoundInfoDb.round_id == round_id
)
result = await self.execute(sql)
total_point = result.scalar() or 0
return total_point
async def put_user_round_info(
self, aime_id: int, round_id: int, round_data: UserRoundInfoDto
+6 -6
View File
@@ -103,7 +103,7 @@ class IDACTeamDb(BaseData):
return None
return result.lastrowid
async def delete_team(
self,
version: int,
@@ -119,9 +119,7 @@ class IDACTeamDb(BaseData):
result = await self.execute(sql)
if result is None:
self.logger.warning(
f"delete_team: Failed to delete! team_id: {team_id}"
)
self.logger.warning(f"delete_team: Failed to delete! team_id: {team_id}")
return None
return result.rowcount
@@ -210,7 +208,9 @@ class IDACTeamDb(BaseData):
UserLeagueInfoDb.team_id,
UserLeagueInfoDb.user,
UserLeagueInfoDb.version,
func.coalesce(TeamMemberDb.role, TeamRoleEnum.MEMBER.value).label("role"),
func.coalesce(TeamMemberDb.role, TeamRoleEnum.MEMBER.value).label(
"role"
),
func.coalesce(TeamMemberDb.daily_bonus, 0).label("daily_bonus"),
func.coalesce(TeamMemberDb.weekly_bonus, 0).label("weekly_bonus"),
TeamMemberDb.create_date_daily,
@@ -451,7 +451,7 @@ class IDACTeamDb(BaseData):
if league_info is None:
return None
return self.mapper.league_info_with_ranking_to_dto(league_info)
async def put_league_info(self, league_info: LeagueInfoDto) -> int:
+1
View File
@@ -87,6 +87,7 @@ class IDACSeason2(IDACBase):
self.user_service,
self.time_trial_service,
self.factory_service,
self.round_service,
),
"timetrial": IDACSeason2TimeTrialController(
self.core_cfg, self.server_cfg, self.game_cfg, self.time_trial_service
+1
View File
@@ -98,6 +98,7 @@ class IDACSeason3(IDACSeason2):
self.user_service,
self.time_trial_service,
self.factory_service,
self.round_service,
self.team_service,
),
"timetrial": IDACSeason3TimeTrialController(
@@ -6,6 +6,7 @@ from titles.idac.const import IDACConstants
from titles.idac.database import IDACData
from titles.idac.gameconfig.season2_config import IDACSeason2Config
from titles.idac.model.season2.round_model import RoundInfoDto
from titles.idac.model.season2.user_model import SeasonRoundEventDto
class IDACSeason2RoundService:
@@ -46,3 +47,36 @@ class IDACSeason2RoundService:
)
await self.data.round.put_round_info(self.version, current_round_info)
async def generate_season_round_event_data(
self, user_id: int, season_id: int
) -> list[SeasonRoundEventDto]:
# get all previous rounds of that season
round_info_list = await self.data.round.get_all_previous_round_info(season_id)
past_season_round_event_data: list[SeasonRoundEventDto] = []
for round_info in round_info_list:
round_id = round_info.id
total_round_point = await self.data.round.get_total_round_point(round_id)
user_round_info = await self.data.round.get_user_round_info_with_ranking(
user_id, round_id
)
season_round_event_data = SeasonRoundEventDto(
total_round_point=total_round_point,
round_name=round_info.name,
round_id=round_id,
)
if user_round_info:
season_round_event_data.count = user_round_info.count
season_round_event_data.win = user_round_info.win
season_round_event_data.point = user_round_info.point
season_round_event_data.rank = user_round_info.rank
past_season_round_event_data.append(season_round_event_data)
return past_season_round_event_data
@@ -1,5 +1,6 @@
from core.config import CoreConfig
from titles.idac.config import IDACConfig, IDACServerConfig
from titles.idac.config import IDACServerConfig
from titles.idac.const import IDACConstants
from titles.idac.gameconfig.season3_config import IDACSeason3Config
from titles.idac.service.season2.arcade_service import IDACSeason2ArcadeService
@@ -1,6 +1,6 @@
from core.config import CoreConfig
from titles.idac.config import IDACConfig, IDACServerConfig
from titles.idac.config import IDACServerConfig
from titles.idac.const import IDACConstants
from titles.idac.gameconfig.season3_config import IDACSeason3Config
from titles.idac.model.common_model import *