fixing unanalyzed reward request for SAO

This commit is contained in:
Midorica 2023-07-02 14:25:24 -04:00
parent 20389011e9
commit 84e880e94f
5 changed files with 17400 additions and 17330 deletions

View File

@ -815,6 +815,8 @@ class SaoBase:
)
# Grab the rare loot from the table, match it with the right item and then push to the player profile
json_data = {"data": []}
for r in range(0,req_data.get_rare_drop_data_list_length):
rewardList = self.game_data.static.get_rare_drop_id(int(req_data.get_rare_drop_data_list[r].quest_rare_drop_id))
commonRewardId = rewardList["commonRewardId"]
@ -851,8 +853,12 @@ class SaoBase:
if itemList:
self.game_data.item.put_item(user_id, randomized_unanalyzed_id['CommonRewardId'])
json_data["data"].append(randomized_unanalyzed_id['CommonRewardId'])
# Send response
self.game_data.item.create_end_session(user_id, episode_id, quest_clear_flag, json_data["data"])
resp = SaoEpisodePlayEndResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1)
return resp.make()
@ -1118,6 +1124,8 @@ class SaoBase:
hero_data["skill_slot5_skill_id"]
)
json_data = {"data": []}
# Grab the rare loot from the table, match it with the right item and then push to the player profile
for r in range(0,req_data.get_rare_drop_data_list_length):
rewardList = self.game_data.static.get_rare_drop_id(int(req_data.get_rare_drop_data_list[r].quest_rare_drop_id))
@ -1155,8 +1163,12 @@ class SaoBase:
if itemList:
self.game_data.item.put_item(user_id, randomized_unanalyzed_id['CommonRewardId'])
json_data["data"].append(randomized_unanalyzed_id['CommonRewardId'])
# Send response
self.game_data.item.create_end_session(user_id, trial_tower_id, quest_clear_flag, json_data["data"])
resp = SaoTrialTowerPlayEndResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1)
return resp.make()
@ -1176,32 +1188,9 @@ class SaoBase:
req_data = req_struct.parse(req)
user_id = req_data.user_id
with open('titles/sao/data/RewardTable.csv', 'r') as f:
keys_unanalyzed = next(f).strip().split(',')
data_unanalyzed = list(DictReader(f, fieldnames=keys_unanalyzed))
end_session_data = self.game_data.item.get_end_session(user_id)
randomized_unanalyzed_id = choice(data_unanalyzed)
heroList = self.game_data.static.get_hero_id(randomized_unanalyzed_id['CommonRewardId'])
i = 0
# Create a loop to check if the id is a hero or else try 15 times before closing the loop and sending a dummy hero
while not heroList:
if i == 15:
# Return the dummy hero but not save it
resp = SaoEpisodePlayEndUnanalyzedLogFixedResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1, 102000070)
return resp.make()
i += 1
randomized_unanalyzed_id = choice(data_unanalyzed)
heroList = self.game_data.static.get_hero_id(randomized_unanalyzed_id['CommonRewardId'])
hero_data = self.game_data.item.get_hero_log(user_id, randomized_unanalyzed_id['CommonRewardId'])
# Avoid having a duplicated card and cause an overwrite
if not hero_data:
self.game_data.item.put_hero_log(user_id, randomized_unanalyzed_id['CommonRewardId'], 1, 0, 101000016, 0, 30086, 1001, 1002, 0, 0)
resp = SaoEpisodePlayEndUnanalyzedLogFixedResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1, randomized_unanalyzed_id['CommonRewardId'])
resp = SaoEpisodePlayEndUnanalyzedLogFixedResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1, end_session_data[4])
return resp.make()
def handle_c91a(self, request: Any) -> bytes: # handler is identical to the episode

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ from datetime import datetime
from construct import *
import sys
import csv
from csv import *
class SaoBaseRequest:
def __init__(self, data: bytes) -> None:
@ -1661,44 +1662,78 @@ class SaoEpisodePlayEndUnanalyzedLogFixedRequest(SaoBaseRequest):
super().__init__(data)
class SaoEpisodePlayEndUnanalyzedLogFixedResponse(SaoBaseResponse):
def __init__(self, cmd, randomized_unanalyzed_id) -> None:
def __init__(self, cmd, end_session_data) -> None:
super().__init__(cmd)
self.result = 1
self.play_end_unanalyzed_log_reward_data_list_size = 1 # Number of arrays
self.unanalyzed_log_grade_id = 3 # RewardTable.csv
self.common_reward_data_size = 1
self.unanalyzed_log_grade_id = []
self.common_reward_type_1 = 1
self.common_reward_id_1 = int(randomized_unanalyzed_id)
self.common_reward_num_1 = 1
self.common_reward_type = []
self.common_reward_id = []
self.common_reward_num = 1
for x in range(len(end_session_data)):
self.common_reward_id.append(end_session_data[x])
with open('titles/sao/data/RewardTable.csv', 'r') as f:
keys_unanalyzed = next(f).strip().split(',')
data_unanalyzed = list(DictReader(f, fieldnames=keys_unanalyzed))
for i in range(len(data_unanalyzed)):
if int(data_unanalyzed[i]["CommonRewardId"]) == int(end_session_data[x]):
self.unanalyzed_log_grade_id.append(int(data_unanalyzed[i]["UnanalyzedLogGradeId"]))
self.common_reward_type.append(int(data_unanalyzed[i]["CommonRewardType"]))
break
self.unanalyzed_log_grade_id = list(map(int,self.unanalyzed_log_grade_id)) #int
self.common_reward_type = list(map(int,self.common_reward_type)) #int
self.common_reward_id = list(map(int,self.common_reward_id)) #int
def make(self) -> bytes:
#new stuff
common_reward_data_struct = Struct(
"common_reward_type" / Int16ub,
"common_reward_id" / Int32ub,
"common_reward_num" / Int32ub,
)
play_end_unanalyzed_log_reward_data_list_struct = Struct(
"unanalyzed_log_grade_id" / Int32ub,
"common_reward_data_size" / Rebuild(Int32ub, len_(this.common_reward_data)), # big endian
"common_reward_data" / Array(this.common_reward_data_size, common_reward_data_struct),
)
# create a resp struct
resp_struct = Struct(
"result" / Int8ul, # result is either 0 or 1
"play_end_unanalyzed_log_reward_data_list_size" / Int32ub, # big endian
"unanalyzed_log_grade_id" / Int32ub,
"common_reward_data_size" / Int32ub,
"common_reward_type_1" / Int16ub,
"common_reward_id_1" / Int32ub,
"common_reward_num_1" / Int32ub,
"play_end_unanalyzed_log_reward_data_list_size" / Rebuild(Int32ub, len_(this.play_end_unanalyzed_log_reward_data_list)), # big endian
"play_end_unanalyzed_log_reward_data_list" / Array(this.play_end_unanalyzed_log_reward_data_list_size, play_end_unanalyzed_log_reward_data_list_struct),
)
resp_data = resp_struct.build(dict(
resp_data = resp_struct.parse(resp_struct.build(dict(
result=self.result,
play_end_unanalyzed_log_reward_data_list_size=self.play_end_unanalyzed_log_reward_data_list_size,
play_end_unanalyzed_log_reward_data_list_size=0,
play_end_unanalyzed_log_reward_data_list=[],
)))
unanalyzed_log_grade_id=self.unanalyzed_log_grade_id,
common_reward_data_size=self.common_reward_data_size,
for i in range(len(self.common_reward_id)):
reward_resp_data = dict(
unanalyzed_log_grade_id=self.unanalyzed_log_grade_id[i],
common_reward_data_size=0,
common_reward_data=[],
)
common_reward_type_1=self.common_reward_type_1,
common_reward_id_1=self.common_reward_id_1,
common_reward_num_1=self.common_reward_num_1,
reward_resp_data["common_reward_data"].append(dict(
common_reward_type=self.common_reward_type[i],
common_reward_id=self.common_reward_id[i],
common_reward_num=self.common_reward_num,
))
resp_data.play_end_unanalyzed_log_reward_data_list.append(reward_resp_data)
# finally, rebuild the resp_data
resp_data = resp_struct.build(resp_data)
self.length = len(resp_data)
return super().make() + resp_data
@ -1733,8 +1768,8 @@ class SaoGetQuestSceneUserDataListResponse(SaoBaseResponse):
self.concurrent_destroying_num.append(quest_data[i][7])
# quest_scene_ex_bonus_user_data_list
self.achievement_flag = [[1, 1, 1],[1, 1, 1]]
self.ex_bonus_table_id = [[1, 2, 3],[4, 5, 6]]
self.achievement_flag = [1,1,1]
self.ex_bonus_table_id = [1,2,3]
self.quest_type = list(map(int,self.quest_type)) #int
@ -1748,8 +1783,8 @@ class SaoGetQuestSceneUserDataListResponse(SaoBaseResponse):
def make(self) -> bytes:
#new stuff
quest_scene_ex_bonus_user_data_list_struct = Struct(
"achievement_flag" / Int32ub, # big endian
"ex_bonus_table_id" / Int32ub, # big endian
"achievement_flag" / Int8ul, # result is either 0 or 1
)
quest_scene_best_score_user_data_struct = Struct(
@ -1803,7 +1838,6 @@ class SaoGetQuestSceneUserDataListResponse(SaoBaseResponse):
concurrent_destroying_num=self.concurrent_destroying_num[i],
))
resp_data.quest_scene_user_data_list.append(quest_resp_data)
# finally, rebuild the resp_data

View File

@ -112,5 +112,4 @@ class SaoServlet(resource.Resource):
self.logger.info(f"Handler {req_url} - {sao_request[:4]} request")
self.logger.debug(f"Request: {request.content.getvalue().hex()}")
self.logger.debug(f"Response: {handler(sao_request).hex()}")
return handler(sao_request)

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
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON
from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select, update, delete
from sqlalchemy.engine import Row
@ -122,6 +122,22 @@ sessions = Table(
mysql_charset="utf8mb4",
)
end_sessions = Table(
"sao_end_sessions",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
Column("quest_id", Integer, nullable=False),
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",
)
class SaoItemData(BaseData):
def create_session(self, user_id: int, user_party_team_id: int, episode_id: int, play_mode: int, quest_drop_boost_apply_flag: int) -> Optional[int]:
sql = insert(sessions).values(
@ -140,6 +156,22 @@ class SaoItemData(BaseData):
return None
return result.lastrowid
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(
user=user_id,
quest_id=quest_id,
play_result_flag=play_result_flag,
reward_data=reward_data,
)
conflict = sql.on_duplicate_key_update(user=user_id)
result = 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
def put_item(self, user_id: int, item_id: int) -> Optional[int]:
sql = insert(item_data).values(
user=user_id,
@ -418,6 +450,22 @@ class SaoItemData(BaseData):
return None
return result.fetchone()
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.asc()
)
result = self.execute(sql)
if result is None:
return None
return result.fetchone()
def remove_hero_log(self, user_id: int, user_hero_log_id: int) -> None:
sql = hero_log_data.delete(
and_(