Equipments saving for SAO now completed
This commit is contained in:
parent
e466ddce55
commit
bf6d126f8a
@ -30,6 +30,9 @@ Games listed below have been tested and confirmed working. Only game versions ol
|
||||
+ POKKÉN TOURNAMENT
|
||||
+ Final Online
|
||||
|
||||
+ Sword Art Online Arcade (partial support)
|
||||
+ Final
|
||||
|
||||
## Requirements
|
||||
- python 3 (tested working with 3.9 and 3.10, other versions YMMV)
|
||||
- pip
|
||||
|
@ -81,6 +81,9 @@ class SaoBase:
|
||||
self.game_data.item.put_hero_log(user_id, 102000010, 1, 0, 103000006, 0, 30086, 1001, 1002, 1003, 1005)
|
||||
self.game_data.item.put_hero_log(user_id, 103000010, 1, 0, 112000009, 0, 30086, 1001, 1002, 1003, 1005)
|
||||
self.game_data.item.put_hero_party(user_id, 0, 101000010, 102000010, 103000010)
|
||||
self.game_data.item.put_equipment_data(user_id, 101000016, 1, 200, 0, 0, 0)
|
||||
self.game_data.item.put_equipment_data(user_id, 103000006, 1, 200, 0, 0, 0)
|
||||
self.game_data.item.put_equipment_data(user_id, 112000009, 1, 200, 0, 0, 0)
|
||||
|
||||
self.logger.info(f"User Authenticated: { access_code } | { user_id }")
|
||||
|
||||
@ -145,9 +148,19 @@ class SaoBase:
|
||||
|
||||
def handle_c602(self, request: Any) -> bytes:
|
||||
#have_object/get_equipment_user_data_list
|
||||
equipmentIdsData = self.game_data.static.get_equipment_ids(0, True)
|
||||
|
||||
resp = SaoGetEquipmentUserDataListResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1, equipmentIdsData)
|
||||
req = bytes.fromhex(request)[24:]
|
||||
req_struct = Struct(
|
||||
Padding(16),
|
||||
"user_id_size" / Rebuild(Int32ub, len_(this.user_id) * 2), # calculates the length of the user_id
|
||||
"user_id" / PaddedString(this.user_id_size, "utf_16_le"), # user_id is a (zero) padded string
|
||||
|
||||
)
|
||||
req_data = req_struct.parse(req)
|
||||
user_id = req_data.user_id
|
||||
|
||||
equipment_data = self.game_data.item.get_user_equipments(user_id)
|
||||
|
||||
resp = SaoGetEquipmentUserDataListResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1, equipment_data)
|
||||
return resp.make()
|
||||
|
||||
def handle_c604(self, request: Any) -> bytes:
|
||||
@ -510,10 +523,11 @@ class SaoBase:
|
||||
randomized_unanalyzed_id = choice(data_unanalyzed)
|
||||
|
||||
heroList = self.game_data.static.get_hero_id(randomized_unanalyzed_id['CommonRewardId'])
|
||||
equipmentList = self.game_data.static.get_equipment_id(randomized_unanalyzed_id['CommonRewardId'])
|
||||
if heroList:
|
||||
self.game_data.item.put_hero_log(req_data.user_id, randomized_unanalyzed_id['CommonRewardId'], 1, 0, 101000016, 0, 30086, 1001, 1002, 0, 0)
|
||||
|
||||
# Item and Equipments saving will be done later here
|
||||
if equipmentList:
|
||||
self.game_data.item.put_equipment_data(req_data.user_id, randomized_unanalyzed_id['CommonRewardId'], 1, 200, 0, 0, 0)
|
||||
|
||||
# Send response
|
||||
|
||||
@ -532,4 +546,4 @@ class SaoBase:
|
||||
def handle_c90a(self, request: Any) -> bytes: #should be tweaked for proper item unlock
|
||||
#quest/episode_play_end_unanalyzed_log_fixed
|
||||
resp = SaoEpisodePlayEndUnanalyzedLogFixedResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1)
|
||||
return resp.make()
|
||||
return resp.make()
|
||||
|
BIN
titles/sao/data/EquipmentLevel.csv
Normal file
BIN
titles/sao/data/EquipmentLevel.csv
Normal file
Binary file not shown.
|
@ -660,19 +660,57 @@ class SaoGetEquipmentUserDataListRequest(SaoBaseRequest):
|
||||
super().__init__(data)
|
||||
|
||||
class SaoGetEquipmentUserDataListResponse(SaoBaseResponse):
|
||||
def __init__(self, cmd, equipmentIdsData) -> None:
|
||||
def __init__(self, cmd, equipment_data) -> None:
|
||||
super().__init__(cmd)
|
||||
self.result = 1
|
||||
|
||||
self.user_equipment_id = []
|
||||
self.enhancement_value = []
|
||||
self.max_enhancement_value_extended_num = []
|
||||
self.enhancement_exp = []
|
||||
self.awakening_stage = []
|
||||
self.awakening_exp = []
|
||||
self.possible_awakening_flag = []
|
||||
equipment_level = 0
|
||||
|
||||
for i in range(len(equipment_data)):
|
||||
|
||||
# Calculate level based off experience and the CSV list
|
||||
with open(r'titles/sao/data/EquipmentLevel.csv') as csv_file:
|
||||
csv_reader = csv.reader(csv_file, delimiter=',')
|
||||
line_count = 0
|
||||
data = []
|
||||
rowf = False
|
||||
for row in csv_reader:
|
||||
if rowf==False:
|
||||
rowf=True
|
||||
else:
|
||||
data.append(row)
|
||||
|
||||
exp = equipment_data[i][4]
|
||||
|
||||
for e in range(0,len(data)):
|
||||
if exp>=int(data[e][1]) and exp<int(data[e+1][1]):
|
||||
equipment_level = int(data[e][0])
|
||||
break
|
||||
|
||||
self.user_equipment_id.append(equipment_data[i][2])
|
||||
self.enhancement_value.append(equipment_level)
|
||||
self.max_enhancement_value_extended_num.append(equipment_level)
|
||||
self.enhancement_exp.append(equipment_data[i][4])
|
||||
self.awakening_stage.append(equipment_data[i][5])
|
||||
self.awakening_exp.append(equipment_data[i][6])
|
||||
self.possible_awakening_flag.append(equipment_data[i][7])
|
||||
|
||||
# equipment_user_data_list
|
||||
self.user_equipment_id = list(map(str,equipmentIdsData)) #str
|
||||
self.equipment_id = equipmentIdsData #int
|
||||
self.enhancement_value = 10 #short
|
||||
self.max_enhancement_value_extended_num = 10 #short
|
||||
self.enhancement_exp = 1000 #int
|
||||
self.possible_awakening_flag = 0 #byte
|
||||
self.awakening_stage = 0 #short
|
||||
self.awakening_exp = 0 #int
|
||||
self.user_equipment_id = list(map(str,self.user_equipment_id)) #str
|
||||
self.equipment_id = list(map(int,self.user_equipment_id)) #int
|
||||
self.enhancement_value = list(map(int,self.enhancement_value)) #short
|
||||
self.max_enhancement_value_extended_num = list(map(int,self.max_enhancement_value_extended_num)) #short
|
||||
self.enhancement_exp = list(map(int,self.enhancement_exp)) #int
|
||||
self.possible_awakening_flag = list(map(int,self.possible_awakening_flag)) #byte
|
||||
self.awakening_stage = list(map(int,self.awakening_stage)) #short
|
||||
self.awakening_exp = list(map(int,self.awakening_exp)) #int
|
||||
self.property1_property_id = 0 #int
|
||||
self.property1_value1 = 0 #int
|
||||
self.property1_value2 = 0 #int
|
||||
@ -739,12 +777,12 @@ class SaoGetEquipmentUserDataListResponse(SaoBaseResponse):
|
||||
user_equipment_id_size=len(self.user_equipment_id[i]) * 2,
|
||||
user_equipment_id=[ord(x) for x in self.user_equipment_id[i]],
|
||||
equipment_id=self.equipment_id[i],
|
||||
enhancement_value=self.enhancement_value,
|
||||
max_enhancement_value_extended_num=self.max_enhancement_value_extended_num,
|
||||
enhancement_exp=self.enhancement_exp,
|
||||
possible_awakening_flag=self.possible_awakening_flag,
|
||||
awakening_stage=self.awakening_stage,
|
||||
awakening_exp=self.awakening_exp,
|
||||
enhancement_value=self.enhancement_value[i],
|
||||
max_enhancement_value_extended_num=self.max_enhancement_value_extended_num[i],
|
||||
enhancement_exp=self.enhancement_exp[i],
|
||||
possible_awakening_flag=self.possible_awakening_flag[i],
|
||||
awakening_stage=self.awakening_stage[i],
|
||||
awakening_exp=self.awakening_exp[i],
|
||||
property1_property_id=self.property1_property_id,
|
||||
property1_value1=self.property1_value1,
|
||||
property1_value2=self.property1_value2,
|
||||
|
@ -8,6 +8,26 @@ from sqlalchemy.dialects.mysql import insert
|
||||
|
||||
from core.data.schema import BaseData, metadata
|
||||
|
||||
equipment_data = Table(
|
||||
"sao_equipment_data",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, nullable=False),
|
||||
Column(
|
||||
"user",
|
||||
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
|
||||
nullable=False,
|
||||
),
|
||||
Column("equipment_id", Integer, 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("get_date", TIMESTAMP, nullable=False, server_default=func.now()),
|
||||
UniqueConstraint("user", "equipment_id", name="sao_equipment_data_uk"),
|
||||
mysql_charset="utf8mb4",
|
||||
)
|
||||
|
||||
hero_log_data = Table(
|
||||
"sao_hero_log_data",
|
||||
metadata,
|
||||
@ -84,6 +104,34 @@ class SaoItemData(BaseData):
|
||||
self.logger.error(f"Failed to create SAO session for user {user_id}!")
|
||||
return None
|
||||
return result.lastrowid
|
||||
|
||||
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]:
|
||||
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,
|
||||
)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
result = 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
|
||||
|
||||
return result.lastrowid
|
||||
|
||||
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(
|
||||
@ -144,6 +192,23 @@ class SaoItemData(BaseData):
|
||||
return None
|
||||
|
||||
return result.lastrowid
|
||||
|
||||
def get_user_equipments(
|
||||
self, user_id: int
|
||||
) -> Optional[List[Row]]:
|
||||
"""
|
||||
A catch-all equipments lookup given a profile
|
||||
"""
|
||||
sql = equipment_data.select(
|
||||
and_(
|
||||
equipment_data.c.user == user_id,
|
||||
)
|
||||
)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None:
|
||||
return None
|
||||
return result.fetchall()
|
||||
|
||||
def get_hero_log(
|
||||
self, user_id: int, user_hero_log_id: int = None
|
||||
@ -167,7 +232,7 @@ class SaoItemData(BaseData):
|
||||
self, user_id: int
|
||||
) -> Optional[List[Row]]:
|
||||
"""
|
||||
A catch-all hero lookup given a profile and user_party_team_id and ID specifiers
|
||||
A catch-all hero lookup given a profile
|
||||
"""
|
||||
sql = hero_log_data.select(
|
||||
and_(
|
||||
|
@ -264,6 +264,14 @@ class SaoStaticData(BaseData):
|
||||
return None
|
||||
return [list[2] for list in result.fetchall()]
|
||||
|
||||
def get_equipment_id(self, equipmentId: int) -> Optional[Dict]:
|
||||
sql = equipment.select(equipment.c.equipmentId == equipmentId)
|
||||
|
||||
result = self.execute(sql)
|
||||
if result is None:
|
||||
return None
|
||||
return result.fetchone()
|
||||
|
||||
def get_equipment_ids(self, version: int, enabled: bool) -> Optional[List[Dict]]:
|
||||
sql = equipment.select(equipment.c.version == version and equipment.c.enabled == enabled).order_by(
|
||||
equipment.c.equipmentId.asc()
|
||||
|
Loading…
Reference in New Issue
Block a user