add back games, conform them to new title dispatch

This commit is contained in:
Hay1tsme
2023-02-17 01:02:21 -05:00
parent f18e939dd0
commit 7e3396a7ff
214 changed files with 19412 additions and 23 deletions

View File

@@ -0,0 +1,6 @@
from titles.wacca.schema.profile import WaccaProfileData
from titles.wacca.schema.score import WaccaScoreData
from titles.wacca.schema.item import WaccaItemData
from titles.wacca.schema.static import WaccaStaticData
__all__ = ["WaccaProfileData", "WaccaScoreData", "WaccaItemData", "WaccaStaticData"]

177
titles/wacca/schema/item.py Normal file
View File

@@ -0,0 +1,177 @@
from typing import Optional, Dict, List
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_, case
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean
from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select, update, delete
from sqlalchemy.engine import Row
from sqlalchemy.dialects.mysql import insert
from core.data.schema import BaseData, metadata
item = Table(
"wacca_item",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("item_id", Integer, nullable=False),
Column("type", Integer, nullable=False),
Column("acquire_date", TIMESTAMP, nullable=False, server_default=func.now()),
Column("use_count", Integer, server_default="0"),
UniqueConstraint("user", "item_id", "type", name="wacca_item_uk"),
mysql_charset='utf8mb4'
)
ticket = Table(
"wacca_ticket",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("ticket_id", Integer, nullable=False),
Column("acquire_date", TIMESTAMP, nullable=False, server_default=func.now()),
Column("expire_date", TIMESTAMP),
mysql_charset='utf8mb4'
)
song_unlock = Table(
"wacca_song_unlock",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("song_id", Integer, nullable=False),
Column("highest_difficulty", Integer, nullable=False),
Column("acquire_date", TIMESTAMP, nullable=False, server_default=func.now()),
UniqueConstraint("user", "song_id", name="wacca_song_unlock_uk"),
mysql_charset='utf8mb4'
)
trophy = Table(
"wacca_trophy",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("trophy_id", Integer, nullable=False),
Column("season", Integer, nullable=False),
Column("progress", Integer, nullable=False, server_default="0"),
Column("badge_type", Integer, nullable=False, server_default="0"),
UniqueConstraint("user", "trophy_id", "season", name="wacca_trophy_uk"),
mysql_charset='utf8mb4'
)
class WaccaItemData(BaseData):
def get_song_unlocks(self, user_id: int) -> Optional[List[Row]]:
sql = song_unlock.select(song_unlock.c.user == user_id)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def unlock_song(self, user_id: int, song_id: int, difficulty: int) -> Optional[int]:
sql = insert(song_unlock).values(
user=user_id,
song_id=song_id,
highest_difficulty=difficulty
)
conflict = sql.on_duplicate_key_update(
highest_difficulty=case(
(song_unlock.c.highest_difficulty >= difficulty, song_unlock.c.highest_difficulty),
(song_unlock.c.highest_difficulty < difficulty, difficulty),
)
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"{__name__} failed to unlock song! user: {user_id}, song_id: {song_id}, difficulty: {difficulty}")
return None
return result.lastrowid
def put_item(self, user_id: int, item_type: int, item_id: int) -> Optional[int]:
sql = insert(item).values(
user = user_id,
item_id = item_id,
type = item_type,
)
conflict = sql.on_duplicate_key_update(
use_count = item.c.use_count + 1
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"{__name__} failed to insert item! user: {user_id}, item_id: {item_id}, item_type: {item_type}")
return None
return result.lastrowid
def get_items(self, user_id: int, item_type: int = None, item_id: int = None) -> Optional[List[Row]]:
"""
A catch-all item lookup given a profile and option item type and ID specifiers
"""
sql = item.select(
and_(item.c.user == user_id,
item.c.type == item_type if item_type is not None else True,
item.c.item_id == item_id if item_id is not None else True)
)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def get_tickets(self, user_id: int) -> Optional[List[Row]]:
sql = select(ticket).where(ticket.c.user == user_id)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def add_ticket(self, user_id: int, ticket_id: int) -> None:
sql = insert(ticket).values(
user = user_id,
ticket_id = ticket_id
)
result = self.execute(sql)
if result is None:
self.logger.error(f"add_ticket: Failed to insert wacca ticket! user_id: {user_id} ticket_id {ticket_id}")
return None
return result.lastrowid
def spend_ticket(self, id: int) -> None:
sql = delete(ticket).where(ticket.c.id == id)
result = self.execute(sql)
if result is None:
self.logger.warn(f"Failed to delete ticket id {id}")
return None
def get_trophies(self, user_id: int, season: int = None) -> Optional[List[Row]]:
if season is None:
sql = select(trophy).where(trophy.c.user == user_id)
else:
sql = select(trophy).where(and_(trophy.c.user == user_id, trophy.c.season == season))
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def update_trophy(self, user_id: int, trophy_id: int, season: int, progress: int, badge_type: int) -> Optional[int]:
sql = insert(trophy).values(
user = user_id,
trophy_id = trophy_id,
season = season,
progress = progress,
badge_type = badge_type
)
conflict = sql.on_duplicate_key_update(
progress = progress
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"update_trophy: Failed to insert wacca trophy! user_id: {user_id} trophy_id: {trophy_id} progress {progress}")
return None
return result.lastrowid

