round database implenments

This commit is contained in:
UncleJim 2024-04-30 17:23:05 +08:00
parent f6cc1422ae
commit a245f3add4
4 changed files with 177 additions and 9 deletions

View File

@ -0,0 +1,22 @@
-- Create the new table idac_round_info
CREATE TABLE idac_round_info (
id INT PRIMARY KEY AUTO_INCREMENT,
round_id INT,
name VARCHAR(64),
season INT,
start_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
end_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Create the new table idac_user_round_info
CREATE TABLE idac_user_round_info (
id INT PRIMARY KEY AUTO_INCREMENT,
user INT,
round_id INT,
count INT,
win INT,
point INT,
play_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT idac_user_vs_course_info_fk FOREIGN KEY (user) REFERENCES aime_user(id) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE KEY idac_user_vs_course_info_uk (user, round_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -2,6 +2,7 @@ from core.data import Data
from core.config import CoreConfig
from titles.idac.schema.profile import IDACProfileData
from titles.idac.schema.item import IDACItemData
from titles.idac.schema.rounds import IDACOnlineRounds
class IDACData(Data):
@ -10,3 +11,4 @@ class IDACData(Data):
self.profile = IDACProfileData(cfg, self.session)
self.item = IDACItemData(cfg, self.session)
self.rounds = IDACOnlineRounds(cfg, self.session)

View File

@ -0,0 +1,95 @@
from typing import Dict, List, Optional
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_, update
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON, BigInteger
from sqlalchemy.engine.base import Connection
from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select
from sqlalchemy.engine import Row
from sqlalchemy.dialects.mysql import insert
from core.data.schema import BaseData, metadata
from core.config import CoreConfig
round_details = 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("point", Integer),
Column("play_dt", TIMESTAMP, server_default=func.now()),
UniqueConstraint("user", "round_id", name="idac_user_round_info_uk"),
mysql_charset="utf8mb4",
)
class IDACOnlineRounds(BaseData):
# get player's ranking from a specified round event
async def get_round_rank_by_id(self, aime_id: int, round_event_id: int) -> Optional[Row]:
subquery = (
select([func.group_concat(func.concat(round_info.c.user, '|', round_info.c.point),order_by=[round_info.c.point.desc(), round_info.c.play_dt])])
.select_from(round_info)
.where(round_info.c.round_id == round_event_id)
.as_scalar()
)
sql = (
select([func.find_in_set(func.concat(round_info.c.user, '|', round_info.c.point), subquery.label('rank'))])
.select_from(round_info)
.where(
and_(
round_info.c.user == aime_id,
round_info.c.round_id == round_event_id
)
)
)
result = self.execute(sql)
if result is None:
return None
return result.fetchone()
# get player's info from a specified round event
async def get_round_info_by_id(self, aime_id: int, round_event_id: int) -> Optional[Row]:
sql = select(round_info).where(
and_(
round_info.c.user == aime_id,
round_info.c.round_id == round_event_id
)
)
result = self.execute(sql)
if result is None:
return None
return result.fetchone()
# save players info to a specified round event
async def put_round_event(
self, aime_id: int, round_id: int, round_data: Dict
) -> Optional[int]:
round_data["user"] = aime_id
round_data["round_id"] = round_id
sql = insert(round_info).values(**round_data)
conflict = sql.on_duplicate_key_update(**round_data)
result = self.execute(conflict)
if result is None:
self.logger.warn(f"putround: Failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
#TODO: get top five players of last round event for Boot/GetConfigData

View File

@ -843,6 +843,60 @@ class IDACSeason2(IDACBase):
vs_info["course_select_priority"] = data.get("course_select_priority")
return vs_info
async def _update_round_info(
self, user_id: int, round_event_id: int, point: int, win: int
) -> Dict:
# get the round info data from database
round_info = []
ri = await self.data.rounds.get_round_info_by_id(user_id, round_event_id)
if ri is not None:
tmp = ri._asdict()
del tmp["id"]
# calculate new round points and info
tmp["point"] = 0 if tmp["point"] + point < 1 else tmp["point"] + point
tmp["count"] += 1
tmp["win"] += win
tmp["play_dt"] = datetime.now()
# update players round info
await self.data.rounds.put_round_event(user_id, round_event_id, tmp)
del tmp["play_dt"]
# get players new round ranking
r = await self.data.rounds.get_round_rank_by_id(user_id, round_event_id)
round_ranking = r._asdict()
tmp["rank"] = round_ranking["find_in_set_1"] if tmp["point"] > 0 else 0
# TODO: get players historical earned points
tmp["total_round_point"] = 0
round_info.append(tmp)
else:
# new player of now-going round event
tmp = {}
tmp["point"] = 0 if point < 1 else point
tmp["count"] = 1
tmp["win"] = win
tmp["play_dt"] = datetime.now()
await self.data.rounds.put_round_event(user_id, round_event_id, tmp)
del tmp["play_dt"]
r = await self.data.rounds.get_round_rank_by_id(user_id, round_event_id)
round_ranking = r._asdict()
tmp["rank"] = round_ranking["find_in_set_1"] if tmp["point"] > 0 else 0
# TODO: get players historical earned points
tmp["total_round_point"] = 0
round_info.append(tmp)
return round_info
def _choose_gift_id(self) -> Dict:
gift_data = self.battle_gift_event["gift_data"]
# calculate the total_rate based on the first_distribution_rate
@ -2849,6 +2903,7 @@ class IDACSeason2(IDACBase):
}
async def handle_user_updateonlinebattle_request(self, data: Dict, headers: Dict):
#TODO: voiding cheaters' result. which will need to analysis historical battle results returned by the game.
return {
"status_code": "0",
"bothwin_penalty": 1,
@ -2922,18 +2977,12 @@ class IDACSeason2(IDACBase):
user_id, self.version, {"online_battle_play_count": tips["online_battle_play_count"] + 1}
)
round_info = await self._update_round_info(user_id, self.round_event_id, data.pop("round_point"), data.pop("win_flg"))
return {
"status_code": "0",
"vsinfo_data": vs_info,
"round_event": [
{
"count": 1,
"win": 1,
"rank": 1,
"point": 1,
"total_round_point": 1,
}
],
"round_event": round_info,
"car_use_count": [],
"maker_use_count": [],
}