sao: backport changes from diana

This commit is contained in:
Kevin Trocolli
2024-06-25 14:02:53 -04:00
parent 6ae11f96a2
commit e91f84fecc
167 changed files with 100587 additions and 28291 deletions

View File

@@ -1,6 +1,6 @@
from typing import Optional, Dict, List
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_, case
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON, BOOLEAN, INTEGER, BIGINT
from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select, update, delete
from sqlalchemy.engine import Row
@@ -17,15 +17,30 @@ equipment_data = Table(
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("equipment_id", Integer, nullable=False),
Column("equipment_id", BIGINT, ForeignKey("sao_static_equipment_list.EquipmentId", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("enhancement_value", Integer, nullable=False),
Column("enhancement_exp", Integer, nullable=False),
Column("awakening_exp", Integer, nullable=False),
Column("awakening_stage", Integer, nullable=False),
Column("possible_awakening_flag", Integer, nullable=False),
Column("is_shop_purchase", BOOLEAN, nullable=False, server_default="0"),
Column("is_protect", BOOLEAN, nullable=False, server_default="0"),
Column("property1_property_id", BIGINT, ForeignKey("sao_static_property.PropertyId", ondelete="cascade", onupdate="cascade"), nullable=False, server_default="2"),
Column("property1_value1", INTEGER, nullable=False, server_default="0"),
Column("property1_value2", INTEGER, nullable=False, server_default="0"),
Column("property2_property_id", BIGINT, ForeignKey("sao_static_property.PropertyId", ondelete="cascade", onupdate="cascade"), nullable=False, server_default="2"),
Column("property2_value1", INTEGER, nullable=False, server_default="0"),
Column("property2_value2", INTEGER, nullable=False, server_default="0"),
Column("property3_property_id", BIGINT, ForeignKey("sao_static_property.PropertyId", ondelete="cascade", onupdate="cascade"), nullable=False, server_default="2"),
Column("property3_value1", INTEGER, nullable=False, server_default="0"),
Column("property3_value2", INTEGER, nullable=False, server_default="0"),
Column("property4_property_id", BIGINT, ForeignKey("sao_static_property.PropertyId", ondelete="cascade", onupdate="cascade"), nullable=False, server_default="2"),
Column("property4_value1", INTEGER, nullable=False, server_default="0"),
Column("property4_value2", INTEGER, nullable=False, server_default="0"),
Column("converted_card_num", INTEGER, nullable=False, server_default="0"),
Column("get_date", TIMESTAMP, nullable=False, server_default=func.now()),
UniqueConstraint("user", "equipment_id", name="sao_equipment_data_uk"),
mysql_charset="utf8mb4",
mysql_charset="utf8mb4"
)
item_data = Table(
@@ -40,7 +55,7 @@ item_data = Table(
Column("item_id", Integer, nullable=False),
Column("get_date", TIMESTAMP, nullable=False, server_default=func.now()),
UniqueConstraint("user", "item_id", name="sao_item_data_uk"),
mysql_charset="utf8mb4",
mysql_charset="utf8mb4"
)
hero_log_data = Table(
@@ -52,19 +67,38 @@ hero_log_data = Table(
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("user_hero_log_id", Integer, nullable=False),
Column("hero_log_id", BIGINT, ForeignKey("sao_static_hero_list.HeroLogId", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("log_level", Integer, nullable=False),
Column("log_exp", Integer, nullable=False),
Column("main_weapon", Integer, nullable=False),
Column("sub_equipment", Integer, nullable=False),
Column("skill_slot1_skill_id", Integer, nullable=False),
Column("skill_slot2_skill_id", Integer, nullable=False),
Column("skill_slot3_skill_id", Integer, nullable=False),
Column("skill_slot4_skill_id", Integer, nullable=False),
Column("skill_slot5_skill_id", Integer, nullable=False),
Column("main_weapon", BIGINT, ForeignKey("sao_equipment_data.id", ondelete="set null", onupdate="set null")),
Column("sub_equipment", BIGINT, ForeignKey("sao_equipment_data.id", ondelete="set null", onupdate="set null")),
Column("skill_slot1_skill_id", BIGINT, ForeignKey("sao_static_skill.SkillId", ondelete="set null", onupdate="set null")),
Column("skill_slot2_skill_id", BIGINT, ForeignKey("sao_static_skill.SkillId", ondelete="set null", onupdate="set null")),
Column("skill_slot3_skill_id", BIGINT, ForeignKey("sao_static_skill.SkillId", ondelete="set null", onupdate="set null")),
Column("skill_slot4_skill_id", BIGINT, ForeignKey("sao_static_skill.SkillId", ondelete="set null", onupdate="set null")),
Column("skill_slot5_skill_id", BIGINT, ForeignKey("sao_static_skill.SkillId", ondelete="set null", onupdate="set null")),
Column("max_level_extend_num", INTEGER, nullable=False, server_default="0"),
Column("is_awakenable", BOOLEAN, nullable=False, server_default="0"),
Column("awakening_stage", INTEGER, nullable=False, server_default="0"),
Column("awakening_exp", INTEGER, nullable=False, server_default="0"),
Column("is_shop_purchase", BOOLEAN, nullable=False, server_default="0"),
Column("is_protect", BOOLEAN, nullable=False, server_default="0"),
Column("property1_property_id", BIGINT, ForeignKey("sao_static_property.PropertyId", ondelete="cascade", onupdate="cascade"), nullable=False, server_default="2"),
Column("property1_value1", INTEGER, nullable=False, server_default="0"),
Column("property1_value2", INTEGER, nullable=False, server_default="0"),
Column("property2_property_id", BIGINT, ForeignKey("sao_static_property.PropertyId", ondelete="cascade", onupdate="cascade"), nullable=False, server_default="2"),
Column("property2_value1", INTEGER, nullable=False, server_default="0"),
Column("property2_value2", INTEGER, nullable=False, server_default="0"),
Column("property3_property_id", BIGINT, ForeignKey("sao_static_property.PropertyId", ondelete="cascade", onupdate="cascade"), nullable=False, server_default="2"),
Column("property3_value1", INTEGER, nullable=False, server_default="0"),
Column("property3_value2", INTEGER, nullable=False, server_default="0"),
Column("property4_property_id", BIGINT, ForeignKey("sao_static_property.PropertyId", ondelete="cascade", onupdate="cascade"), nullable=False, server_default="2"),
Column("property4_value1", INTEGER, nullable=False, server_default="0"),
Column("property4_value2", INTEGER, nullable=False, server_default="0"),
Column("converted_card_num", INTEGER, nullable=False, server_default="0"),
Column("get_date", TIMESTAMP, nullable=False, server_default=func.now()),
UniqueConstraint("user", "user_hero_log_id", name="sao_hero_log_data_uk"),
mysql_charset="utf8mb4",
UniqueConstraint("user", "hero_log_id", name="sao_hero_log_data_uk"),
mysql_charset="utf8mb4"
)
hero_party = Table(
@@ -77,11 +111,11 @@ hero_party = Table(
nullable=False,
),
Column("user_party_team_id", Integer, nullable=False),
Column("user_hero_log_id_1", Integer, nullable=False),
Column("user_hero_log_id_2", Integer, nullable=False),
Column("user_hero_log_id_3", Integer, nullable=False),
Column("user_hero_log_id_1", Integer, ForeignKey("sao_hero_log_data.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("user_hero_log_id_2", Integer, ForeignKey("sao_hero_log_data.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("user_hero_log_id_3", Integer, ForeignKey("sao_hero_log_data.id", ondelete="cascade", onupdate="cascade"), nullable=False),
UniqueConstraint("user", "user_party_team_id", name="sao_hero_party_uk"),
mysql_charset="utf8mb4",
mysql_charset="utf8mb4"
)
quest = Table(
@@ -93,15 +127,28 @@ quest = Table(
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("episode_id", Integer, nullable=False),
Column("quest_type", INTEGER, nullable=False, server_default="1"),
Column("quest_scene_id", BIGINT, ForeignKey("sao_static_quest.QuestSceneId", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("quest_clear_flag", Boolean, nullable=False),
Column("clear_time", Integer, nullable=False),
Column("combo_num", Integer, nullable=False),
Column("total_damage", Integer, nullable=False),
Column("concurrent_destroying_num", Integer, nullable=False),
Column("play_date", TIMESTAMP, nullable=False, server_default=func.now()),
UniqueConstraint("user", "episode_id", name="sao_player_quest_uk"),
mysql_charset="utf8mb4",
UniqueConstraint("user", "quest_scene_id", name="sao_player_quest_uk"),
mysql_charset="utf8mb4"
)
ex_bonus = Table(
"sao_player_ex_bonus",
metadata,
Column("id", BIGINT, primary_key=True, nullable=False),
Column("user", INTEGER, ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("quest_scene_id", BIGINT, ForeignKey("sao_static_quest.QuestSceneId", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("ex_bonus_table_id", BIGINT, ForeignKey("sao_static_ex_bonus.ExBonusTableId", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("quest_clear_flag", BOOLEAN, nullable=False, server_default="0"),
UniqueConstraint("user", "quest_scene_id", "ex_bonus_table_id", name="sao_player_ex_bonus_uk"),
mysql_charset="utf8mb4"
)
sessions = Table(
@@ -114,12 +161,12 @@ sessions = Table(
nullable=False,
),
Column("user_party_team_id", Integer, nullable=False),
Column("episode_id", Integer, nullable=False),
Column("episode_id", Integer, nullable=False), # TODO: Change to quest scene id
Column("play_mode", Integer, nullable=False),
Column("quest_drop_boost_apply_flag", Integer, nullable=False),
Column("play_date", TIMESTAMP, nullable=False, server_default=func.now()),
UniqueConstraint("user", "user_party_team_id", "play_date", name="sao_play_sessions_uk"),
mysql_charset="utf8mb4",
mysql_charset="utf8mb4"
)
end_sessions = Table(
@@ -135,7 +182,7 @@ end_sessions = Table(
Column("play_result_flag", Boolean, nullable=False),
Column("reward_data", JSON, nullable=True),
Column("play_date", TIMESTAMP, nullable=False, server_default=func.now()),
mysql_charset="utf8mb4",
mysql_charset="utf8mb4"
)
class SaoItemData(BaseData):
@@ -148,13 +195,17 @@ class SaoItemData(BaseData):
quest_drop_boost_apply_flag=quest_drop_boost_apply_flag
)
conflict = sql.on_duplicate_key_update(user=user_id)
conflict = sql.on_duplicate_key_update(
user_party_team_id=user_party_team_id,
episode_id=episode_id,
play_mode=play_mode,
quest_drop_boost_apply_flag=quest_drop_boost_apply_flag
)
result = await self.execute(conflict)
if result is None:
self.logger.error(f"Failed to create SAO session for user {user_id}!")
return None
return result.lastrowid
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to create SAO session for user {user_id}!")
async def create_end_session(self, user_id: int, quest_id: int, play_result_flag: bool, reward_data: JSON) -> Optional[int]:
sql = insert(end_sessions).values(
@@ -164,13 +215,16 @@ class SaoItemData(BaseData):
reward_data=reward_data,
)
conflict = sql.on_duplicate_key_update(user=user_id)
conflict = sql.on_duplicate_key_update(
play_result_flag=play_result_flag,
reward_data=reward_data
)
result = await self.execute(conflict)
if result is None:
self.logger.error(f"Failed to create SAO end session for user {user_id}!")
return None
return result.lastrowid
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to create SAO end session for user {user_id}!")
async def put_item(self, user_id: int, item_id: int) -> Optional[int]:
sql = insert(item_data).values(
@@ -178,51 +232,93 @@ class SaoItemData(BaseData):
item_id=item_id,
)
conflict = sql.on_duplicate_key_update(
item_id=item_id,
)
conflict = sql.on_duplicate_key_update(item_id=item_id)
result = await self.execute(conflict)
if result is None:
self.logger.error(
f"{__name__} failed to insert item! user: {user_id}, item_id: {item_id}"
)
return None
return result.lastrowid
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert item! user: {user_id}, item_id: {item_id}")
async def put_equipment_data(self, user_id: int, equipment_id: int, enhancement_value: int, enhancement_exp: int, awakening_exp: int, awakening_stage: int, possible_awakening_flag: int) -> Optional[int]:
async def put_equipment(self, user_id: int, equipment_id: int) -> Optional[int]:
sql = insert(equipment_data).values(
user=user_id,
equipment_id=equipment_id,
enhancement_value=enhancement_value,
enhancement_exp=enhancement_exp,
awakening_exp=awakening_exp,
awakening_stage=awakening_stage,
possible_awakening_flag=possible_awakening_flag,
enhancement_value=1,
enhancement_exp=200,
awakening_exp=0,
awakening_stage=0,
possible_awakening_flag=0,
)
conflict = sql.on_duplicate_key_update(
enhancement_value=enhancement_value,
enhancement_exp=enhancement_exp,
awakening_exp=awakening_exp,
awakening_stage=awakening_stage,
possible_awakening_flag=possible_awakening_flag,
)
conflict = sql.on_duplicate_key_update(equipment_id=equipment_id)
result = await self.execute(conflict)
if result is None:
self.logger.error(
f"{__name__} failed to insert equipment! user: {user_id}, equipment_id: {equipment_id}"
)
return None
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert equipment! user: {user_id}, equipment_id: {equipment_id}")
async def put_ex_bonus(self, user_id: int, quest_scene_id: int, ex_bonus_id: int, clear: bool = False) -> Optional[int]:
sql = insert(ex_bonus).values(
user=user_id,
quest_scene_id=quest_scene_id,
ex_bonus_table_id=ex_bonus_id,
quest_clear_flag=clear,
)
return result.lastrowid
conflict = sql.on_duplicate_key_update(quest_clear_flag=clear)
result = await self.execute(conflict)
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert ex bonus status! user: {user_id}, quest_scene_id: {quest_scene_id}, ex_bonus_id: {ex_bonus_id}, clear: {clear}")
async def add_equipment_enhancement_exp(self, user_weapon_id: int, enhancement_exp: int) -> None:
result = await self.execute(
equipment_data.update(equipment_data.c.id == user_weapon_id)
.values(enhancement_exp=equipment_data.c.enhancement_exp + enhancement_exp)
)
if not result:
self.logger.error(f"Failed to give equipment {user_weapon_id} {enhancement_exp} xp!")
async def get_equipment_enhancement_exp(self, user_weapon_id: int) -> Optional[int]:
result = await self.execute(select(equipment_data.c.enhancement_exp).where(equipment_data.c.id==user_weapon_id))
if result:
row = result.fetchone()
if row:
return row['enhancement_exp']
return 0
self.logger.error(f"Failed to get equipment {user_weapon_id} xp!")
async def set_equipment_enhancement_value(self, user_equip_id: int, enhancement_val: int) -> None:
result = await self.execute(equipment_data.update(equipment_data.c.id == user_equip_id).values(enhancement_value=enhancement_val))
if result is None:
self.logger.error(f"Failed to set equipment {user_equip_id} level to {enhancement_val}!")
async def add_hero_xp(self, user_hero_log_id: int, add_xp: int) -> Optional[int]:
result = await self.execute(
hero_log_data.update(hero_log_data.c.id == user_hero_log_id)
.values(log_exp=hero_log_data.c.log_exp + add_xp)
)
if not result:
self.logger.error(f"Failed to give hero {user_hero_log_id} {add_xp} xp!")
async def get_hero_xp(self, user_hero_log_id: int) -> Optional[int]:
result = await self.execute(select(hero_log_data.c.log_exp).where(hero_log_data.c.id==user_hero_log_id))
if result:
row = result.fetchone()
if row:
return row['log_exp']
return 0
self.logger.error(f"Failed to get hero xp for {user_hero_log_id}")
async def set_hero_level(self, user_hero_log_id: int, new_level: int):
result = await self.execute(hero_log_data.update(hero_log_data.c.id == user_hero_log_id).values(log_level=new_level))
if result is None:
self.logger.error(f"Failed to set hero {user_hero_log_id} level to {new_level}!")
async def put_hero_log(self, user_id: int, user_hero_log_id: int, log_level: int, log_exp: int, main_weapon: int, sub_equipment: int, skill_slot1_skill_id: int, skill_slot2_skill_id: int, skill_slot3_skill_id: int, skill_slot4_skill_id: int, skill_slot5_skill_id: int) -> Optional[int]:
sql = insert(hero_log_data).values(
user=user_id,
user_hero_log_id=user_hero_log_id,
hero_log_id=user_hero_log_id,
log_level=log_level,
log_exp=log_exp,
main_weapon=main_weapon,
@@ -243,17 +339,36 @@ class SaoItemData(BaseData):
skill_slot2_skill_id=skill_slot2_skill_id,
skill_slot3_skill_id=skill_slot3_skill_id,
skill_slot4_skill_id=skill_slot4_skill_id,
skill_slot5_skill_id=skill_slot5_skill_id,
skill_slot5_skill_id=skill_slot5_skill_id
)
result = await self.execute(conflict)
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert hero! user: {user_id}, user_hero_log_id: {user_hero_log_id}")
async def set_user_hero_weapons(self, user_hero_id: int, main_weapon: int, sub_weapon: int) -> None:
sql = hero_log_data.update(hero_log_data.c.id == user_hero_id).values(
main_weapon=main_weapon,
sub_equipment=sub_weapon,
)
result = await self.execute(sql)
if result is None:
self.logger.error(
f"{__name__} failed to insert hero! user: {user_id}, user_hero_log_id: {user_hero_log_id}"
)
self.logger.error(f"Failed to update user hero {user_hero_id} weapons {main_weapon}/{sub_weapon}")
return None
return result.lastrowid
async def set_user_hero_skills(self, user_hero_id: int, skill1: int, skill2: int, skill3: int, skill4: int, skill5: int) -> None:
sql = hero_log_data.update(hero_log_data.c.id == user_hero_id).values(
skill_slot1_skill_id = skill1,
skill_slot2_skill_id = skill2,
skill_slot3_skill_id = skill3,
skill_slot4_skill_id = skill4,
skill_slot5_skill_id = skill5,
)
result = await self.execute(sql)
if result is None:
self.logger.error(f"Failed to update user hero {user_hero_id} skills {skill1}/{skill2}/{skill3}/{skill4}/{skill5}")
return None
async def put_hero_party(self, user_id: int, user_party_team_id: int, user_hero_log_id_1: int, user_hero_log_id_2: int, user_hero_log_id_3: int) -> Optional[int]:
sql = insert(hero_party).values(
@@ -267,22 +382,19 @@ class SaoItemData(BaseData):
conflict = sql.on_duplicate_key_update(
user_hero_log_id_1=user_hero_log_id_1,
user_hero_log_id_2=user_hero_log_id_2,
user_hero_log_id_3=user_hero_log_id_3,
user_hero_log_id_3=user_hero_log_id_3
)
result = await self.execute(conflict)
if result is None:
self.logger.error(
f"{__name__} failed to insert hero party! user: {user_id}, user_party_team_id: {user_party_team_id}"
)
return None
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert hero party! user: {user_id}, user_party_team_id: {user_party_team_id}")
return result.lastrowid
async def put_player_quest(self, user_id: int, episode_id: int, quest_clear_flag: bool, clear_time: int, combo_num: int, total_damage: int, concurrent_destroying_num: int) -> Optional[int]:
async def put_player_quest(self, user_id: int, quest_type: int, quest_scene_id: int, quest_clear_flag: bool, clear_time: int, combo_num: int, total_damage: int, concurrent_destroying_num: int) -> Optional[int]:
sql = insert(quest).values(
user=user_id,
episode_id=episode_id,
quest_type=quest_type,
quest_scene_id=quest_scene_id,
quest_clear_flag=quest_clear_flag,
clear_time=clear_time,
combo_num=combo_num,
@@ -299,13 +411,9 @@ class SaoItemData(BaseData):
)
result = await self.execute(conflict)
if result is None:
self.logger.error(
f"{__name__} failed to insert quest! user: {user_id}, episode_id: {episode_id}"
)
return None
return result.lastrowid
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert quest! user: {user_id}, quest_scene_id: {quest_scene_id}")
async def get_user_equipment(self, user_id: int, equipment_id: int) -> Optional[Dict]:
sql = equipment_data.select(equipment_data.c.user == user_id and equipment_data.c.equipment_id == equipment_id)
@@ -315,6 +423,14 @@ class SaoItemData(BaseData):
return None
return result.fetchone()
async def get_user_equipment_by_id(self, equipment_user_id: int) -> Optional[Row]:
sql = equipment_data.select(equipment_data.c.id == equipment_user_id)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
async def get_user_equipments(
self, user_id: int
) -> Optional[List[Row]]:
@@ -349,6 +465,38 @@ class SaoItemData(BaseData):
return None
return result.fetchall()
async def get_player_ex_bonus_status(self, user_id: int) -> Optional[List[Row]]:
sql = equipment_data.select(ex_bonus.c.user == user_id)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
async def get_player_ex_bonus_by_quest(self, user_id: int, quest_scene_id) -> Optional[List[Row]]:
sql = ex_bonus.select(and_(ex_bonus.c.user == user_id, ex_bonus.c.quest_scene_id == quest_scene_id))
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
async def get_user_item_by_id(
self, user_item_id: int
) -> Optional[Row]:
sql = item_data.select(item_data.c.id == user_item_id)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
async def get_user_hero_by_id(self, user_hero_id: int) -> Optional[Row]:
result = await self.execute(hero_log_data.select(hero_log_data.c.id == user_hero_id))
if result is None:
return None
return result.fetchone()
async def get_hero_log(
self, user_id: int, user_hero_log_id: int = None
) -> Optional[List[Row]]:
@@ -358,7 +506,7 @@ class SaoItemData(BaseData):
sql = hero_log_data.select(
and_(
hero_log_data.c.user == user_id,
hero_log_data.c.user_hero_log_id == user_hero_log_id if user_hero_log_id is not None else True,
hero_log_data.c.hero_log_id == user_hero_log_id if user_hero_log_id is not None else True,
)
)
@@ -366,6 +514,12 @@ class SaoItemData(BaseData):
if result is None:
return None
return result.fetchone()
async def get_hero_log_by_id(self, user_hero_log_id: int) -> Optional[Row]:
result = await self.execute(hero_log_data.select(hero_log_data.c.id == user_hero_log_id))
if result is None:
return None
return result.fetchone()
async def get_hero_logs(
self, user_id: int
@@ -373,17 +527,17 @@ class SaoItemData(BaseData):
"""
A catch-all hero lookup given a profile
"""
sql = hero_log_data.select(
and_(
hero_log_data.c.user == user_id,
)
)
result = await self.execute(sql)
result = await self.execute(hero_log_data.select(hero_log_data.c.user == user_id))
if result is None:
return None
return result.fetchall()
async def get_hero_party_by_id(self, party_id: int) -> Optional[Row]:
result = await self.execute(hero_party.select(hero_party.c.id == party_id))
if result is None:
return None
return result.fetchone()
async def get_hero_party(
self, user_id: int, user_party_team_id: int = None
) -> Optional[List[Row]]:
@@ -397,18 +551,18 @@ class SaoItemData(BaseData):
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
return result.fetchall()
async def get_quest_log(
self, user_id: int, episode_id: int = None
) -> Optional[List[Row]]:
self, user_id: int, quest_scene_id: int
) -> Optional[Row]:
"""
A catch-all quest lookup given a profile and episode_id
A catch-all quest lookup given a profile and quest_scene_id
"""
sql = quest.select(
and_(
quest.c.user == user_id,
quest.c.episode_id == episode_id if episode_id is not None else True,
quest.c.quest_scene_id == quest_scene_id
)
)
@@ -420,16 +574,7 @@ class SaoItemData(BaseData):
async def get_quest_logs(
self, user_id: int
) -> Optional[List[Row]]:
"""
A catch-all quest lookup given a profile
"""
sql = quest.select(
and_(
quest.c.user == user_id,
)
)
result = await self.execute(sql)
result = await self.execute(quest.select(quest.c.user == user_id))
if result is None:
return None
return result.fetchall()
@@ -437,13 +582,7 @@ class SaoItemData(BaseData):
async def get_session(
self, user_id: int = None
) -> Optional[List[Row]]:
sql = sessions.select(
and_(
sessions.c.user == user_id,
)
).order_by(
sessions.c.play_date.asc()
)
sql = sessions.select(sessions.c.user == user_id).order_by(sessions.c.play_date.desc())
result = await self.execute(sql)
if result is None:
@@ -453,54 +592,36 @@ class SaoItemData(BaseData):
async def get_end_session(
self, user_id: int = None
) -> Optional[List[Row]]:
sql = end_sessions.select(
and_(
end_sessions.c.user == user_id,
)
).order_by(
end_sessions.c.play_date.desc()
)
sql = end_sessions.select(end_sessions.c.user == user_id).order_by(end_sessions.c.play_date.desc())
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
async def remove_hero_log(self, user_id: int, user_hero_log_id: int) -> None:
sql = hero_log_data.delete(
and_(
hero_log_data.c.user == user_id,
hero_log_data.c.user_hero_log_id == user_hero_log_id,
)
)
async def remove_end_session(self, end_id: int) -> None:
result = await self.execute(end_sessions.delete(end_sessions.c.id == end_id))
if result is None:
self.logger.error(f"Failed to delete end session {end_id}")
async def remove_hero_log(self, user_hero_log_id: int) -> None:
sql = hero_log_data.delete(hero_log_data.c.id == user_hero_log_id)
result = await self.execute(sql)
if result is None:
self.logger.error(
f"{__name__} failed to remove hero log! profile: {user_id}, user_hero_log_id: {user_hero_log_id}"
)
return None
if not result:
self.logger.error(f"Failed to remove hero log id: {user_hero_log_id}")
async def remove_equipment(self, user_id: int, equipment_id: int) -> None:
sql = equipment_data.delete(
and_(equipment_data.c.user == user_id, equipment_data.c.equipment_id == equipment_id)
)
async def remove_equipment(self, equipment_id: int) -> None:
sql = equipment_data.delete(equipment_data.c.id == equipment_id)
result = await self.execute(sql)
if result is None:
self.logger.error(
f"{__name__} failed to remove equipment! profile: {user_id}, equipment_id: {equipment_id}"
)
return None
if not result:
self.logger.error(f"Failed to remove equipment id {equipment_id}")
async def remove_item(self, user_id: int, item_id: int) -> None:
sql = item_data.delete(
and_(item_data.c.user == user_id, item_data.c.item_id == item_id)
)
async def remove_item(self, user_item_id: int) -> None:
sql = item_data.delete(item_data.c.id == user_item_id)
result = await self.execute(sql)
if result is None:
self.logger.error(
f"{__name__} failed to remove item! profile: {user_id}, item_id: {item_id}"
)
return None
if not result:
self.logger.error(f"Failed to remove item {user_item_id}!")

View File

@@ -1,13 +1,12 @@
from typing import Optional, Dict, List
from typing import Optional, Tuple, List
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_, case
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON
from sqlalchemy.types import Integer, String, BOOLEAN, INTEGER, BIGINT, VARCHAR, TIMESTAMP
from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select, update, delete
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 ..const import SaoConstants
profile = Table(
"sao_profile",
@@ -24,9 +23,70 @@ profile = Table(
Column("rank_num", Integer, server_default="1"),
Column("rank_exp", Integer, server_default="0"),
Column("own_col", Integer, server_default="0"),
Column("own_vp", Integer, server_default="300"),
Column("own_vp", Integer, server_default="0"),
Column("own_yui_medal", Integer, server_default="0"),
Column("setting_title_id", Integer, server_default="20005"),
Column("my_shop", INTEGER),
Column("fav_hero", INTEGER, ForeignKey("sao_hero_log_data.id", ondelete="set null", onupdate="cascade")),
Column("when_register", TIMESTAMP, server_default=func.now()),
Column("last_login_date", TIMESTAMP),
Column("last_yui_medal_date", TIMESTAMP),
Column("last_bonus_yui_medal_date", TIMESTAMP),
Column("last_comeback_date", TIMESTAMP),
Column("last_login_bonus_date", TIMESTAMP),
Column("ad_confirm_date", TIMESTAMP),
Column("login_ct", INTEGER, server_default="0"),
mysql_charset="utf8mb4"
)
beginner_mission = Table(
"sao_player_beginner_mission",
metadata,
Column("id", BIGINT, primary_key=True, nullable=False),
Column("user", INTEGER, ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False, unique=True),
Column("beginner_mission_id", INTEGER, nullable=False),
Column("condition_id", INTEGER, nullable=False),
Column("is_seat", BOOLEAN, nullable=False, server_default="0"),
Column("achievement_num", INTEGER, nullable=False),
Column("complete_flag", BOOLEAN, nullable=False, server_default="0"),
Column("complete_date", TIMESTAMP),
Column("reward_received_flag", BOOLEAN, nullable=False, server_default="0"),
Column("reward_received_date", TIMESTAMP),
UniqueConstraint("user", "condition_id", name="sao_player_beginner_mission_uk"),
mysql_charset="utf8mb4"
)
resource_card = Table(
"sao_player_resource_card",
metadata,
Column("id", BIGINT, primary_key=True, nullable=False),
Column("user", INTEGER, ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("common_reward_type", INTEGER, nullable=False),
Column("common_reward_id", INTEGER, nullable=False),
Column("holographic_flag", BOOLEAN, nullable=False, server_default="0"),
Column("serial", VARCHAR(20), unique=True),
mysql_charset="utf8mb4"
)
hero_card = Table(
"sao_player_hero_card",
metadata,
Column("id", BIGINT, primary_key=True, nullable=False),
Column("user", INTEGER, ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("user_hero_id", INTEGER, ForeignKey("sao_hero_log_data.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("holographic_flag", BOOLEAN, nullable=False, server_default="0"),
Column("serial", VARCHAR(20), unique=True),
mysql_charset="utf8mb4"
)
tutorial = Table(
"sao_player_tutorial",
metadata,
Column("id", BIGINT, primary_key=True, nullable=False),
Column("user", INTEGER, ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
Column("tutorial_byte", INTEGER, nullable=False),
UniqueConstraint("user", "tutorial_byte", name="sao_player_tutorial_uk"),
mysql_charset="utf8mb4"
)
class SaoProfileData(BaseData):
@@ -35,10 +95,81 @@ class SaoProfileData(BaseData):
conflict = sql.on_duplicate_key_update(user=user_id)
result = await self.execute(conflict)
if result:
return result.inserted_primary_key['id']
self.logger.error("Failed to create SAO profile!")
async def set_my_shop(self, user_id: int, store_id: int):
result = await self.execute(profile.update(profile.c.user == user_id).values(my_shop = store_id))
if result is None:
self.logger.error(f"Failed to create SAO profile for user {user_id}!")
return None
return result.lastrowid
self.logger.error(f"Failed to set my shop for user {user_id} to {store_id}!")
async def user_login(self, user_id: int) -> Optional[Row]:
sql = profile.update(profile.c.user == user_id).values(
login_ct=profile.c.login_ct + 1,
last_login_date=func.now()
)
result = await self.execute(sql)
if result:
return result.last_updated_params()
self.logger.error(f"Failed to create log in user {user_id}!")
async def update_yui_medal_date(self, user_id: int) -> None:
sql = profile.update(profile.c.user == user_id).values(
last_yui_medal_date=func.now()
)
result = await self.execute(sql)
if result is None:
self.logger.error(f"Failed to update user {user_id} yui medal date!")
async def add_yui_medals(self, user_id: int, num_medals: int = 1):
sql = profile.update(profile.c.user == user_id).values(
own_yui_medal=profile.c.own_yui_medal + num_medals
)
result = await self.execute(sql)
if result is None:
self.logger.error(f"Failed to give user {user_id} {num_medals} yui medals!")
async def add_col(self, user_id: int, num_col: int) -> None:
sql = profile.update(profile.c.user == user_id).values(
own_col=profile.c.own_col + num_col
)
result = await self.execute(sql)
if not result:
self.logger.error(f"Failed to give user {user_id} {num_col} Col!")
async def add_vp(self, user_id: int, num_vp: int) -> None:
sql = profile.update(profile.c.user == user_id).values(
own_vp=profile.c.own_vp + num_vp
)
result = await self.execute(sql)
if not result:
self.logger.error(f"Failed to give user {user_id} {num_vp} VP!")
async def add_exp(self, user_id: int, xp_ammount: int) -> Optional[int]:
sql = profile.update(profile.c.user == user_id).values(
rank_exp=profile.c.rank_exp + xp_ammount
)
result = await self.execute(sql)
if not result:
self.logger.error(f"Failed to give user {user_id} {xp_ammount} xp!")
async def get_exp(self, user_id: int) -> Optional[int]:
result = await self.execute(select(profile.c.rank_exp).where(profile.c.user==user_id))
if result:
row = result.fetchone()
if row:
return row['rank_exp']
return 0
self.logger.error(f"Failed to query rank xp for user {user_id}")
async def set_level(self, user_id: int, level: int):
sql = profile.update(profile.c.user == user_id).values(
rank_num=level
)
result = await self.execute(sql)
if result is None:
self.logger.error(f"Failed to set user {user_id} level to {level}!")
async def put_profile(self, user_id: int, user_type: int, nick_name: str, rank_num: int, rank_exp: int, own_col: int, own_vp: int, own_yui_medal: int, setting_title_id: int) -> Optional[int]:
sql = insert(profile).values(
@@ -63,17 +194,118 @@ class SaoProfileData(BaseData):
)
result = await self.execute(conflict)
if result is None:
self.logger.error(
f"{__name__} failed to insert profile! user: {user_id}"
)
return None
return result.lastrowid
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert profile! user: {user_id}")
async def get_profile(self, user_id: int) -> Optional[Row]:
sql = profile.select(profile.c.user == user_id)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
return result.fetchone()
async def set_profile_name(self, user_id: int, new_name: str) -> None:
sql = profile.update(profile.c.user == user_id).values(
nick_name=new_name
)
result = await self.execute(sql)
if result is None:
self.logger.error(f"Failed to update nickname {new_name} for user {user_id}")
async def add_tutorial_byte(self, user_id: int, tutorial_byte: int) -> None:
sql = insert(tutorial).values(
user = user_id,
tutorial_byte = tutorial_byte
)
conflict = sql.on_duplicate_key_update(tutorial_byte = tutorial_byte)
result = await self.execute(conflict)
if result is None:
self.logger.error(f"Failed to add tutorial byte {tutorial_byte} to user {user_id}")
async def get_tutorial_bytes(self, user_id: int) -> Optional[List[Row]]:
sql = tutorial.select(tutorial.c.user == user_id)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
async def put_hero_card(self, user_id: int, serial: str, user_hero_id: int, is_holo: bool) -> Optional[int]:
sql = insert(hero_card).values(
user=user_id,
user_hero_id=user_hero_id,
holographic_flag=is_holo,
serial=serial
)
conflict = sql.on_duplicate_key_update(
holographic_flag=is_holo,
serial=serial
)
result = await self.execute(conflict)
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert card {serial} for user {user_id} as hero {user_hero_id}")
async def get_hero_card(self, serial: str) -> Optional[Row]:
result = await self.execute(hero_card.select(hero_card.c.serial == serial))
if result is None:
return None
return result.fetchone()
async def put_resource_card(self, user_id: int, serial: str, reward_type: int, reward_id: int, is_holo: bool) -> Optional[int]:
sql = insert(resource_card).values(
user=user_id,
common_reward_type=reward_type,
common_reward_id=reward_id,
holographic_flag=is_holo,
serial=serial
)
conflict = sql.on_duplicate_key_update(
holographic_flag=is_holo,
serial=serial
)
result = await self.execute(conflict)
if result:
return result.inserted_primary_key['id']
self.logger.error(f"Failed to insert card {serial} for user {user_id} as resource {reward_id}")
async def get_resource_card(self, serial: str) -> Optional[int]:
result = await self.execute(resource_card.select(resource_card.c.serial == serial))
if result is None:
return None
return result.fetchone()
async def update_beginner_mission_date(self, user_id: int) -> None:
sql = profile.update(profile.c.user == user_id).values(
ad_confirm_date=func.now()
)
result = await self.execute(sql)
if result is None:
self.logger.error(f"Failed to update user {user_id} yui medal date!")
async def put_beginner_mission(self, user_id: int, beginner_mission_id: int, condition_id: int, is_seat: bool, achievement_num: int) -> Optional[int]:
pass
async def complete_beginner_mission(self, user_id: int, condition_id: int) -> None:
pass
async def reward_beginner_mission(self, user_id: int, condition_id: int) -> None:
pass
async def get_beginner_missions(self, user_id: int) -> Optional[List[Row]]:
pass
async def get_beginner_missions_by_mission_id(self, user_id: int, beginner_mission_id: int) -> Optional[List[Row]]:
pass
async def get_beginner_mission(self, user_id: int, condition_id: int) -> Optional[Row]:
pass
async def set_title(self, user_id: int, title_id: int) -> None:
result = await self.execute(profile.update(profile.c.user == user_id).values(setting_title_id=title_id))
if not result:
self.logger.error(f"Failed to set user {user_id} title to {title_id}")

File diff suppressed because it is too large Load Diff