View File

@@ -0,0 +1,428 @@
from typing import Optional, Dict, List
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON
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
profile = Table(
"wacca_profile",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("version", Integer),
Column("username", String(8), nullable=False),
Column("xp", Integer, server_default="0"),
Column("wp", Integer, server_default="0"),
Column("wp_total", Integer, server_default="0"),
Column("wp_spent", Integer, server_default="0"),
Column("dan_type", Integer, server_default="0"),
Column("dan_level", Integer, server_default="0"),
Column("title_0", Integer, server_default="0"),
Column("title_1", Integer, server_default="0"),
Column("title_2", Integer, server_default="0"),
Column("rating", Integer, server_default="0"),
Column("vip_expire_time", TIMESTAMP),
Column("always_vip", Boolean, server_default="0"),
Column("login_count", Integer, server_default="0"),
Column("login_count_consec", Integer, server_default="0"),
Column("login_count_days", Integer, server_default="0"),
Column("login_count_days_consec", Integer, server_default="0"),
Column("login_count_today", Integer, server_default="0"),
Column("playcount_single", Integer, server_default="0"),
Column("playcount_multi_vs", Integer, server_default="0"),
Column("playcount_multi_coop", Integer, server_default="0"),
Column("playcount_stageup", Integer, server_default="0"),
Column("friend_view_1", Integer),
Column("friend_view_2", Integer),
Column("friend_view_3", Integer),
Column("last_game_ver", String(50)),
Column("last_song_id", Integer, server_default="0"),
Column("last_song_difficulty", Integer, server_default="0"),
Column("last_folder_order", Integer, server_default="0"),
Column("last_folder_id", Integer, server_default="0"),
Column("last_song_order", Integer, server_default="0"),
Column("last_login_date", TIMESTAMP, server_default=func.now()),
Column("gate_tutorial_flags", JSON),
UniqueConstraint("user", "version", name="wacca_profile_uk"),
mysql_charset='utf8mb4'
)
option = Table(
"wacca_option",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("opt_id", Integer, nullable=False),
Column("value", Integer, nullable=False),
UniqueConstraint("user", "opt_id", name="wacca_option_uk"),
)
bingo = Table(
"wacca_bingo",
metadata,
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), primary_key=True, nullable=False),
Column("page_number", Integer, nullable=False),
Column("page_progress", JSON, nullable=False),
UniqueConstraint("user", "page_number", name="wacca_bingo_uk"),
mysql_charset='utf8mb4'
)
friend = Table(
"wacca_friend",
metadata,
Column("profile_sender", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("profile_reciever", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("is_accepted", Boolean, server_default="0"),
PrimaryKeyConstraint('profile_sender', 'profile_reciever', name='arcade_owner_pk'),
mysql_charset='utf8mb4'
)
favorite = Table(
"wacca_favorite_song",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("song_id", Integer, nullable=False),
UniqueConstraint("user", "song_id", name="wacca_favorite_song_uk"),
mysql_charset='utf8mb4'
)
gate = Table(
"wacca_gate",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("gate_id", Integer, nullable=False),
Column("page", Integer, nullable=False, server_default="0"),
Column("progress", Integer, nullable=False, server_default="0"),
Column("loops", Integer, nullable=False, server_default="0"),
Column("last_used", TIMESTAMP, nullable=False, server_default=func.now()),
Column("mission_flag", Integer, nullable=False, server_default="0"),
Column("total_points", Integer, nullable=False, server_default="0"),
UniqueConstraint("user", "gate_id", name="wacca_gate_uk"),
)
class WaccaProfileData(BaseData):
def create_profile(self, aime_id: int, username: str, version: int) -> Optional[int]:
"""
Given a game version, aime id, and username, create a profile and return it's ID
"""
sql = insert(profile).values(
user=aime_id,
username=username,
version=version
)
conflict = sql.on_duplicate_key_update(
username = sql.inserted.username
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"{__name__} Failed to insert wacca profile! aime id: {aime_id} username: {username}")
return None
return result.lastrowid
def update_profile_playtype(self, profile_id: int, play_type: int, game_version: str) -> None:
sql = profile.update(profile.c.id == profile_id).values(
playcount_single = profile.c.playcount_single + 1 if play_type == 1 else profile.c.playcount_single,
playcount_multi_vs = profile.c.playcount_multi_vs + 1 if play_type == 2 else profile.c.playcount_multi_vs,
playcount_multi_coop = profile.c.playcount_multi_coop + 1 if play_type == 3 else profile.c.playcount_multi_coop,
playcount_stageup = profile.c.playcount_stageup + 1 if play_type == 4 else profile.c.playcount_stageup,
last_game_ver = game_version,
)
result = self.execute(sql)
if result is None:
self.logger.error(f"update_profile: failed to update profile! profile: {profile_id}")
return None
def update_profile_lastplayed(self, profile_id: int, last_song_id: int, last_song_difficulty: int, last_folder_order: int,
last_folder_id: int, last_song_order: int) -> None:
sql = profile.update(profile.c.id == profile_id).values(
last_song_id = last_song_id,
last_song_difficulty = last_song_difficulty,
last_folder_order = last_folder_order,
last_folder_id = last_folder_id,
last_song_order = last_song_order
)
result = self.execute(sql)
if result is None:
self.logger.error(f"update_profile_lastplayed: failed to update profile! profile: {profile_id}")
return None
def update_profile_dan(self, profile_id: int, dan_level: int, dan_type: int) -> Optional[int]:
sql = profile.update(profile.c.id == profile_id).values(
dan_level = dan_level,
dan_type = dan_type
)
result = self.execute(sql)
if result is None:
self.logger.warn(f"update_profile_dan: Failed to update! profile {profile_id}")
return None
return result.lastrowid
def get_profile(self, profile_id: int = 0, aime_id: int = None) -> Optional[Row]:
"""
Given a game version and either a profile or aime id, return the profile
"""
if aime_id is not None:
sql = profile.select(profile.c.user == aime_id)
elif profile_id > 0:
sql = profile.select(profile.c.id == profile_id)
else:
self.logger.error(f"get_profile: Bad arguments!! profile_id {profile_id} aime_id {aime_id}")
return None
result = self.execute(sql)
if result is None: return None
return result.fetchone()
def get_options(self, user_id: int, option_id: int = None) -> Optional[List[Row]]:
"""
Get a specific user option for a profile, or all of them if none specified
"""
sql = option.select(
and_(option.c.user == user_id,
option.c.opt_id == option_id if option_id is not None else True)
)
result = self.execute(sql)
if result is None: return None
if option_id is not None:
return result.fetchone()
else:
return result.fetchall()
def update_option(self, user_id: int, option_id: int, value: int) -> Optional[int]:
sql = insert(option).values(
user = user_id,
opt_id = option_id,
value = value
)
conflict = sql.on_duplicate_key_update(
value = sql.inserted.value
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"{__name__} failed to insert option! profile: {user_id}, option: {option_id}, value: {value}")
return None
return result.lastrowid
def add_favorite_song(self, user_id: int, song_id: int) -> Optional[int]:
sql = favorite.insert().values(
user=user_id,
song_id=song_id
)
result = self.execute(sql)
if result is None:
self.logger.error(f"{__name__} failed to insert favorite! profile: {user_id}, song_id: {song_id}")
return None
return result.lastrowid
def remove_favorite_song(self, user_id: int, song_id: int) -> None:
sql = favorite.delete(and_(favorite.c.user == user_id, favorite.c.song_id == song_id))
result = self.execute(sql)
if result is None:
self.logger.error(f"{__name__} failed to remove favorite! profile: {user_id}, song_id: {song_id}")
return None
def get_favorite_songs(self, user_id: int) -> Optional[List[Row]]:
sql = favorite.select(favorite.c.user == user_id)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def get_gates(self, user_id: int) -> Optional[List[Row]]:
sql = select(gate).where(gate.c.user == user_id)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def update_gate(self, user_id: int, gate_id: int, page: int, progress: int, loop: int, mission_flag: int,
total_points: int) -> Optional[int]:
sql = insert(gate).values(
user=user_id,
gate_id=gate_id,
page=page,
progress=progress,
loops=loop,
mission_flag=mission_flag,
total_points=total_points
)
conflict = sql.on_duplicate_key_update(
page=sql.inserted.page,
progress=sql.inserted.progress,
loops=sql.inserted.loops,
mission_flag=sql.inserted.mission_flag,
total_points=sql.inserted.total_points,
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"{__name__} failed to update gate! user: {user_id}, gate_id: {gate_id}")
return None
return result.lastrowid
def get_friends(self, user_id: int) -> Optional[List[Row]]:
sql = friend.select(friend.c.profile_sender == user_id)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def profile_to_aime_user(self, profile_id: int) -> Optional[int]:
sql = select(profile.c.user).where(profile.c.id == profile_id)
result = self.execute(sql)
if result is None:
self.logger.info(f"profile_to_aime_user: No user found for profile {profile_id}")
return None
this_profile = result.fetchone()
if this_profile is None:
self.logger.info(f"profile_to_aime_user: No user found for profile {profile_id}")
return None
return this_profile['user']
def session_login(self, profile_id: int, is_new_day: bool, is_consec_day: bool) -> None:
# TODO: Reset consec days counter
sql = profile.update(profile.c.id == profile_id).values(
login_count = profile.c.login_count + 1,
login_count_consec = profile.c.login_count_consec + 1,
login_count_days = profile.c.login_count_days + 1 if is_new_day else profile.c.login_count_days,
login_count_days_consec = profile.c.login_count_days_consec + 1 if is_new_day and is_consec_day else profile.c.login_count_days_consec,
login_count_today = 1 if is_new_day else profile.c.login_count_today + 1,
last_login_date = func.now()
)
result = self.execute(sql)
if result is None:
self.logger.error(f"session_login: failed to update profile! profile: {profile_id}")
return None
def session_logout(self, profile_id: int) -> None:
sql = profile.update(profile.c.id == id).values(
login_count_consec = 0
)
result = self.execute(sql)
if result is None:
self.logger.error(f"{__name__} failed to update profile! profile: {profile_id}")
return None
def add_xp(self, profile_id: int, xp: int) -> None:
sql = profile.update(profile.c.id == profile_id).values(
xp = profile.c.xp + xp
)
result = self.execute(sql)
if result is None:
self.logger.error(f"add_xp: Failed to update profile! profile_id {profile_id} xp {xp}")
return None
def add_wp(self, profile_id: int, wp: int) -> None:
sql = profile.update(profile.c.id == profile_id).values(
wp = profile.c.wp + wp,
wp_total = profile.c.wp_total + wp,
)
result = self.execute(sql)
if result is None:
self.logger.error(f"add_wp: Failed to update profile! profile_id {profile_id} wp {wp}")
return None
def spend_wp(self, profile_id: int, wp: int) -> None:
sql = profile.update(profile.c.id == profile_id).values(
wp = profile.c.wp - wp,
wp_spent = profile.c.wp_spent + wp,
)
result = self.execute(sql)
if result is None:
self.logger.error(f"spend_wp: Failed to update profile! profile_id {profile_id} wp {wp}")
return None
def activate_vip(self, profile_id: int, expire_time) -> None:
sql = profile.update(profile.c.id == profile_id).values(
vip_expire_time = expire_time
)
result = self.execute(sql)
if result is None:
self.logger.error(f"activate_vip: Failed to update profile! profile_id {profile_id} expire_time {expire_time}")
return None
def update_user_rating(self, profile_id: int, new_rating: int) -> None:
sql = profile.update(profile.c.id == profile_id).values(
rating = new_rating
)
result = self.execute(sql)
if result is None:
self.logger.error(f"update_user_rating: Failed to update profile! profile_id {profile_id} new_rating {new_rating}")
return None
def update_bingo(self, aime_id: int, page: int, progress: int) -> Optional[int]:
sql = insert(bingo).values(
user=aime_id,
page_number=page,
page_progress=progress
)
conflict = sql.on_duplicate_key_update(
page_number=page,
page_progress=progress
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"put_bingo: failed to update! aime_id: {aime_id}")
return None
return result.lastrowid
def get_bingo(self, aime_id: int) -> Optional[List[Row]]:
sql = select(bingo).where(bingo.c.user==aime_id)
result = self.execute(sql)
if result is None: return None
return result.fetchone()
def get_bingo_page(self, aime_id: int, page: Dict) -> Optional[List[Row]]:
sql = select(bingo).where(and_(bingo.c.user==aime_id, bingo.c.page_number==page))
result = self.execute(sql)
if result is None: return None
return result.fetchone()
def update_vip_time(self, profile_id: int, time_left) -> None:
sql = profile.update(profile.c.id == profile_id).values(vip_expire_time = time_left)
result = self.execute(sql)
if result is None:
self.logger.error(f"Failed to update VIP time for profile {profile_id}")
def update_tutorial_flags(self, profile_id: int, flags: Dict) -> None:
sql = profile.update(profile.c.id == profile_id).values(gate_tutorial_flags = flags)
result = self.execute(sql)
if result is None:
self.logger.error(f"Failed to update tutorial flags for profile {profile_id}")

View File

@@ -0,0 +1,260 @@
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
from sqlalchemy.types import Integer, String, TIMESTAMP, JSON, Boolean
from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select
from sqlalchemy.engine import Row
from sqlalchemy.dialects.mysql import insert
from typing import Optional, List, Dict, Any
from core.data.schema import BaseData, metadata
from core.data import cached
best_score = Table(
"wacca_score_best",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("song_id", Integer),
Column("chart_id", Integer),
Column("score", Integer),
Column("play_ct", Integer),
Column("clear_ct", Integer),
Column("missless_ct", Integer),
Column("fullcombo_ct", Integer),
Column("allmarv_ct", Integer),
Column("grade_d_ct", Integer),
Column("grade_c_ct", Integer),
Column("grade_b_ct", Integer),
Column("grade_a_ct", Integer),
Column("grade_aa_ct", Integer),
Column("grade_aaa_ct", Integer),
Column("grade_s_ct", Integer),
Column("grade_ss_ct", Integer),
Column("grade_sss_ct", Integer),
Column("grade_master_ct", Integer),
Column("grade_sp_ct", Integer),
Column("grade_ssp_ct", Integer),
Column("grade_sssp_ct", Integer),
Column("best_combo", Integer),
Column("lowest_miss_ct", Integer),
Column("rating", Integer),
UniqueConstraint("user", "song_id", "chart_id", name="wacca_score_uk"),
mysql_charset='utf8mb4'
)
playlog = Table(
"wacca_score_playlog",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("song_id", Integer),
Column("chart_id", Integer),
Column("score", Integer),
Column("clear", Integer),
Column("grade", Integer),
Column("max_combo", Integer),
Column("marv_ct", Integer),
Column("great_ct", Integer),
Column("good_ct", Integer),
Column("miss_ct", Integer),
Column("fast_ct", Integer),
Column("late_ct", Integer),
Column("season", Integer),
Column("date_scored", TIMESTAMP, server_default=func.now()),
mysql_charset='utf8mb4'
)
stageup = Table(
"wacca_score_stageup",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("user", ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("version", Integer),
Column("stage_id", Integer),
Column("clear_status", Integer),
Column("clear_song_ct", Integer),
Column("song1_score", Integer),
Column("song2_score", Integer),
Column("song3_score", Integer),
Column("play_ct", Integer, server_default="1"),
UniqueConstraint("user", "stage_id", name="wacca_score_stageup_uk"),
mysql_charset='utf8mb4'
)
class WaccaScoreData(BaseData):
def put_best_score(self, user_id: int, song_id: int, chart_id: int, score: int, clear: List[int],
grade: List[int], best_combo: int, lowest_miss_ct: int) -> Optional[int]:
"""
Update the user's best score for a chart
"""
while len(grade) < 13:
grade.append(0)
sql = insert(best_score).values(
user=user_id,
song_id=song_id,
chart_id=chart_id,
score=score,
play_ct=clear[0],
clear_ct=clear[1],
missless_ct=clear[2],
fullcombo_ct=clear[3],
allmarv_ct=clear[4],
grade_d_ct=grade[0],
grade_c_ct=grade[1],
grade_b_ct=grade[2],
grade_a_ct=grade[3],
grade_aa_ct=grade[4],
grade_aaa_ct=grade[5],
grade_s_ct=grade[6],
grade_ss_ct=grade[7],
grade_sss_ct=grade[8],
grade_master_ct=grade[9],
grade_sp_ct=grade[10],
grade_ssp_ct=grade[11],
grade_sssp_ct=grade[12],
best_combo=best_combo,
lowest_miss_ct=lowest_miss_ct,
rating=0
)
conflict = sql.on_duplicate_key_update(
score=score,
play_ct=clear[0],
clear_ct=clear[1],
missless_ct=clear[2],
fullcombo_ct=clear[3],
allmarv_ct=clear[4],
grade_d_ct=grade[0],
grade_c_ct=grade[1],
grade_b_ct=grade[2],
grade_a_ct=grade[3],
grade_aa_ct=grade[4],
grade_aaa_ct=grade[5],
grade_s_ct=grade[6],
grade_ss_ct=grade[7],
grade_sss_ct=grade[8],
grade_master_ct=grade[9],
grade_sp_ct=grade[10],
grade_ssp_ct=grade[11],
grade_sssp_ct=grade[12],
best_combo=best_combo,
lowest_miss_ct=lowest_miss_ct,
)
result = self.execute(conflict)
if result is None:
self.logger.error(f"{__name__}: failed to insert best score! profile: {user_id}, song: {song_id}, chart: {chart_id}")
return None
return result.lastrowid
def put_playlog(self, user_id: int, song_id: int, chart_id: int, this_score: int, clear: int, grade: int, max_combo: int,
marv_ct: int, great_ct: int, good_ct: int, miss_ct: int, fast_ct: int, late_ct: int, season: int) -> Optional[int]:
"""
Add an entry to the user's play log
"""
sql = playlog.insert().values(
user=user_id,
song_id=song_id,
chart_id=chart_id,
score=this_score,
clear=clear,
grade=grade,
max_combo=max_combo,
marv_ct=marv_ct,
great_ct=great_ct,
good_ct=good_ct,
miss_ct=miss_ct,
fast_ct=fast_ct,
late_ct=late_ct,
season=season
)
result = self.execute(sql)
if result is None:
self.logger.error(f"{__name__} failed to insert playlog! profile: {user_id}, song: {song_id}, chart: {chart_id}")
return None
return result.lastrowid
def get_best_score(self, user_id: int, song_id: int, chart_id: int) -> Optional[Row]:
sql = best_score.select(
and_(best_score.c.user == user_id, best_score.c.song_id == song_id, best_score.c.chart_id == chart_id)
)
result = self.execute(sql)
if result is None: return None
return result.fetchone()
def get_best_scores(self, user_id: int) -> Optional[List[Row]]:
sql = best_score.select(
best_score.c.user == user_id
)
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def update_song_rating(self, user_id: int, song_id: int, chart_id: int, new_rating: int) -> None:
sql = best_score.update(
and_(
best_score.c.user == user_id,
best_score.c.song_id == song_id,
best_score.c.chart_id == chart_id
)).values(
rating = new_rating
)
result = self.execute(sql)
if result is None:
self.logger.error(f"update_song_rating: failed to update rating! user_id: {user_id} song_id: {song_id} chart_id {chart_id} new_rating {new_rating}")
return None
def put_stageup(self, user_id: int, version: int, stage_id: int, clear_status: int, clear_song_ct: int, score1: int,
score2: int, score3: int) -> Optional[int]:
sql = insert(stageup).values(
user = user_id,
version = version,
stage_id = stage_id,
clear_status = clear_status,
clear_song_ct = clear_song_ct,
song1_score = score1,
song2_score = score2,
song3_score = score3,
)
conflict = sql.on_duplicate_key_update(
clear_status = clear_status,
clear_song_ct = clear_song_ct,
song1_score = score1,
song2_score = score2,
song3_score = score3,
play_ct = stageup.c.play_ct + 1
)
result = self.execute(conflict)
if result is None:
self.logger.warn(f"put_stageup: failed to update! user_id: {user_id} version: {version} stage_id: {stage_id}")
return None
return result.lastrowid
def get_stageup(self, user_id: int, version: int) -> Optional[List[Row]]:
sql = select(stageup).where(and_(stageup.c.user==user_id, stageup.c.version==version))
result = self.execute(sql)
if result is None: return None
return result.fetchall()
def get_stageup_stage(self, user_id: int, version: int, stage_id: int) -> Optional[Row]:
sql = select(stageup).where(
and_(
stageup.c.user == user_id,
stageup.c.version == version,
stageup.c.stage_id == stage_id,
)
)
result = self.execute(sql)
if result is None: return None
return result.fetchone()

View File

@@ -0,0 +1,68 @@
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
from sqlalchemy.types import Integer, String, TIMESTAMP, JSON, Boolean, Float
from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select
from sqlalchemy.engine import Row
from sqlalchemy.dialects.mysql import insert
from typing import Optional, List, Dict, Any
from core.data.schema import BaseData, metadata
from core.data import cached
music = Table(
"wacca_static_music",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column("version", Integer, nullable=False),
Column("songId", Integer),
Column("chartId", Integer),
Column("title", String(255)),
Column("artist", String(255)),
Column("bpm", String(255)),
Column("difficulty", Float),
Column("chartDesigner", String(255)),
Column("jacketFile", String(255)),
UniqueConstraint("version", "songId", "chartId", name="wacca_static_music_uk"),
mysql_charset='utf8mb4'
)
class WaccaStaticData(BaseData):
def put_music(self, version: int, song_id: int, chart_id: int, title: str, artist: str, bpm: str,
difficulty: float, chart_designer: str, jacket: str) -> Optional[int]:
sql = insert(music).values(
version = version,
songId = song_id,
chartId = chart_id,
title = title,
artist = artist,
bpm = bpm,
difficulty = difficulty,
chartDesigner = chart_designer,
jacketFile = jacket
)
conflict = sql.on_duplicate_key_update(
title = title,
artist = artist,
bpm = bpm,
difficulty = difficulty,
chartDesigner = chart_designer,
jacketFile = jacket
)
result = self.execute(conflict)
if result is None:
self.logger.warn(f"Failed to insert music {song_id} chart {chart_id}")
return None
return result.lastrowid
def get_music_chart(self, version: int, song_id: int, chart_id: int) -> Optional[List[Row]]:
sql = select(music).where(and_(
music.c.version == version,
music.c.songId == song_id,
music.c.chartId == chart_id
))
result = self.execute(sql)
if result is None: return None
return result.fetchone()