- Add Ranking Event Support

- Add Technical Challenge Event Support
- Fix Event Enumeration for EVT_TYPES as Enum starts with 1, to be in spec with what game expects, also add missing Max EVT_TYPE
- Add documentation on how to properly configure and run Events for ONGEKI
This commit is contained in:
2023-11-05 18:09:58 +01:00
committed by phantomlan
parent 4bedf71d3d
commit 4da886a083
4 changed files with 171 additions and 21 deletions

View File

@ -1,3 +1,4 @@
from datetime import date, datetime, timedelta
from typing import Dict, Optional, List
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON
@ -172,6 +173,9 @@ event_point = Table(
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade")),
Column("eventId", Integer),
Column("point", Integer),
Column("rank", Integer),
Column("type", Integer),
Column("date", String(25)),
Column("isRankingRewarded", Boolean),
UniqueConstraint("user", "eventId", name="ongeki_user_event_point_uk"),
mysql_charset="utf8mb4",
@ -247,6 +251,31 @@ tech_event = Table(
mysql_charset="utf8mb4",
)
tech_music = Table(
"ongeki_tech_music_list",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("eventId", Integer),
Column("musicId", Integer),
Column("level", Integer),
UniqueConstraint("musicId", name="ongeki_tech_music_list_uk"),
mysql_charset="utf8mb4",
)
tech_ranking = Table(
"ongeki_tech_event_ranking",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("date", String(25)),
Column("eventId", Integer),
Column("rank", Integer),
Column("totalPlatinumScore", Integer),
Column("totalTechScore", Integer),
UniqueConstraint("user", "eventId", name="ongeki_tech_event_ranking_uk"),
mysql_charset="utf8mb4",
)
gacha = Table(
"ongeki_user_gacha",
metadata,
@ -534,7 +563,12 @@ class OngekiItemData(BaseData):
return result.fetchall()
def put_event_point(self, aime_id: int, event_point_data: Dict) -> Optional[int]:
# We update only the newest (type: 1) entry, in official spec game watches for both latest(type:1) and previous (type:2) entries to give an additional info how many ranks has player moved up or down
# This fully featured is on TODO list, at the moment we just update the tables as data comes and give out rank as request comes
event_point_data["user"] = aime_id
event_point_data["type"] = 1
event_point_time = datetime.now()
event_point_data["date"] = datetime.strftime(event_point_time, "%Y-%m-%d %H:%M")
sql = insert(event_point).values(**event_point_data)
conflict = sql.on_duplicate_key_update(**event_point_data)
@ -613,6 +647,14 @@ class OngekiItemData(BaseData):
return None
return result.fetchall()
def get_tech_music(self) -> Optional[List[Dict]]:
sql = select(tech_music)
result = self.execute(sql)
if result is None:
return None
return result.fetchall()
def put_tech_event(self, aime_id: int, tech_event_data: Dict) -> Optional[int]:
tech_event_data["user"] = aime_id
@ -625,6 +667,22 @@ class OngekiItemData(BaseData):
return None
return result.lastrowid
def put_tech_event_ranking(self, aime_id: int, tech_event_data: Dict) -> Optional[int]:
tech_event_data["user"] = aime_id
tech_event_data.pop("isRankingRewarded")
tech_event_data.pop("isTotalTechNewRecord")
tech_event_data["date"] = tech_event_data.pop("techRecordDate")
tech_event_data["rank"] = 0
sql = insert(tech_ranking).values(**tech_event_data)
conflict = sql.on_duplicate_key_update(**tech_event_data)
result = self.execute(conflict)
if result is None:
self.logger.warning(f"put_tech_event_ranking: Failed to update ranking! aime_id {aime_id}")
return None
return result.lastrowid
def get_tech_event(self, aime_id: int) -> Optional[List[Dict]]:
sql = select(tech_event).where(tech_event.c.user == aime_id)
result = self.execute(sql)
@ -714,3 +772,21 @@ class OngekiItemData(BaseData):
)
return None
return result.lastrowid
def get_ranking_event_ranks(self, aime_id: int) -> Optional[List[Dict]]:
# Calculates player rank on GameRequest from server, and sends it back, official spec would rank players in maintenance period, on TODO list
sql = select(event_point.c.id, event_point.c.user, event_point.c.eventId, event_point.c.type, func.row_number().over(partition_by=event_point.c.eventId, order_by=event_point.c.point.desc()).label('rank'), event_point.c.date, event_point.c.point)
result = self.execute(sql)
if result is None:
self.logger.error(f"failed to rank aime_id: {aime_id} ranking event positions")
return None
return result.fetchall()
def get_tech_event_ranking(self, aime_id: int) -> Optional[List[Dict]]:
sql = select(tech_ranking.c.id, tech_ranking.c.user, tech_ranking.c.date, tech_ranking.c.eventId, func.row_number().over(partition_by=tech_ranking.c.eventId, order_by=[tech_ranking.c.totalTechScore.desc(),tech_ranking.c.totalPlatinumScore.desc()]).label('rank'), tech_ranking.c.totalTechScore, tech_ranking.c.totalPlatinumScore)
result = self.execute(sql)
if result is None:
self.logger.warning(f"aime_id: {aime_id} has no tech ranking ranks")
return None
return result.fetchall()