forked from Dniel97/artemis
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:
parent
d5b2074945
commit
ba5591cd81
@ -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
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
@ -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"
|
||||||
),
|
),
|
||||||
|
@ -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')
|
@ -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(往路) |
|
||||||
|
@ -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",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user