idac: added support for basic 1.70

- Added special mode based on device version
- Added number plate lottery
- Updated online battle rounds handling
This commit is contained in:
Dniel97 2024-06-12 23:43:42 +02:00
parent d5b2074945
commit ba5591cd81
Signed by untrusted user: Dniel97
GPG Key ID: 6180B3C768FB2E08
12 changed files with 277 additions and 127 deletions

View File

@ -1,6 +1,12 @@
# Changelog # Changelog
Documenting updates to ARTEMiS, to be updated every time the master branch is pushed to. Documenting updates to ARTEMiS, to be updated every time the master branch is pushed to.
## 20240612
+ Support Initial D THE ARCADE v1.70
+ Added special mode based on device version
+ Added number plate lottery
+ Updated online battle rounds handling
## 20240526 ## 20240526
+ Fixed missing awaits causing coroutine error + Fixed missing awaits causing coroutine error

View File

@ -1,7 +1,7 @@
"""idac rounds event info added """idac rounds event info added
Revision ID: 202d1ada1b39 Revision ID: 202d1ada1b39
Revises: e4e8d89c9b02 Revises: 7dc13e364e53
Create Date: 2024-05-03 15:51:02.384863 Create Date: 2024-05-03 15:51:02.384863
""" """
@ -12,7 +12,7 @@ from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '202d1ada1b39' revision = '202d1ada1b39'
down_revision = 'e4e8d89c9b02' down_revision = '7dc13e364e53'
branch_labels = None branch_labels = None
depends_on = None depends_on = None
@ -22,7 +22,7 @@ def upgrade():
"idac_round_info", "idac_round_info",
sa.Column("id", sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column("round_id_in_json", sa.Integer(), nullable=True), sa.Column("round_id_in_json", sa.Integer(), nullable=True),
sa.Column("name", String(64), nullable=True), sa.Column("name", sa.String(64), nullable=True),
sa.Column("season", sa.Integer(), nullable=True), sa.Column("season", sa.Integer(), nullable=True),
sa.Column( sa.Column(
"start_dt", "start_dt",

View File

@ -1,4 +1,4 @@
"""idac plate number lottery added """IDAC plate number lottery added
Revision ID: 7e98c2c328b1 Revision ID: 7e98c2c328b1
Revises: 202d1ada1b39 Revises: 202d1ada1b39
@ -24,6 +24,12 @@ def upgrade():
sa.Column("version", sa.Integer(), nullable=False), sa.Column("version", sa.Integer(), nullable=False),
sa.Column("saved_value", sa.Integer(), nullable=False), sa.Column("saved_value", sa.Integer(), nullable=False),
sa.Column("lottery_count", sa.Integer(), nullable=False), sa.Column("lottery_count", sa.Integer(), nullable=False),
sa.Column(
"create_date",
sa.TIMESTAMP(),
server_default=sa.text("now()"),
nullable=False,
),
sa.ForeignKeyConstraint( sa.ForeignKeyConstraint(
["user"], ["aime_user.id"], onupdate="cascade", ondelete="cascade" ["user"], ["aime_user.id"], onupdate="cascade", ondelete="cascade"
), ),

View File

@ -0,0 +1,26 @@
"""IDAC device_version added
Revision ID: aeb6b1e28354
Revises: 7e98c2c328b1
Create Date: 2024-05-29 17:40:45.123656
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = 'aeb6b1e28354'
down_revision = '7e98c2c328b1'
branch_labels = None
depends_on = None
def upgrade():
op.add_column('idac_profile', sa.Column('device_version', sa.String(length=7), server_default='1.50.00', nullable=True))
op.drop_column('idac_profile', 'asset_version')
def downgrade():
op.add_column('idac_profile', sa.Column('asset_version', mysql.INTEGER(), server_default="1", nullable=True))
op.drop_column('idac_profile', 'device_version')

View File

@ -733,10 +733,11 @@ python dbutils.py upgrade
### TimeRelease Chapter: ### TimeRelease Chapter:
1. Story: 1, 2, 3, 4, 5, 6, 7, 8, 9, 19 (Chapter 10), (29 Chapter 11?) 1. Story: 1, 2, 3, 4, 5, 6, 7, 8, 9, 19 (Chapter 10), (29 Chapter 11)
2. MF Ghost: 10, 11, 12, 13, 14, 15 2. MF Ghost: 10, 11, 12, 13, 14, 15
3. Bunta: 15, 16, 17, 18, 20, 21, 21, 22 3. Bunta: 15, 16, 17, 18, 20, 21, 21, 22
4. Special Event: 23, 24, 25, 26, 27, 28 (Touhou Project) 4. Touhou Project Special Event: 23, 24, 25, 26, 27, 28
5. Hatsune Miku Special Event: 36, 37, 38
### TimeRelease Courses: ### TimeRelease Courses:
@ -762,6 +763,8 @@ python dbutils.py upgrade
| 58 | Momiji Line(もみじライン) | Hillclimb(上り) | | 58 | Momiji Line(もみじライン) | Hillclimb(上り) |
| 24 | Happogahara(八方ヶ原) | Outbound(往路) | | 24 | Happogahara(八方ヶ原) | Outbound(往路) |
| 26 | Happogahara(八方ヶ原) | Inbound(復路) | | 26 | Happogahara(八方ヶ原) | Inbound(復路) |
| 28 | Nagao(長尾) | Downhill(下り) |
| 30 | Nagao(長尾) | Hillclimb(上り) |
| 40 | Sadamine(定峰) | Downhill(下り) | | 40 | Sadamine(定峰) | Downhill(下り) |
| 42 | Sadamine(定峰) | Hillclimb(上り) | | 42 | Sadamine(定峰) | Hillclimb(上り) |
| 44 | Tsuchisaka(土坂) | Outbound(往路) | | 44 | Tsuchisaka(土坂) | Outbound(往路) |

View File

@ -166,7 +166,7 @@ class IDACRoundConfig:
"idac", "idac",
"round_event", "round_event",
"enabled_round", "enabled_round",
default="S1R1", default="S2R2",
) )
@property @property
@ -176,7 +176,7 @@ class IDACRoundConfig:
"idac", "idac",
"round_event", "round_event",
"last_round", "last_round",
default="S1R1", default="S2R1",
) )

View File

@ -1,13 +1,12 @@
from typing import Dict, Optional, List from datetime import datetime
from typing import Dict, Optional
from sqlalchemy import ( from sqlalchemy import (
Table, Table,
Column, Column,
UniqueConstraint, UniqueConstraint,
PrimaryKeyConstraint,
and_, and_,
update,
) )
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON from sqlalchemy.types import Integer, TIMESTAMP
from sqlalchemy.schema import ForeignKey from sqlalchemy.schema import ForeignKey
from sqlalchemy.engine import Row from sqlalchemy.engine import Row
from sqlalchemy.sql import func, select from sqlalchemy.sql import func, select
@ -23,6 +22,7 @@ lottery = Table(
Column("version", Integer, nullable=False), Column("version", Integer, nullable=False),
Column("saved_value", Integer, nullable=False), Column("saved_value", Integer, nullable=False),
Column("lottery_count", Integer, nullable=False), Column("lottery_count", Integer, nullable=False),
Column("create_date", TIMESTAMP, server_default=func.now()),
UniqueConstraint("user", "version", name="idac_user_lottery_uk"), UniqueConstraint("user", "version", name="idac_user_lottery_uk"),
mysql_charset="utf8mb4", mysql_charset="utf8mb4",
) )
@ -41,14 +41,17 @@ class IDACFactoryData(BaseData):
return result.fetchone() return result.fetchone()
async def put_lottery( async def put_lottery(
self, aime_id: int, version: int, saved_value: int, lottery_count: int
self, aime_id: int, version: int, saved_value: int, lottery_count: int, create_date: datetime
) -> Optional[int]: ) -> Optional[int]:
lottery_data = {} lottery_data = {
lottery_data["user"] = aime_id "user": aime_id,
lottery_data["version"] = version "version": version,
lottery_data["saved_value"] = saved_value "saved_value": saved_value,
lottery_data["lottery_count"] = lottery_count "lottery_count": lottery_count,
"create_date": create_date
}
sql = insert(lottery).values(**lottery_data) sql = insert(lottery).values(**lottery_data)
conflict = sql.on_duplicate_key_update(**lottery_data) conflict = sql.on_duplicate_key_update(**lottery_data)

View File

@ -249,30 +249,6 @@ vs_course_info = Table(
mysql_charset="utf8mb4", mysql_charset="utf8mb4",
) )
round_infos = Table(
"idac_round_info",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("name", String(64)),
Column("season", Integer),
Column("start_dt", TIMESTAMP, server_default=func.now()),
Column("end_dt", TIMESTAMP, server_default=func.now()),
mysql_charset="utf8mb4",
)
round_info = Table(
"idac_user_round_info",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade")),
Column("round_id", Integer),
Column("count", Integer),
Column("win", Integer),
Column("points", Integer),
UniqueConstraint("user", "round_id", name="idac_user_round_info_uk"),
mysql_charset="utf8mb4",
)
stamp = Table( stamp = Table(
"idac_user_stamp", "idac_user_stamp",
metadata, metadata,
@ -354,7 +330,7 @@ class IDACItemData(BaseData):
return result.fetchone() return result.fetchone()
async def get_random_car(self, version: int) -> Optional[List[Row]]: async def get_random_car(self, version: int) -> Optional[List[Row]]:
sql = select(car).where(car.c.version == version).order_by(func.rand()).limit(1) sql = select(car).where(car.c.version <= version).order_by(func.rand()).limit(1)
result = await self.execute(sql) result = await self.execute(sql)
if result is None: if result is None:
@ -367,7 +343,7 @@ class IDACItemData(BaseData):
sql = select(car).where( sql = select(car).where(
and_( and_(
car.c.user == aime_id, car.c.user == aime_id,
car.c.version == version, car.c.version <= version,
car.c.style_car_id == style_car_id, car.c.style_car_id == style_car_id,
) )
) )
@ -384,7 +360,7 @@ class IDACItemData(BaseData):
sql = select(car).where( sql = select(car).where(
and_( and_(
car.c.user == aime_id, car.c.user == aime_id,
car.c.version == version, car.c.version <= version,
car.c.pickup_seq != 0, car.c.pickup_seq != 0,
) )
) )

View File

@ -28,7 +28,7 @@ profile = Table(
Column("daily_play", Integer, server_default="0"), Column("daily_play", Integer, server_default="0"),
Column("day_play", Integer, server_default="0"), Column("day_play", Integer, server_default="0"),
Column("mileage", Integer, server_default="0"), Column("mileage", Integer, server_default="0"),
Column("asset_version", Integer, server_default="1"), Column("device_version", String(7), server_default="1.50.00"),
Column("last_play_date", TIMESTAMP, server_default=func.now()), Column("last_play_date", TIMESTAMP, server_default=func.now()),
Column("mytitle_id", Integer, server_default="0"), Column("mytitle_id", Integer, server_default="0"),
Column("mytitle_efffect_id", Integer, server_default="0"), Column("mytitle_efffect_id", Integer, server_default="0"),
@ -279,7 +279,7 @@ class IDACProfileData(BaseData):
sql = select(profile).where( sql = select(profile).where(
and_( and_(
profile.c.user == aime_id, profile.c.user == aime_id,
profile.c.version == version, profile.c.version <= version,
) )
) )
@ -336,7 +336,7 @@ class IDACProfileData(BaseData):
sql = select(rank).where( sql = select(rank).where(
and_( and_(
rank.c.user == aime_id, rank.c.user == aime_id,
rank.c.version == version, rank.c.version <= version,
) )
) )
@ -349,7 +349,7 @@ class IDACProfileData(BaseData):
sql = select(stock).where( sql = select(stock).where(
and_( and_(
stock.c.user == aime_id, stock.c.user == aime_id,
stock.c.version == version, stock.c.version <= version,
) )
) )
@ -362,7 +362,7 @@ class IDACProfileData(BaseData):
sql = select(theory).where( sql = select(theory).where(
and_( and_(
theory.c.user == aime_id, theory.c.user == aime_id,
theory.c.version == version, theory.c.version <= version,
) )
) )
@ -375,7 +375,7 @@ class IDACProfileData(BaseData):
sql = select(tips).where( sql = select(tips).where(
and_( and_(
tips.c.user == aime_id, tips.c.user == aime_id,
tips.c.version == version, tips.c.version <= version,
) )
) )

View File

@ -119,11 +119,13 @@ class IDACOnlineRounds(BaseData):
async def _try_load_round_event( async def _try_load_round_event(
self, round_id: int, version: int, round_data: Dict self, round_id: int, version: int, round_data: Dict
) -> Optional[int]: ) -> Optional[int]:
sql = select(round_details).where( sql = select(round_details).where(
round_details.c.round_id_in_json == round_id round_details.c.round_id_in_json == round_id
) )
result = await self.execute(sql) result = await self.execute(sql)
rid = result.fetchone() rid = result.fetchone()
if rid is None: if rid is None:
tmp = {} tmp = {}
tmp["round_id_in_json"] = round_id tmp["round_id_in_json"] = round_id
@ -131,8 +133,11 @@ class IDACOnlineRounds(BaseData):
tmp["season"] = version tmp["season"] = version
tmp["start_dt"] = datetime.datetime.fromtimestamp(round_data["start_dt"]) tmp["start_dt"] = datetime.datetime.fromtimestamp(round_data["start_dt"])
tmp["end_dt"] = datetime.datetime.fromtimestamp(round_data["end_dt"]) tmp["end_dt"] = datetime.datetime.fromtimestamp(round_data["end_dt"])
sql = insert(round_details).values(**tmp) sql = insert(round_details).values(**tmp)
result = await self.execute(sql) result = await self.execute(sql)
return result.lastrowid return result.lastrowid
return rid["id"] return rid["id"]
#TODO: get top five players of last round event for Boot/GetConfigData
# TODO: get top five players of last round event for Boot/GetConfigData

View File

@ -93,12 +93,11 @@ class IDACSeason2(IDACBase):
# Load current round event # Load current round event
round = self.game_config.round_event.enabled_round round = self.game_config.round_event.enabled_round
if round is not None: if round is not None:
if not os.path.exists(f"./titles/idac/data/rounds/season{self.version+1}/{round}.json"): 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!") self.logger.warning(f"Round info {round} is enabled but json file does not exist!")
else: else:
with open( with open(path, encoding="UTF-8") as f:
f"./titles/idac/data/rounds/season{self.version+1}/{round}.json", encoding="UTF-8"
) as f:
self.logger.debug(f"Loading round info {round}...") self.logger.debug(f"Loading round info {round}...")
tmp = json.load(f) 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_id = await self.data.rounds._try_load_round_event(tmp["round_event_id"], self.version, tmp)
@ -108,12 +107,11 @@ class IDACSeason2(IDACBase):
# Load last round event # Load last round event
round = self.game_config.round_event.last_round round = self.game_config.round_event.last_round
if round is not None: if round is not None:
if not os.path.exists(f"./titles/idac/data/rounds/season{self.version+1}/{round}.json"): 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!") self.logger.warning(f"Round info {round} is enabled but json file does not exist!")
else: else:
with open( with open(path, encoding="UTF-8") as f:
f"./titles/idac/data/rounds/season{self.version+1}/{round}.json", encoding="UTF-8"
) as f:
self.logger.debug(f"Loading round info {round}...") self.logger.debug(f"Loading round info {round}...")
tmp = json.load(f) 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_id = await self.data.rounds._try_load_round_event(tmp["round_event_id"], self.version, tmp)
@ -217,6 +215,16 @@ class IDACSeason2(IDACBase):
output[key] = value output[key] = value
return output 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)
async def handle_boot_getconfigdata_request(self, data: Dict, headers: Dict): async def handle_boot_getconfigdata_request(self, data: Dict, headers: Dict):
""" """
category: category:
@ -255,6 +263,18 @@ class IDACSeason2(IDACBase):
else: else:
domain_api_game = f"http://{self.core_cfg.server.hostname}:{Utils.get_title_port(self.core_cfg)}/{ver_str}/" domain_api_game = f"http://{self.core_cfg.server.hostname}:{Utils.get_title_port(self.core_cfg)}/{ver_str}/"
# 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
}
return { return {
"status_code": "0", "status_code": "0",
"free_continue_enable": 1, "free_continue_enable": 1,
@ -456,14 +476,90 @@ class IDACSeason2(IDACBase):
"theory_open_version": "1.30.00", "theory_open_version": "1.30.00",
"theory_close_version": "9.99.99", "theory_close_version": "9.99.99",
# unlocks the version specific special mode # unlocks the version specific special mode
"special_mode_data": { "special_mode_data": 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": 4, # touhou special event
},
"timetrial_event_data": self.timetrial_event, "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,
},
],
} }
async def handle_boot_bookkeep_request(self, data: Dict, headers: Dict): async def handle_boot_bookkeep_request(self, data: Dict, headers: Dict):
@ -524,7 +620,7 @@ class IDACSeason2(IDACBase):
timerelease chapter: timerelease chapter:
1 = Story: 1, 2, 3, 4, 5, 6, 7, 8, 9, 19 (Chapter 10), (29 Chapter 11 lol?) 1 = Story: 1, 2, 3, 4, 5, 6, 7, 8, 9, 19 (Chapter 10), (29 Chapter 11 lol?)
2 = MF Ghost: 10, 11, 12, 13, 14, 15 2 = MF Ghost: 10, 11, 12, 13, 14, 15
3 = Bunta: 15, 16, 17, 18, 20, (21, 21, 22?) 3 = Bunta: 15, 16, 17, 18, 20, 21, 21, 22
4 = Special Event: 23, 24, 25, 26, 27, 28 (Touhou Project) 4 = Special Event: 23, 24, 25, 26, 27, 28 (Touhou Project)
""" """
path = "./titles/idac/data/" path = "./titles/idac/data/"
@ -613,6 +709,16 @@ class IDACSeason2(IDACBase):
"rank_management_flag": 0, "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
async def handle_login_checklock_request(self, data: Dict, headers: Dict): async def handle_login_checklock_request(self, data: Dict, headers: Dict):
user_id = data["id"] user_id = data["id"]
access_code = data["accesscode"] access_code = data["accesscode"]
@ -625,6 +731,13 @@ class IDACSeason2(IDACBase):
# check if an IDAC profile already exists # check if an IDAC profile already exists
p = await self.data.profile.get_profile(user_id, self.version) p = await self.data.profile.get_profile(user_id, self.version)
is_new_player = 1 if p is None else 0 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: else:
lock_result = 0 lock_result = 0
user_id = "" user_id = ""
@ -706,10 +819,10 @@ class IDACSeason2(IDACBase):
return story_data return story_data
async def _generate_special_data(self, user_id: int) -> Dict: async def _generate_special_data(self, user_id: int, headers: Dict) -> Dict:
# 4 = special mode # 4 = touhou project, 5 = hatsune miku
specials = await self.data.item.get_best_challenges_by_vs_type( specials = await self.data.item.get_best_challenges_by_vs_type(
user_id, story_type=4 user_id, story_type=self._special_story_type(headers)
) )
special_data = [] special_data = []
@ -1321,7 +1434,7 @@ class IDACSeason2(IDACBase):
"theory_course_data": theory_course_data, "theory_course_data": theory_course_data,
"theory_partner_data": theory_partner_data, "theory_partner_data": theory_partner_data,
"theory_running_pram_data": theory_running_pram_data, "theory_running_pram_data": theory_running_pram_data,
"special_mode_data": await self._generate_special_data(user_id), "special_mode_data": await self._generate_special_data(user_id, headers),
"challenge_mode_data": await self._generate_challenge_data(user_id), "challenge_mode_data": await self._generate_challenge_data(user_id),
"season_rewards_data": [], "season_rewards_data": [],
"timetrial_event_data": timetrial_event_data, "timetrial_event_data": timetrial_event_data,
@ -1519,7 +1632,7 @@ class IDACSeason2(IDACBase):
# save profile in database # save profile in database
data["store"] = headers.get("a_store", 0) data["store"] = headers.get("a_store", 0)
data["country"] = headers.get("a_country", 0) data["country"] = headers.get("a_country", 0)
data["asset_version"] = headers.get("asset_version", 1) data["device_version"] = headers.get("device_version", "1.50.00")
await self.data.profile.put_profile(user_id, self.version, data) await self.data.profile.put_profile(user_id, self.version, data)
# save rank data in database # save rank data in database
@ -1925,7 +2038,9 @@ class IDACSeason2(IDACBase):
# update the tips play count # update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version) tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips( await self.data.profile.put_profile_tips(
user_id, self.version, {"timetrial_play_count": tips["timetrial_play_count"] + 1} user_id,
self.version,
{"timetrial_play_count": tips["timetrial_play_count"] + 1},
) )
return { return {
@ -2147,12 +2262,14 @@ class IDACSeason2(IDACBase):
# update the tips play count # update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version) tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips( await self.data.profile.put_profile_tips(
user_id, self.version, {"special_play_count": tips["special_play_count"] + 1} user_id,
self.version,
{"special_play_count": tips["special_play_count"] + 1},
) )
return { return {
"status_code": "0", "status_code": "0",
"special_mode_data": await self._generate_special_data(user_id), "special_mode_data": await self._generate_special_data(user_id, headers),
"car_use_count": [], "car_use_count": [],
"maker_use_count": [], "maker_use_count": [],
} }
@ -2233,7 +2350,9 @@ class IDACSeason2(IDACBase):
# update the tips play count # update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version) tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips( await self.data.profile.put_profile_tips(
user_id, self.version, {"challenge_play_count": tips["challenge_play_count"] + 1} user_id,
self.version,
{"challenge_play_count": tips["challenge_play_count"] + 1},
) )
return { return {
@ -3011,7 +3130,9 @@ class IDACSeason2(IDACBase):
# update the tips play count # update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version) tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips( await self.data.profile.put_profile_tips(
user_id, self.version, {"online_battle_play_count": tips["online_battle_play_count"] + 1} 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")) round_info = await self._update_round_info(user_id, self.round_event_id, data.pop("round_point"), data.pop("win_flg"))
@ -3103,7 +3224,9 @@ class IDACSeason2(IDACBase):
# update the tips play count # update the tips play count
tips = await self.data.profile.get_profile_tips(user_id, self.version) tips = await self.data.profile.get_profile_tips(user_id, self.version)
await self.data.profile.put_profile_tips( await self.data.profile.put_profile_tips(
user_id, self.version, {"store_battle_play_count": tips["store_battle_play_count"] + 1} user_id,
self.version,
{"store_battle_play_count": tips["store_battle_play_count"] + 1},
) )
return { return {
@ -3118,23 +3241,25 @@ class IDACSeason2(IDACBase):
win_list = [] win_list = []
lottery_count = 0 lottery_count = 0
p = await self.data.factory.get_lottery(user_id, self.version) # retrieve the lottery data for the user
if p is not None: l = await self.data.factory.get_lottery(user_id, self.version)
lottery_data = p._asdict() if l:
lottery_count = lottery_data["lottery_count"] # check if create_data is younger than 24 hours
number = 0 if datetime.now() - l["create_date"] < timedelta(days=1):
while number < 10: lottery_count = l["lottery_count"]
if int(lottery_data["saved_value"]) & 1: saved_value = int(l["saved_value"])
win_list_data = {
# 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, "m_number_lottery_schedule_no": 1,
"win_number": 0 "win_number": number * 1111
} })
win_list_data["win_number"] = number*1111 # right shift saved_value to check the next bit
win_list.append(win_list_data) saved_value >>= 1
lottery_data["saved_value"] = lottery_data["saved_value"] / 2
number = number + 1
return { return {
"status_code": "0", "status_code": "0",
@ -3148,43 +3273,43 @@ class IDACSeason2(IDACBase):
user_id = headers["session"] user_id = headers["session"]
win_number = data.pop("win_number") win_number = data.pop("win_number")
lottery_count = data.pop("lottery_count") 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
# save count if not a lucky number otherwise save all
if win_number != 10000: if win_number != 10000:
shifted = win_number / 1111 # calculate the bit position to set based on the win_number
number = 1 << int(shifted) shifted = win_number // 1111
p = await self.data.factory.get_lottery(user_id, self.version) saved_value += 1 << shifted
if p is not None:
lottery_data = p._asdict()
saved_value = lottery_data["saved_value"] + number
else:
saved_value = number
await self.data.factory.put_lottery(user_id, self.version, saved_value, lottery_count) # update the create_date timestamp when the last create_date is older than 24 hours
else: if l and datetime.now() - l["create_date"] > timedelta(days=1):
p = await self.data.factory.get_lottery(user_id, self.version) create_date = datetime.now()
if p is not None:
lottery_data = p._asdict()
saved_value = lottery_data["saved_value"]
else:
saved_value = 0
await self.data.factory.put_lottery(user_id, self.version, saved_value, lottery_count)
# save car data if lottery ended # update the lottery data with the new saved_value and lottery_count
car = {} await self.data.factory.put_lottery(user_id, self.version, saved_value, lottery_count, create_date)
car["style_car_id"] = data.pop("style_car_id")
car["l_no"] = data.pop("l_no")
if data.pop("isEnd") == 1:
await self.data.item.put_car(user_id, self.version, car)
# save ticket data if license_no != 10000 and is_end == 1:
for ticket in data.pop("ticket_data"): # 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) await self.data.item.put_ticket(user_id, ticket)
# save cash # save remaining profile data
await self.data.profile.put_profile(user_id, self.version, data) await self.data.profile.put_profile(user_id, self.version, data)
return { return {
"status_code": "0" "status_code": "0"
} }

File diff suppressed because one or more lines are too long