forked from Hay1tsme/artemis
2626 lines
133 KiB
Python
2626 lines
133 KiB
Python
import logging
|
|
from csv import *
|
|
from random import choice, randint
|
|
from typing import Dict, List
|
|
from os import path
|
|
import re
|
|
from sqlalchemy.engine import Row
|
|
|
|
from core import CoreConfig
|
|
from .config import SaoConfig
|
|
from .database import SaoData
|
|
from .const import GameconnectCmd, RewardType, ExBonusCondition, QuestType
|
|
from titles.sao.handlers.base import *
|
|
import csv
|
|
|
|
class SaoBase:
|
|
DATA_LIST = {}
|
|
def __init__(self, core_cfg: CoreConfig, game_cfg: SaoConfig) -> None:
|
|
self.core_cfg = core_cfg
|
|
self.game_cfg = game_cfg
|
|
self.data = SaoData(core_cfg)
|
|
self.logger = logging.getLogger("sao")
|
|
|
|
def load_data_csv(self, file: str, version: int = 1, base_ver: int = 1) -> List[Dict]:
|
|
if base_ver > version:
|
|
self.logger.warning(f"load_data_csv: Cannot use base version higher then requested version ({base_ver} > {version})")
|
|
return []
|
|
|
|
for x in range(version, base_ver - 1, -1):
|
|
ret = self.DATA_LIST.get(x, {}).get(file, [])
|
|
if ret:
|
|
break
|
|
|
|
if not ret and base_ver != 1:
|
|
ret = self.DATA_LIST.get(1, {}).get(file, [])
|
|
|
|
if ret:
|
|
return ret
|
|
|
|
found = False
|
|
for x in range(version, base_ver - 1, -1):
|
|
fname = f"./titles/sao/data/{x}/{file}.csv"
|
|
if path.exists(fname):
|
|
found_ver = x
|
|
found = True
|
|
break
|
|
|
|
if not found and base_ver != 1: # v1 will always be fallback if it isn't already
|
|
fname = f"./titles/sao/data/1/{file}.csv"
|
|
if path.exists(fname):
|
|
found_ver = 1
|
|
found = True
|
|
|
|
if not found:
|
|
self.logger.warning(f"load_data_csv: Failed to find v{version} csv file {fname}")
|
|
return []
|
|
|
|
ret = []
|
|
with open(fname, "r", encoding="utf8") as f:
|
|
data = csv.DictReader(f, delimiter=',')
|
|
for x in data:
|
|
newdict = {}
|
|
for k, v in x.items():
|
|
newkey = k
|
|
if k.startswith("// "):
|
|
newkey = k.replace("// ", "")
|
|
|
|
if v.isdigit():
|
|
newdict[newkey] = int(v)
|
|
elif v.lower() == "true":
|
|
newdict[newkey] = True
|
|
elif v.lower() == "false":
|
|
newdict[newkey] = False
|
|
elif re.match(r"^\d\d\d\d\/\d\d\/\d\d \d{1,2}:\d\d:\d\d$", v):
|
|
newdict[newkey] = datetime.strptime(v, "%Y/%m/%d %H:%M:%S")
|
|
elif re.match(r"^\d\d\d\d\/\d\d\/\d\d$", v):
|
|
newdict[newkey] = datetime.strptime(v, "%Y/%m/%d")
|
|
else:
|
|
newdict[newkey] = v
|
|
ret.append(newdict)
|
|
|
|
# Cache the CSV data in memory
|
|
if found_ver not in self.DATA_LIST:
|
|
self.DATA_LIST[found_ver] = {}
|
|
self.DATA_LIST[found_ver][file] = ret
|
|
|
|
return ret
|
|
|
|
async def add_reward(self, reward: Dict, user_id: int):
|
|
reward_type = int(reward.get("CommonRewardType", "0"))
|
|
if reward_type == RewardType.HeroLog:
|
|
reward_hero_data = await self.data.static.get_hero_by_id(reward['CommonRewardId'])
|
|
now_have_skills = await self.hero_default_skills(reward_hero_data['SkillTableSubId'])
|
|
|
|
new_hero_id = await self.data.item.put_hero_log(
|
|
user_id,
|
|
reward['CommonRewardId'],
|
|
1,
|
|
0,
|
|
None,
|
|
None,
|
|
now_have_skills[0],
|
|
now_have_skills[1],
|
|
now_have_skills[2],
|
|
now_have_skills[3],
|
|
now_have_skills[4],
|
|
)
|
|
self.logger.info(f"Rewarded user {user_id} with hero {reward['CommonRewardId']} (ID {new_hero_id})")
|
|
# TODO: add properties
|
|
|
|
elif reward_type == RewardType.Equipment:
|
|
new_equip_id = await self.data.item.put_equipment(user_id, reward['CommonRewardId'])
|
|
self.logger.info(f"Rewarded user {user_id} with equipment {reward['CommonRewardId']} (ID {new_equip_id})")
|
|
|
|
elif reward_type == RewardType.Item:
|
|
new_item_id = await self.data.item.put_item(user_id, reward['CommonRewardId'])
|
|
self.logger.info(f"Rewarded user {user_id} with item {reward['CommonRewardId']} (ID {new_item_id})")
|
|
|
|
elif reward_type == RewardType.Col:
|
|
col_num = int(reward['CommonRewardNum'])
|
|
self.logger.info(f"Rewarded user {user_id} with {col_num} Col")
|
|
await self.data.profile.add_col(user_id, col_num)
|
|
|
|
elif reward_type == RewardType.VP:
|
|
vp_num = int(reward['CommonRewardNum'])
|
|
self.logger.info(f"Rewarded user {user_id} with {vp_num} VP")
|
|
await self.data.profile.add_vp(user_id, vp_num)
|
|
|
|
elif reward_type == RewardType.YuiMadal:
|
|
medal_num = int(reward['CommonRewardNum'])
|
|
self.logger.info(f"Rewarded user {user_id} with {medal_num} Yui Medals")
|
|
await self.data.profile.add_yui_medals(user_id, medal_num)
|
|
|
|
else:
|
|
self.logger.warn(f"User {user_id} Unhandled reward type {reward_type} -> {reward}")
|
|
|
|
async def hero_default_skills(self, skill_table_id: int) -> List[int]:
|
|
skills = await self.data.static.get_skill_table_by_subid(skill_table_id)
|
|
if not skills:
|
|
self.logger.error(f"Failed to find skill table {skill_table_id}! Please run the reader")
|
|
return [None, None, None, None, None]
|
|
|
|
default_skills = []
|
|
now_have_skills = [None, None, None, None, None]
|
|
for skill in skills:
|
|
if skill['LevelObtained'] == 1 and skill['AwakeningId'] == 0:
|
|
default_skills.append(skill['SkillId'])
|
|
|
|
for skill in default_skills:
|
|
skill_info = await self.data.static.get_skill_by_id(skill)
|
|
skill_slot = skill_info['Level'] - 1
|
|
if now_have_skills[skill_slot] is not None:
|
|
now_have_skills[skill]
|
|
|
|
return now_have_skills
|
|
|
|
async def handle_noop(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
return SaoNoopResponse(header.cmd + 1).make()
|
|
|
|
async def handle_c000(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#ticket/ticket
|
|
req = SaoTicketRequest(header, request)
|
|
return SaoTicketResponse().make()
|
|
|
|
async def handle_c100(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#common/get_app_versions
|
|
resp = SaoGetAppVersionsResponse()
|
|
resp.data_list.append(AppVersionData.from_args(self.game_cfg.server.game_version, datetime.fromtimestamp(0)))
|
|
return resp.make()
|
|
|
|
async def handle_c102(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#common/master_data_version_check
|
|
req = SaoMasterDataVersionCheckRequest(header, request)
|
|
self.logger.info(f"Cab at {src_ip} checked in with master data v{req.current_data_version}")
|
|
return SaoMasterDataVersionCheckResponse(self.game_cfg.server.data_version, req.current_data_version).make()
|
|
|
|
async def handle_c104(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#common/login
|
|
req = SaoLoginRequest(header, request)
|
|
|
|
user_id = await self.data.card.get_user_id_from_card( req.access_code )
|
|
if not user_id:
|
|
card = await self.data.card.get_card_by_idm(req.chip_id[:16])
|
|
if card:
|
|
user_id = card['user']
|
|
card_id = card['id']
|
|
await self.data.card.set_access_code_by_access_code(card['access_code'], req.access_code)
|
|
|
|
else:
|
|
user_id = await self.data.user.create_user() #works
|
|
card_id = await self.data.card.create_card(user_id, req.access_code)
|
|
|
|
if card_id is None:
|
|
user_id = -1
|
|
self.logger.error("Failed to register card!")
|
|
|
|
self.logger.info(f"Registered card {req.access_code} to user {user_id} from {req.serial_no}")
|
|
|
|
if req.access_code.startswith("5"):
|
|
await self.data.card.set_idm_by_access_code(req.access_code, req.chip_id[:16])
|
|
elif (req.access_code.startswith("010") or req.access_code.startswith("3")) and int(req.chip_id[:8], 16) != 0x04030201:
|
|
await self.data.card.set_chip_id_by_access_code(req.access_code, int(req.chip_id[:8], 16))
|
|
|
|
profile_data = await self.data.profile.get_profile(user_id)
|
|
|
|
if not profile_data:
|
|
profile_id = await self.data.profile.create_profile(user_id)
|
|
if profile_id:
|
|
equip1 = await self.data.item.put_equipment(user_id, 101000000)
|
|
equip2 = await self.data.item.put_equipment(user_id, 102000000)
|
|
equip3 = await self.data.item.put_equipment(user_id, 109000000)
|
|
if not equip1 or not equip2 or not equip3:
|
|
self.logger.error(f"Failed to create profile for user {user_id} from {req.serial_no} (could not add equipment)")
|
|
return SaoNoopResponse(GameconnectCmd.LOGIN_RESPONSE).make()
|
|
|
|
hero1 = await self.data.item.put_hero_log(user_id, 101000010, 1, 0, equip1, None, 1002, 1003, 1014, None, None)
|
|
hero2 = await self.data.item.put_hero_log(user_id, 102000010, 1, 0, equip2, None, 3001, 3002, 3004, None, None)
|
|
hero3 = await self.data.item.put_hero_log(user_id, 105000010, 1, 0, equip3, None, 10005, 10002, 10004, None, None)
|
|
if not hero1 or not hero2 or not hero3:
|
|
self.logger.error(f"Failed to create profile for user {user_id} from {req.serial_no} (could not add heros)")
|
|
return SaoNoopResponse(GameconnectCmd.LOGIN_RESPONSE).make()
|
|
|
|
await self.data.item.put_hero_party(user_id, 0, hero1, hero2, hero3)
|
|
self.logger.info(f"Create profile {profile_id} for user {user_id} from {req.serial_no}")
|
|
else:
|
|
self.logger.error(f"Failed to create profile for user {user_id} from {req.serial_no}")
|
|
return SaoNoopResponse(GameconnectCmd.LOGIN_RESPONSE).make()
|
|
resp = SaoLoginResponse(user_id, True, False)
|
|
|
|
else:
|
|
is_login_today = False
|
|
|
|
if profile_data['last_login_date']:
|
|
last_login_time = int(profile_data["last_login_date"].timestamp())
|
|
midnight_today_ts = int(
|
|
datetime.now()
|
|
.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
.timestamp()
|
|
)
|
|
|
|
if last_login_time > midnight_today_ts:
|
|
is_login_today = True
|
|
|
|
if not is_login_today:
|
|
await self.data.profile.add_vp(user_id, 100)
|
|
|
|
resp = SaoLoginResponse(user_id, profile_data['login_ct'] < 1, is_login_today)
|
|
|
|
await self.data.profile.user_login(user_id)
|
|
return resp.make()
|
|
|
|
async def handle_c106(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/logout
|
|
req = SaoLogoutRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} Logout from {'game' if req.cabinet_type == 0 else 'terminal'} @ {src_ip} with {req.remaining_ticket_num} tickets remaining")
|
|
return SaoNoopResponse(GameconnectCmd.LOGOUT_RESPONSE).make()
|
|
|
|
async def handle_c108(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/logout_ticket_unpurchased
|
|
req = SaoLogoutTicketUnpurchasedRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} Logout from {'game' if req.cabinet_type == 0 else 'terminal'} @ {src_ip} without buying a ticket")
|
|
return SaoNoopResponse(GameconnectCmd.LOGOUT_TICKET_UNPURCHASED_RESPONSE).make()
|
|
|
|
async def handle_c10a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/paying_play_start
|
|
req = SaoPayingPlayStartRequest(header, request)
|
|
self.logger.info(f"User {req.paying_user_id} started paying session @ {req.store_name} ({src_ip}) on cab {req.serial_no}")
|
|
resp = SaoPayingPlayStartResponse()
|
|
# TODO: session management
|
|
return resp.make()
|
|
|
|
async def handle_c10c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/paying_play_end
|
|
req = SaoPayingPlayEndRequest(header, request)
|
|
self.logger.info(f"User {req.paying_user_id} ended paying session {req.paying_session_id} @ {req.store_name} ({src_ip}) on cab {req.serial_no} after {req.played_amount} {req.played_type} type games")
|
|
return SaoNoopResponse(GameconnectCmd.PAYING_PLAY_END_RESPONSE).make()
|
|
|
|
async def handle_c10e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/purchase_ticket
|
|
req = SaoPurchaseTicketRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} pruchased {req.purchase_num} tickets (ID {req.ticket_id}) @ {src_ip} with discout type {req.discount_type}")
|
|
return SaoNoopResponse(GameconnectCmd.PURCHASE_TICKET_RESPONSE).make()
|
|
|
|
async def handle_c110(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/consume_ticket
|
|
req = SaoConsumeTicketRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} consumed {req.consume_num} tickets (ID {req.ticket_id}) @ {src_ip} with discout type {req.discount_type} on {req.act_type}")
|
|
return SaoNoopResponse(GameconnectCmd.CONSUME_TICKET_RESPONSE).make()
|
|
|
|
async def handle_c112(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/add_credit
|
|
req = SaoAddCreditRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} added {req.add_num} credits to a {'game' if req.cabinet_type == 0 else 'terminal'} @ {src_ip}")
|
|
return SaoNoopResponse(GameconnectCmd.ADD_CREDIT_RESPONSE).make()
|
|
|
|
async def handle_c114(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/consume_credit
|
|
req = SaoConsumeCreditRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} consumed {req.consume_num} credits on a {'game' if req.cabinet_type == 0 else 'terminal'} @ {req.store_id} ({src_ip}) on {req.act_type}")
|
|
return SaoNoopResponse(GameconnectCmd.CONSUME_CREDIT_RESPONSE).make()
|
|
|
|
async def handle_c116(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/purchase_ticket_guest
|
|
req = SaoPurchaseTicketGuestRequest(header, request)
|
|
self.logger.info(f"Guest purchased {req.purchase_num} tickets on a {'game' if req.cabinet_type == 0 else 'terminal'} @ {req.store_id} ({src_ip} | SN {req.serial_no})")
|
|
return SaoNoopResponse(GameconnectCmd.PURCHASE_TICKET_GUEST_RESPONSE).make()
|
|
|
|
async def handle_c118(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/consume_ticket_guest
|
|
req = SaoConsumeTicketGuestRequest(header, request)
|
|
self.logger.info(f"Guest consumed {req.consume_num} tickets @ {req.store_id} ({src_ip} | SN {req.serial_no}) with discout type {req.discount_type} on {req.act_type}")
|
|
return SaoNoopResponse(GameconnectCmd.CONSUME_TICKET_GUEST_RESPONSE).make()
|
|
|
|
async def handle_c11a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/add_credit_guest
|
|
req = SaoAddCreditGuestRequest(header, request)
|
|
self.logger.info(f"Guest added {req.add_num} credits to a {'game' if req.cabinet_type == 0 else 'terminal'} @ {req.store_id} ({src_ip} | SN {req.serial_no})")
|
|
return SaoNoopResponse(GameconnectCmd.ADD_CREDIT_GUEST_RESPONSE).make()
|
|
|
|
async def handle_c11c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/consume_credit_guest
|
|
req = SaoConsumeCreditGuestRequest(header, request)
|
|
self.logger.info(f"Guest consumed {req.consume_num} credits on a {'game' if req.cab_type == 0 else 'terminal'} @ {req.shop_id} ({src_ip} | SN {req.serial_num}) on {req.act_type}")
|
|
return SaoNoopResponse(GameconnectCmd.CONSUME_CREDIT_GUEST_RESPONSE).make()
|
|
|
|
async def handle_c11e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#common/get_auth_card_data
|
|
req = SaoGetAuthCardDataRequest(header, request)
|
|
|
|
#Check authentication
|
|
card = await self.data.card.get_card_by_access_code( req.access_code )
|
|
|
|
if not card:
|
|
card = await self.data.card.get_card_by_idm(req.chip_id[:16])
|
|
if not card:
|
|
self.logger.info(f"Unregistered card {req.access_code} authenticated from {req.serial_no}")
|
|
return SaoGetAuthCardDataResponse("NEW PLAYER", 0).make()
|
|
|
|
await self.data.card.set_access_code_by_access_code(card['access_code'], req.access_code)
|
|
|
|
else:
|
|
user_id = card['user']
|
|
card_id = card['id']
|
|
|
|
if req.access_code.startswith("5") and not card['idm']:
|
|
await self.data.card.set_idm_by_access_code(card_id, req.chip_id[:16])
|
|
elif (req.access_code.startswith("010") or req.access_code.startswith("3")) and not card['chip_id'] and int(req.chip_id[:8], 16) != 0x04030201:
|
|
await self.data.card.set_chip_id_by_access_code(card_id, int(req.chip_id[:8], 16))
|
|
|
|
self.logger.info(f"User Authenticated from {req.serial_no}: { req.access_code } | { user_id }")
|
|
|
|
#Grab values from profile
|
|
profile_data = await self.data.profile.get_profile(user_id)
|
|
|
|
if not profile_data:
|
|
self.logger.info(f"Unregistered user {user_id} with card {req.access_code} authenticated from {req.serial_no}")
|
|
return SaoGetAuthCardDataResponse("NEW PLAYER", user_id).make()
|
|
|
|
return SaoGetAuthCardDataResponse(profile_data['nick_name'], user_id).make()
|
|
|
|
async def handle_c120(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/get_access_code_by_keitai
|
|
req = SaoGetAccessCodeByKeitaiRequest(header, request)
|
|
cid = req.chip_id
|
|
idm = cid[:16]
|
|
pmm = cid[16:]
|
|
card = await self.data.card.get_card_by_idm(idm)
|
|
|
|
# If we don't have that card saved locally, check aimedb
|
|
if not card:
|
|
# Validate that we're talking to a phone
|
|
if not int(pmm[2:4], 16) in self.data.card.moble_os_codes:
|
|
self.logger.warn(f"{req.serial_no} looked up non-moble chip ID {cid}!")
|
|
return SaoGetAccessCodeByKeitaiResponse("").make()
|
|
|
|
# TODO: Actual felica moble registration
|
|
return SaoGetAccessCodeByKeitaiResponse("").make()
|
|
#ac = await self.data.card.register_felica_moble_ac(idm, pmm)
|
|
# if we didn't get an access code, fail hard
|
|
if not ac:
|
|
self.logger.warn(f"Failed to register access code for chip ID {cid} requested by {req.serial_no}")
|
|
return SaoGetAccessCodeByKeitaiResponse("").make()
|
|
|
|
self.logger.info(f"Successfully registered moble felica access code {ac} for chip ID {cid} requested by {req.serial_no}")
|
|
|
|
uid = await self.data.user.create_user()
|
|
if not uid:
|
|
self.logger.error(f"Failed to create user for chip ID {cid} (access code {ac}) @ LoadAccessCode request from {req.serial_no}")
|
|
return SaoGetAccessCodeByKeitaiResponse("").make()
|
|
|
|
cardid = await self.data.card.create_card(uid, ac)
|
|
if not cardid:
|
|
self.logger.error(f"Failed to create card for user {uid} with chip ID {cid} (access code {ac}) @ LoadAccessCode request from {req.serial_no}")
|
|
await self.data.user.delete_user(uid)
|
|
return SaoGetAccessCodeByKeitaiResponse("").make()
|
|
|
|
self.logger.info(f"Moble Felica access code lookup for {cid} -> {ac} (user {uid}) requested by {req.serial_no}")
|
|
|
|
else:
|
|
ac = card['access_code']
|
|
uid = card['user']
|
|
self.logger.info(f"Moble Felica access code for {cid} -> {ac} (user {uid}) requested by {req.serial_no}")
|
|
|
|
return SaoGetAccessCodeByKeitaiResponse(ac).make()
|
|
|
|
async def handle_c122(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#common/get_maintenance_info
|
|
resp = SaoGetMaintenanceInfoResponse()
|
|
return resp.make()
|
|
|
|
async def handle_c124(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#common/get_resource_path_info
|
|
resp = SaoGetResourcePathInfoResponse(f"https://{self.core_cfg.server.hostname}/saoresource/")
|
|
return resp.make()
|
|
|
|
async def handle_c126(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/validation_error_notification
|
|
req = SaoValidationErrorNotificationRequest(header, request)
|
|
self.logger.warn(f"User {req.user_id} on {'game' if req.cabinet_type == 0 else 'terminal'} {req.serial_no} @ {req.store_name} ({src_ip} | Place ID {req.place_id}) " \
|
|
+ f"Validation error: {req.send_protocol_name} || {req.send_data_to_fraud_value} || {req.send_data_to_modification_value}")
|
|
return SaoNoopResponse(GameconnectCmd.VALIDATION_ERROR_NOTIFICATION_RESPONSE).make()
|
|
|
|
async def handle_c128(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/power_cutting_return_notification
|
|
req = SaoPowerCuttingReturnNotification(header, request)
|
|
self.logger.warn(f"User {req.user_id} on {'game' if req.cabinet_type == 0 else 'terminal'} {req.serial_no} @ {req.store_name} ({src_ip} | Place ID {req.place_id}) " \
|
|
+ f"Power outage return: Act Type {req.last_act_type} || {req.remaining_ticket_num} Remaining Tickets || {req.remaining_credit_num} Remaining Credits")
|
|
return SaoNoopResponse(GameconnectCmd.POWER_CUTTING_RETURN_NOTIFICATION_RESPONSE).make()
|
|
|
|
async def handle_c12a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#common/give_free_ticket
|
|
req = SaoGiveFreeTicketRequest(header, request)
|
|
self.logger.info(f"Give {req.give_num} free tickets (id {req.ticket_id}) to user {req.user_id}")
|
|
resp = SaoNoopResponse(GameconnectCmd.GIVE_FREE_TICKET_RESPONSE)
|
|
return resp.make()
|
|
|
|
async def handle_c12c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# common/matching_error_notification
|
|
req = SaoMatchingErrorNotificationRequest(header, request)
|
|
self.logger.warn(f"{'game' if req.cabinet_type == 0 else 'terminal'} {req.serial_no} @ {req.store_name} ({src_ip} | Place ID {req.place_id}) " \
|
|
+ f"Matching error: {req.matching_error_data_list[0]}")
|
|
return SaoNoopResponse(GameconnectCmd.MATCHING_ERROR_NOTIFICATION_RESPONSE).make()
|
|
|
|
async def handle_c12e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#common/ac_cabinet_boot_notification
|
|
req = SaoCommonAcCabinetBootNotificationRequest(header, request)
|
|
|
|
if req.current_version_app_id < self.game_cfg.server.game_version:
|
|
self.logger.info(f"!!OUTDATED!! {'Game' if req.cabinet_type == 0 else 'Terminal'} {req.serial_no} Booted v{req.current_version_app_id} (Master data v{req.current_master_data_version}): {req.store_name} ({src_ip} | Place/Shop ID {req.place_id}/{req.store_id})")
|
|
|
|
if req.current_version_app_id > self.game_cfg.server.game_version:
|
|
self.logger.info(f"!!TOO NEW!! {'Game' if req.cabinet_type == 0 else 'Terminal'} {req.serial_no} Booted v{req.current_version_app_id} (Master data v{req.current_master_data_version}): {req.store_name} ({src_ip} | Place/Shop ID {req.place_id}/{req.store_id})")
|
|
|
|
self.logger.info(f"{'Game' if req.cabinet_type == 0 else 'Terminal'} {req.serial_no} Booted v{req.current_version_app_id} (Master data v{req.current_master_data_version}): {req.store_name} ({src_ip} | Place/Shop ID {req.place_id}/{req.store_id})")
|
|
resp = SaoNoopResponse(GameconnectCmd.AC_CABINET_BOOT_NOTIFICATION_RESPONSE)
|
|
return resp.make()
|
|
|
|
async def handle_c200(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# tutorial/first_tutorial_end
|
|
req = SaoGenericUserTicketRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} (ticket {req.ticket_id}) finished first tutorial")
|
|
return SaoNoopResponse(GameconnectCmd.FIRST_TUTORIAL_END_RESPONSE).make()
|
|
|
|
async def handle_c202(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# tutorial/various_tutorial_end
|
|
req = SaoVariousTutorialEndRequest(header, request)
|
|
await self.data.profile.add_tutorial_byte(int(req.user_id), req.tutorial_type)
|
|
return SaoNoopResponse(GameconnectCmd.VARIOUS_TUTORIAL_END_RESPONSE).make()
|
|
|
|
async def handle_c204(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# tutorial/get_various_tutorial_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
tuts = await self.data.profile.get_tutorial_bytes(int(req.user_id))
|
|
resp = SaoGetVariousTutorialDataListResponse()
|
|
if tuts:
|
|
for t in tuts:
|
|
resp.end_tutorial_type_list.append(t['tutorial_byte'])
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c300(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# card/discharge_profile_card
|
|
req = SaoDischargeProfileCardRequest(header, request)
|
|
# Real cards seem to start with 10-17 as the first 2 digits, so we'll anchor ours with 2 to ensure no overlap
|
|
sn = f"2{str(randint(1, 999999999999999999)).zfill(18)}"
|
|
while await self.data.profile.get_hero_card(sn):
|
|
sn = f"2{str(randint(1, 999999999999999999)).zfill(18)}"
|
|
resp = SaoDischargeProfileCardResponse(sn)
|
|
|
|
db_hero = await self.data.item.get_hero_log(req.user_id, req.hero_log_user_hero_log_id)
|
|
if not db_hero:
|
|
hero_statc = await self.data.static.get_hero_by_id(db_hero['hero_log_id'])
|
|
if not hero_statc:
|
|
self.logger.error(f"Failed to find hero log {db_hero['hero_log_id']}! Please run the reader")
|
|
resp.header.error_type = ProtocolErrorNum.RESOURCE_CARD_ERR1
|
|
return resp.make()
|
|
|
|
now_have_skills = await self.hero_default_skills(hero_statc['SkillTableSubId'])
|
|
|
|
db_hero_id = await self.data.item.put_hero_log(
|
|
req.user_id,
|
|
db_hero['hero_log_id'],
|
|
1,
|
|
0,
|
|
None,
|
|
None,
|
|
now_have_skills[0],
|
|
now_have_skills[1],
|
|
now_have_skills[2],
|
|
now_have_skills[3],
|
|
now_have_skills[4]
|
|
)
|
|
if not db_hero_id:
|
|
self.logger.error(f"Failed to give user {req.user_id} hero {db_hero['hero_log_id']}!")
|
|
resp.header.error_type = ProtocolErrorNum.RESOURCE_CARD_ERR6
|
|
return resp.make()
|
|
|
|
else:
|
|
db_hero_id = db_hero['id']
|
|
|
|
await self.data.profile.put_hero_card(req.user_id, sn, db_hero_id, req.holographic_flag)
|
|
|
|
self.logger.info(f"User {req.user_id} printed {'holo ' if req.holographic_flag == 1 else ''}profile card {req.hero_log_user_hero_log_id} {req.execute_print_type}, code {sn}")
|
|
return resp.make()
|
|
|
|
async def handle_c302(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# card/discharge_resource_card
|
|
req = SaoDischargeResourceCardRequest(header, request)
|
|
|
|
for x in req.common_reward_user_data:
|
|
sn = f"2{str(randint(1, 999999999999999999)).zfill(18)}"
|
|
self.logger.info(f"User {req.user_id} printed {'holo ' if req.holographic_flag == 1 else ''}resource card {x.user_common_reward_id} {req.execute_print_type}, code {sn}")
|
|
await self.data.profile.put_resource_card(req.user_id, sn, x.common_reward_type, x.user_common_reward_id, req.holographic_flag)
|
|
|
|
return SaoDischargeProfileCardResponse(sn).make()
|
|
|
|
async def handle_c304(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# card/discharge_resource_card_complete
|
|
req = SaoDischargeResourceCardCompleteRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} finished printing resource card {req.resource_card_code}")
|
|
return SaoNoopResponse(GameconnectCmd.DISCHARGE_RESOURCE_CARD_COMPLETE_RESPONSE).make()
|
|
|
|
async def handle_c306(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#card/scan_qr_quest_profile_card
|
|
req = SaoScanQrQuestProfileCardRequest(header, request)
|
|
resp = SaoScanQrQuestProfileCardResponse()
|
|
|
|
card = await self.data.profile.get_hero_card(req.profile_card_code)
|
|
if not card:
|
|
self.logger.warn(f"User {req.user_id} scanned unregistered QR code {req.profile_card_code}")
|
|
return resp.make()
|
|
|
|
hero = await self.data.item.get_hero_log_by_id(card['user_hero_id'])
|
|
if not hero: # Shouldn't happen
|
|
self.logger.warn(f"User {req.user_id} scanned QR code {req.profile_card_code} but does not have hero entry {card['user_hero_id']}")
|
|
return resp.make()
|
|
|
|
hero_static_data = await self.data.static.get_hero_by_id(hero['hero_log_id'])
|
|
if not hero_static_data: # Shouldn't happen
|
|
self.logger.warn(f"No entry for hero {hero['hero_log_id']}, please run read.py")
|
|
return resp.make()
|
|
|
|
profile = await self.data.profile.get_profile(card['user'])
|
|
if not profile: # Shouldn't happen
|
|
self.logger.warn(f"No profile for user {card['user']}, something broke")
|
|
return resp.make()
|
|
|
|
self.logger.info(f"User {req.user_id} scanned QR code {req.profile_card_code}")
|
|
card_resp = ReadProfileCard.from_args(req.profile_card_code, profile['nick_name'])
|
|
card_resp.rank_num = profile['rank_num']
|
|
card_resp.setting_title_id = profile['setting_title_id']
|
|
card_resp.skill_id = hero['skill_slot1_skill_id']
|
|
card_resp.hero_log_hero_log_id = hero['hero_log_id']
|
|
card_resp.hero_log_log_level = hero['log_level']
|
|
#TODO: Awakening
|
|
#card_resp.hero_log_awakening_stage = hero['log_level']
|
|
|
|
resp.profile_card_data.append(card_resp)
|
|
return resp.make()
|
|
|
|
async def handle_c308(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# card/scan_qr_shop_resource_card
|
|
req = SaoScanQrShopResourceCardRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} scanned shop resource card {req.resource_card_code}")
|
|
resp = SaoNoopResponse(GameconnectCmd.SCAN_QR_SHOP_RESOURCE_CARD_RESPONSE)
|
|
# On official, resource cards have limited uses, but we don't track that currently (tho we should)
|
|
|
|
card = await self.data.profile.get_resource_card(req.resource_card_code) # TODO: use count
|
|
if not card:
|
|
self.logger.warn(f"No resource card with serial {req.resource_card_code} exists!")
|
|
resp.header.err_status = 4832 # Theres a few error codes but none seem to do anything?
|
|
# Also not sure if it should be this or result
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c30a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# card/scan_qr_quest_resource_card
|
|
req = SaoScanQrQuestResourceCardRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} scanned quest resource card {req.resource_card_code}")
|
|
|
|
card = await self.data.profile.get_resource_card(req.resource_card_code)
|
|
if not card:
|
|
resp = SaoScanQrQuestResourceCardResponse(card['common_reward_type'], card['common_reward_id'], card['holographic_flag'])
|
|
|
|
else:
|
|
self.logger.warn(f"No resource card with serial {req.resource_card_code} exists!")
|
|
resp = SaoScanQrQuestResourceCardResponse()
|
|
resp.header.err_status = 4832 # Theres a few error codes but none seem to do anything?
|
|
# Also not sure if it should be this or result
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c400(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#home/check_yui_medal_get_condition
|
|
req = SaoCheckYuiMedalGetConditionRequest(header, request)
|
|
profile = await self.data.profile.get_profile(req.user_id)
|
|
if profile['last_yui_medal_date']:
|
|
last_check_ts = int(profile['last_yui_medal_date'].timestamp())
|
|
day_ts = int(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).timestamp())
|
|
diff_ts = day_ts - last_check_ts
|
|
if diff_ts > 0:
|
|
num_days = diff_ts / 86400
|
|
else:
|
|
num_days = 0
|
|
else:
|
|
num_days = 1
|
|
|
|
if num_days > 1:
|
|
await self.data.profile.add_yui_medals(req.user_id)
|
|
|
|
await self.data.profile.update_yui_medal_date(req.user_id)
|
|
return SaoCheckYuiMedalGetConditionResponse(num_days, 1 if num_days > 1 else 0).make()
|
|
|
|
async def handle_c402(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#home/get_yui_medal_bonus_user_data
|
|
req = SaoGetYuiMedalBonusUserDataRequest(header, request)
|
|
resp = SaoGetYuiMedalBonusUserDataResponse() # TODO: Track yui login bonus
|
|
return resp.make()
|
|
|
|
async def handle_c404(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# home/check_comeback_event
|
|
req = SaoGenericUserTicketRequest(header, request)
|
|
resp = SaoCheckComebackEventResponse()
|
|
#resp.get_comeback_event_id_list += [1,2,3,4] # TODO: track comeback date
|
|
return resp.make()
|
|
|
|
async def handle_c406(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# home/change_my_store
|
|
req = SaoChangeMyStoreRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} changed My Store to {req.store_id}")
|
|
shop_id = int(req.store_id[3:], 16)
|
|
await self.data.profile.set_my_shop(req.user_id, shop_id)
|
|
return SaoNoopResponse(GameconnectCmd.CHANGE_MY_STORE_RESPONSE).make()
|
|
|
|
async def handle_c408(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# home/check_title_get_decision
|
|
req = SaoCheckTitleGetDecisionRequest(header, request)
|
|
resp = SaoCheckTitleGetDecisionResponse() # TODO: titles
|
|
return resp.make()
|
|
|
|
async def handle_c40a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# home/check_profile_card_used_reward
|
|
req = SaoCheckProfileCardUsedRewardRequest(header, request)
|
|
resp = SaoCheckProfileCardUsedRewardResponse() # TODO: check_profile_card_used_reward
|
|
return resp.make()
|
|
|
|
async def handle_c40c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# home/check_ac_login_bonus
|
|
req = SaoGenericUserTicketRequest(header, request)
|
|
resp = SaoCheckAcLoginBonusResponse()
|
|
#resp.get_ac_login_bonus_id_list.append(1) # TODO: track login bonus date
|
|
#resp.get_ac_login_bonus_id_list.append(2)
|
|
return resp.make()
|
|
|
|
async def handle_c500(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# user_info/get_user_basic_data
|
|
req = SaoGetUserBasicDataRequest(header, request)
|
|
|
|
profile_data = await self.data.profile.get_profile(req.user_id)
|
|
player_rank_data = self.load_data_csv("PlayerRank")
|
|
|
|
resp = SaoGetUserBasicDataResponse(profile_data)
|
|
for e in player_rank_data:
|
|
if resp.user_basic_data[0].rank_num == int(e['PlayerRankId']):
|
|
resp.user_basic_data[0].rank_exp = resp.user_basic_data[0].rank_exp - int(e["TotalExp"])
|
|
break
|
|
|
|
if profile_data['my_shop']:
|
|
ac = await self.data.arcade.get_arcade(profile_data['my_shop'])
|
|
if ac:
|
|
resp.user_basic_data[0].my_store_name = ac['name']
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c502(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# user_info/get_vp_gasha_ticket_data_list
|
|
req = SaoGetVpGashaTicketDataListRequest(header, request)
|
|
# TODO: gasha tickets
|
|
resp = SaoGetVpGashaTicketDataListResponse()
|
|
return resp.make()
|
|
|
|
async def handle_c504(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# user_info/get_present_box_num
|
|
req = SaoGenericUserRequest(header, request)
|
|
# TODO: presents
|
|
return SaoGetPresentBoxNumResponse().make()
|
|
|
|
async def handle_c600(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# have_object/get_hero_log_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
hero_level_data = self.load_data_csv("HeroLogLevel")
|
|
|
|
hero_data = await self.data.item.get_hero_logs(req.user_id)
|
|
|
|
resp = SaoGetHeroLogUserDataListResponse()
|
|
for hero in hero_data:
|
|
append = HeroLogUserData.from_args(hero)
|
|
hero_static = await self.data.static.get_hero_by_id(hero['hero_log_id'])
|
|
if not hero_static:
|
|
self.logger.warn(f"No hero for id {hero['hero_log_id']}, please run reader")
|
|
resp.hero_log_user_data_list.append(append)
|
|
continue
|
|
|
|
append.property1_property_id = hero_static['Property1PropertyId'] if hero_static['Property1PropertyId'] else 0
|
|
append.property1_value1 = hero_static['Property1Value1'] if hero_static['Property1Value1'] else 0
|
|
append.property1_value2 = hero_static['Property1Value2'] if hero_static['Property1Value2'] else 0
|
|
append.property2_property_id = hero_static['Property2PropertyId'] if hero_static['Property2PropertyId'] else 0
|
|
append.property2_value1 = hero_static['Property2Value1'] if hero_static['Property2Value1'] else 0
|
|
append.property2_value2 = hero_static['Property2Value2'] if hero_static['Property2Value2'] else 0
|
|
append.property3_property_id = hero_static['Property3PropertyId'] if hero_static['Property3PropertyId'] else 0
|
|
append.property3_value1 = hero_static['Property3Value1'] if hero_static['Property3Value1'] else 0
|
|
append.property3_value2 = hero_static['Property3Value2'] if hero_static['Property3Value2'] else 0
|
|
append.property4_property_id = hero_static['Property4PropertyId'] if hero_static['Property4PropertyId'] else 0
|
|
append.property4_value1 = hero_static['Property4Value1'] if hero_static['Property4Value1'] else 0
|
|
append.property4_value2 = hero_static['Property4Value2'] if hero_static['Property4Value2'] else 0
|
|
|
|
for e in hero_level_data:
|
|
if hero['log_level'] == int(e['HeroLogLevelId']):
|
|
append.log_exp = hero['log_exp'] - int(e["TotalExp"])
|
|
break
|
|
resp.hero_log_user_data_list.append(append)
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c602(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# have_object/get_equipment_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetEquipmentUserDataListResponse()
|
|
equip_level_data = self.load_data_csv("EquipmentLevel")
|
|
|
|
equipment_data = await self.data.item.get_user_equipments(req.user_id)
|
|
|
|
if equipment_data:
|
|
for equipment in equipment_data:
|
|
e = EquipmentUserData.from_args(equipment)
|
|
weapon_static = await self.data.static.get_equipment_by_id(equipment['equipment_id'])
|
|
if not weapon_static:
|
|
self.logger.warn(f"No equipment for id {equipment['equipment_id']}, please run reader")
|
|
resp.equipment_user_data_list.append(e)
|
|
continue
|
|
|
|
if not e.property1_property_id:
|
|
e.property1_property_id = weapon_static['Property1PropertyId'] if weapon_static['Property1PropertyId'] else 0
|
|
e.property1_value1 = weapon_static['Property1Value1'] if weapon_static['Property1Value1'] else 0
|
|
e.property1_value2 = weapon_static['Property1Value2'] if weapon_static['Property1Value2'] else 0
|
|
|
|
if not e.property2_property_id:
|
|
e.property2_property_id = weapon_static['Property2PropertyId'] if weapon_static['Property2PropertyId'] else 0
|
|
e.property2_value1 = weapon_static['Property2Value1'] if weapon_static['Property2Value1'] else 0
|
|
e.property2_value2 = weapon_static['Property2Value2'] if weapon_static['Property2Value2'] else 0
|
|
|
|
if e.property3_property_id:
|
|
e.property3_property_id = weapon_static['Property3PropertyId'] if weapon_static['Property3PropertyId'] else 0
|
|
e.property3_value1 = weapon_static['Property3Value1'] if weapon_static['Property3Value1'] else 0
|
|
e.property3_value2 = weapon_static['Property3Value2'] if weapon_static['Property3Value2'] else 0
|
|
|
|
if e.property4_property_id:
|
|
e.property4_property_id = weapon_static['Property4PropertyId'] if weapon_static['Property4PropertyId'] else 0
|
|
e.property4_value1 = weapon_static['Property4Value1'] if weapon_static['Property4Value1'] else 0
|
|
e.property4_value2 = weapon_static['Property4Value2'] if weapon_static['Property4Value2'] else 0
|
|
|
|
for f in equip_level_data:
|
|
if equipment['enhancement_value'] == int(f['EquipmentLevelId']):
|
|
e.enhancement_exp = equipment['enhancement_exp'] - int(f["TotalExp"])
|
|
break
|
|
resp.equipment_user_data_list.append(e)
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c604(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# have_object/get_item_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
|
|
item_data = await self.data.item.get_user_items(req.user_id)
|
|
|
|
resp = SaoGetItemUserDataListResponse(item_data)
|
|
return resp.make()
|
|
|
|
async def handle_c606(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# have_object/get_support_log_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetSupportLogUserDataListResponse()
|
|
supports = self.load_data_csv("SupportLog")
|
|
# TODO: Save supports
|
|
|
|
for x in range(len(supports)):
|
|
tmp = SupportLogUserData.from_args(f"{req.user_id}{x}", supports[x]['SupportLogId'])
|
|
resp.support_log_user_data_list.append(tmp)
|
|
return resp.make()
|
|
|
|
async def handle_c608(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#have_object/get_episode_append_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
# TODO: Appends
|
|
resp = SaoGetEpisodeAppendDataListResponse()
|
|
return resp.make()
|
|
|
|
async def handle_c60a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# have_object/get_event_item_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
res = SaoGetEventItemDataListResponse()
|
|
# TODO: Event items maybe
|
|
return res.make()
|
|
|
|
async def handle_c60c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# have_object/get_gasha_medal_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
res = SaoGetGashaMedalUserDataListResponse()
|
|
# TODO: Gasha Medal data
|
|
return res.make()
|
|
|
|
async def handle_c700(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# shop/get_shop_resource_sales_data_list
|
|
# TODO: Get user shop data
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetShopResourceSalesDataListResponse()
|
|
return resp.make()
|
|
|
|
async def handle_c702(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# shop/purchase_shop_resource
|
|
req = SaoPurchaseShopResourceRequest(header, request)
|
|
self.logger.infof(f"User {req.user_id} (ticket {req.ticket_id}) purchased shop resourse {req.user_shop_resource_id}")
|
|
# TODO: Shop purchases
|
|
return SaoNoopResponse(GameconnectCmd.PURCHASE_SHOP_RESOURCE_RESPONSE).make()
|
|
|
|
async def handle_c704(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# shop/discard_shop_resource
|
|
req = SaoPurchaseShopResourceRequest(header, request)
|
|
self.logger.infof(f"User {req.user_id} (ticket {req.ticket_id}) discarded shop resourse {req.user_shop_resource_id}")
|
|
return SaoNoopResponse(GameconnectCmd.DISCARD_SHOP_RESOURCE_RESPONSE).make()
|
|
|
|
async def handle_c800(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# custom/get_title_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
titleIdsData = await self.data.static.get_title_ids(0, True)
|
|
# TODO: Save titles
|
|
|
|
resp = SaoGetTitleUserDataListResponse(req.user_id, titleIdsData)
|
|
return resp.make()
|
|
|
|
async def handle_c802(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# custom/change_title
|
|
req = SaoChangeTitleRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} (ticket {req.ticket_id}) changed their title to {req.user_title_id}")
|
|
await self.data.profile.set_title(req.user_id, req.user_title_id)
|
|
|
|
return SaoNoopResponse(GameconnectCmd.CHANGE_TITLE_RESPONSE).make()
|
|
|
|
async def handle_c804(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# custom/get_party_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetPartyDataListResponse()
|
|
|
|
hero_parties = await self.data.item.get_hero_party(req.user_id)
|
|
for party in hero_parties:
|
|
hero1_data = await self.data.item.get_user_hero_by_id(party['user_hero_log_id_1'])
|
|
hero2_data = await self.data.item.get_user_hero_by_id(party['user_hero_log_id_2'])
|
|
hero3_data = await self.data.item.get_user_hero_by_id(party['user_hero_log_id_3'])
|
|
|
|
resp.party_data_list.append(PartyData.from_args(party['id'], party['user_party_team_id'], hero1_data._asdict(), hero2_data._asdict(), hero3_data._asdict()))
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c808(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# custom/get_support_log_party_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetSupportLogPartyDataListResponse()
|
|
# TODO: Support logs
|
|
return resp.make()
|
|
|
|
async def handle_c812(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# custom/disposal_resource
|
|
req = SaoDisposalResourceRequest(header, request)
|
|
get_col = 0
|
|
for disposal in req.disposal_common_reward_user_data_list:
|
|
if disposal.common_reward_type == RewardType.HeroLog:
|
|
removed_hero = await self.data.item.remove_hero_log(disposal.user_common_reward_id)
|
|
if removed_hero:
|
|
static_hero = await self.data.static.get_hero_by_id(removed_hero)
|
|
get_col += static_hero['SalePrice']
|
|
|
|
elif disposal.common_reward_type == RewardType.Equipment:
|
|
removed_equip = await self.data.item.remove_equipment(disposal.user_common_reward_id)
|
|
if removed_equip:
|
|
static_equip = await self.data.static.get_equipment_by_id(removed_equip)
|
|
get_col += static_equip['SalePrice']
|
|
|
|
elif disposal.common_reward_type == RewardType.Item:
|
|
removed_equip = await self.data.item.remove_item(disposal.user_common_reward_id)
|
|
if removed_equip:
|
|
static_equip = await self.data.static.get_equipment_by_id(removed_equip)
|
|
get_col += static_equip['SalePrice']
|
|
|
|
elif disposal.common_reward_type == RewardType.SupportLog:
|
|
continue
|
|
|
|
else:
|
|
self.logger.warn(f"Unhandled disposal type {disposal.common_reward_type}")
|
|
|
|
await self.data.profile.add_col(req.user_id, get_col)
|
|
return SaoDisposalResourceResponse(get_col).make()
|
|
|
|
async def handle_c814(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#custom/synthesize_enhancement_hero_log
|
|
req = SaoSynthesizeEnhancementHeroLogRequest(header, request)
|
|
resp = SaoSynthesizeEnhancementHeroLogResponse()
|
|
hero_level_data = self.load_data_csv("HeroLogLevel")
|
|
equip_level_data = self.load_data_csv("EquipmentLevel")
|
|
hero_exp = 0
|
|
col_cost = 0
|
|
|
|
for x in req.material_common_reward_user_data_list:
|
|
if x.common_reward_type == RewardType.Item:
|
|
user_item = await self.data.item.get_user_item_by_id(x.user_common_reward_id)
|
|
static_item = await self.data.static.get_item_id(user_item['item_id'])
|
|
|
|
if int(static_item['ItemTypeId']) == 7:
|
|
hero_exp += int(static_item['Value'])
|
|
self.logger.info(f"Remove item {x.user_common_reward_id} and add {int(static_item['Value'])} XP (running {hero_exp})")
|
|
await self.data.item.remove_item(x.user_common_reward_id)
|
|
|
|
elif x.common_reward_type == RewardType.Equipment:
|
|
equipment_data = await self.data.item.get_user_equipment_by_id(x.user_common_reward_id)
|
|
if equipment_data is None:
|
|
self.logger.error(f"Failed to find equipment {x.user_common_reward_id} for user {req.user_id}!")
|
|
continue
|
|
|
|
req_exp = 0
|
|
for e in range(len(equip_level_data)):
|
|
if equipment_data['enhancement_value'] == int(equip_level_data[e]['EquipmentLevelId']):
|
|
req_exp = equip_level_data[e + 1]['RequireExp']
|
|
break
|
|
|
|
static_equip_data = await self.data.static.get_equipment_by_id(equipment_data['equipment_id'])
|
|
|
|
hero_exp += int(static_equip_data['CompositionExp']) + req_exp
|
|
self.logger.info(f"Remove equipment {x.user_common_reward_id} and add {int(static_equip_data['CompositionExp']) + req_exp} XP (running {hero_exp})")
|
|
await self.data.item.remove_equipment(x.user_common_reward_id)
|
|
|
|
elif x.common_reward_type == RewardType.HeroLog:
|
|
hero_data = await self.data.item.get_hero_log_by_id(x.user_common_reward_id)
|
|
if hero_data is None:
|
|
self.logger.error(f"Failed to find hero {x.user_common_reward_id} for user {req.user_id}!")
|
|
continue
|
|
|
|
req_exp = 0
|
|
for e in range(len(hero_level_data)):
|
|
if hero_data['log_level'] == int(hero_level_data[e]['HeroLogLevelId']):
|
|
req_exp = hero_level_data[e + 1]['RequireExp']
|
|
break
|
|
|
|
static_hero_data = await self.data.static.get_hero_by_id(hero_data['hero_log_id'])
|
|
|
|
hero_exp += int(static_hero_data['CompositionExp']) + req_exp
|
|
self.logger.info(f"Remove hero {x.user_common_reward_id} and add {int(static_hero_data['CompositionExp']) + req_exp} XP (running {hero_exp})")
|
|
await self.data.item.remove_hero_log(x.user_common_reward_id)
|
|
|
|
else:
|
|
self.logger.warn(f"Unhandled ype {x.common_reward_type}! (running {hero_exp})")
|
|
|
|
hero_exp = int(hero_exp * 1.5)
|
|
await self.data.item.add_hero_xp(req.origin_user_hero_log_id, hero_exp)
|
|
log_exp = await self.data.item.get_hero_xp(req.origin_user_hero_log_id)
|
|
pre_synth_xp = log_exp - hero_exp
|
|
pre_synth_level = 1
|
|
|
|
for e in range(len(hero_level_data)):
|
|
if log_exp>=int(hero_level_data[e]["TotalExp"]) and log_exp<int(hero_level_data[e+1]["TotalExp"]):
|
|
self.logger.info(f"Set hero {req.origin_user_hero_log_id} level {hero_level_data[e]['HeroLogLevelId']}")
|
|
remain_exp = log_exp - int(hero_level_data[e]["TotalExp"])
|
|
await self.data.item.set_hero_level(req.origin_user_hero_log_id, hero_level_data[e]["HeroLogLevelId"])
|
|
break
|
|
|
|
for e in range(len(hero_level_data)):
|
|
if pre_synth_xp>=int(hero_level_data[e]["TotalExp"]) and pre_synth_xp<int(hero_level_data[e+1]["TotalExp"]):
|
|
pre_synth_level = int(hero_level_data[e]["HeroLogLevelId"])
|
|
break
|
|
|
|
# Load the item again to push to the response handler
|
|
synthesize_hero_log_data = await self.data.item.get_hero_log_by_id(req.origin_user_hero_log_id)
|
|
|
|
col_cost = pre_synth_level * (100 * len(req.material_common_reward_user_data_list)) * (1 - synthesize_hero_log_data['awakening_stage'] * 0.1)
|
|
if pre_synth_level >= 100:
|
|
col_cost = col_cost * 10
|
|
|
|
col_cost = col_cost * 1000
|
|
col_cost = max(100, int(col_cost / 1000))
|
|
|
|
self.logger.info(f"Synthesize {hero_exp} exp for hero {req.origin_user_hero_log_id}, costing {col_cost} col")
|
|
|
|
await self.data.profile.add_col(req.user_id, -col_cost)
|
|
if synthesize_hero_log_data is not None:
|
|
resp.after_hero_log_user_data.append(HeroLogUserData.from_args(synthesize_hero_log_data))
|
|
resp.after_hero_log_user_data[0].log_exp = remain_exp
|
|
return resp.make()
|
|
|
|
async def handle_c816(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#custom/synthesize_enhancement_equipment
|
|
req_data = SaoSynthesizeEnhancementEquipmentRequest(header, request)
|
|
resp = SaoSynthesizeEnhancementEquipmentResponse()
|
|
hero_level_data = self.load_data_csv("HeroLogLevel")
|
|
equip_level_data = self.load_data_csv("EquipmentLevel")
|
|
equipment_exp = 0
|
|
col_cost = 0
|
|
|
|
for x in req_data.material_common_reward_user_data_list:
|
|
if x.common_reward_type == RewardType.Item:
|
|
user_item = await self.data.item.get_user_item_by_id(x.user_common_reward_id)
|
|
static_item = await self.data.static.get_item_id(user_item['item_id'])
|
|
|
|
if int(static_item['ItemTypeId']) == 7:
|
|
equipment_exp += int(static_item['Value'])
|
|
self.logger.info(f"Remove item {x.user_common_reward_id} and add {int(static_item['Value'])} XP (running {equipment_exp})")
|
|
await self.data.item.remove_item(x.user_common_reward_id)
|
|
|
|
elif x.common_reward_type == RewardType.Equipment:
|
|
equipment_data = await self.data.item.get_user_equipment_by_id(x.user_common_reward_id)
|
|
if equipment_data is None:
|
|
self.logger.error(f"Failed to find equipment {x.user_common_reward_id} for user {req_data.user_id}!")
|
|
continue
|
|
|
|
req_exp = 0
|
|
for e in range(len(equip_level_data)):
|
|
if equipment_data['enhancement_value'] == int(equip_level_data[e]['EquipmentLevelId']):
|
|
req_exp = equip_level_data[e + 1]['RequireExp']
|
|
break
|
|
|
|
static_equip_data = await self.data.static.get_equipment_by_id(equipment_data['equipment_id'])
|
|
|
|
equipment_exp += int(static_equip_data['CompositionExp']) + req_exp
|
|
self.logger.info(f"Remove equipment {x.user_common_reward_id} and add {int(static_equip_data['CompositionExp']) + req_exp} XP (running {equipment_exp})")
|
|
await self.data.item.remove_equipment(x.user_common_reward_id)
|
|
|
|
elif x.common_reward_type == RewardType.HeroLog:
|
|
hero_data = await self.data.item.get_hero_log_by_id(x.user_common_reward_id)
|
|
if hero_data is None:
|
|
self.logger.error(f"Failed to find hero {x.user_common_reward_id} for user {req_data.user_id}!")
|
|
continue
|
|
|
|
req_exp = 0
|
|
for e in range(len(hero_level_data)):
|
|
if hero_data['log_level'] == int(hero_level_data[e]['HeroLogLevelId']):
|
|
req_exp = hero_level_data[e + 1]['RequireExp']
|
|
break
|
|
|
|
static_hero_data = await self.data.static.get_hero_by_id(hero_data['hero_log_id'])
|
|
|
|
equipment_exp += int(static_hero_data['CompositionExp']) + req_exp
|
|
self.logger.info(f"Remove hero {x.user_common_reward_id} and add {int(static_hero_data['CompositionExp']) + req_exp} XP (running {equipment_exp})")
|
|
await self.data.item.remove_hero_log(x.user_common_reward_id)
|
|
|
|
else:
|
|
self.logger.warn(f"Unhandled ype {x.common_reward_type}! (running {equipment_exp})")
|
|
|
|
equipment_exp = int(equipment_exp * 1.5)
|
|
await self.data.item.add_equipment_enhancement_exp(req_data.origin_user_equipment_id, equipment_exp)
|
|
synthesize_equipment_data = await self.data.item.get_user_equipment(req_data.user_id, req_data.origin_user_equipment_id)
|
|
equip_exp_new = synthesize_equipment_data['enhancement_exp']
|
|
pre_synth_level = synthesize_equipment_data['enhancement_value']
|
|
new_synth_level = 1
|
|
|
|
for e in range(len(equip_level_data)):
|
|
if equip_exp_new>=int(equip_level_data[e]["TotalExp"]) and equip_exp_new<int(equip_level_data[e+1]["TotalExp"]):
|
|
self.logger.info(f"Set equipment {req_data.origin_user_equipment_id} level {equip_level_data[e]['EquipmentLevelId']}")
|
|
new_synth_level = equip_level_data[e]['EquipmentLevelId']
|
|
remain_exp = equip_exp_new - int(equip_level_data[e]["TotalExp"])
|
|
await self.data.item.set_equipment_enhancement_value(req_data.origin_user_equipment_id, equip_level_data[e]["EquipmentLevelId"])
|
|
break
|
|
|
|
# Load the item again to push to the response handler
|
|
|
|
col_cost = pre_synth_level * (100 * len(req_data.material_common_reward_user_data_list)) * (1 - synthesize_equipment_data['awakening_stage'] * 0.1)
|
|
if pre_synth_level >= 100:
|
|
col_cost = col_cost * 10
|
|
|
|
col_cost = col_cost * 1000
|
|
col_cost = max(100, int(col_cost / 1000))
|
|
|
|
self.logger.info(f"Synthesize {equipment_exp} exp for equipment {req_data.origin_user_equipment_id}, costing {col_cost} col")
|
|
|
|
await self.data.profile.add_col(req_data.user_id, -col_cost)
|
|
if synthesize_equipment_data is not None:
|
|
resp.after_equipment_user_data.append(EquipmentUserData.from_args(synthesize_equipment_data))
|
|
resp.after_equipment_user_data[0].enhancement_exp = remain_exp
|
|
resp.after_equipment_user_data[0].enhancement_value = new_synth_level
|
|
return resp.make()
|
|
|
|
async def handle_c806(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#custom/change_party
|
|
req_data = SaoChangePartyRequest(header, request)
|
|
|
|
for party_team in req_data.party_data_list:
|
|
for hero in party_team.party_team_data_list:
|
|
await self.data.item.set_user_hero_weapons(
|
|
int(hero.user_hero_log_id),
|
|
int(hero.main_weapon_user_equipment_id) if hero.main_weapon_user_equipment_id and int(hero.main_weapon_user_equipment_id) > 0 else None,
|
|
int(hero.sub_equipment_user_equipment_id) if hero.sub_equipment_user_equipment_id and int(hero.sub_equipment_user_equipment_id) > 0 else None
|
|
)
|
|
await self.data.item.set_user_hero_skills(
|
|
int(hero.user_hero_log_id),
|
|
hero.skill_slot1_skill_id if hero.skill_slot1_skill_id > 0 else None,
|
|
hero.skill_slot2_skill_id if hero.skill_slot2_skill_id > 0 else None,
|
|
hero.skill_slot3_skill_id if hero.skill_slot3_skill_id > 0 else None,
|
|
hero.skill_slot4_skill_id if hero.skill_slot4_skill_id > 0 else None,
|
|
hero.skill_slot5_skill_id if hero.skill_slot5_skill_id > 0 else None
|
|
)
|
|
|
|
|
|
await self.data.item.put_hero_party(
|
|
req_data.user_id,
|
|
party_team.team_no,
|
|
party_team.party_team_data_list[0].user_hero_log_id,
|
|
party_team.party_team_data_list[1].user_hero_log_id,
|
|
party_team.party_team_data_list[2].user_hero_log_id,
|
|
)
|
|
|
|
resp = SaoNoopResponse(GameconnectCmd.CHANGE_PARTY_RESPONSE)
|
|
return resp.make()
|
|
|
|
async def handle_c900(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#quest/get_quest_scene_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
|
|
quest_data = await self.data.item.get_quest_logs(req.user_id)
|
|
|
|
resp = SaoGetQuestSceneUserDataListResponse()
|
|
for quest in quest_data:
|
|
ex_bonus_data = await self.data.item.get_player_ex_bonus_by_quest(req.user_id, quest["quest_scene_id"])
|
|
tmp = QuestSceneUserData.from_args(quest)
|
|
|
|
for ex_bonus in ex_bonus_data:
|
|
tmp.quest_scene_ex_bonus_user_data_list.append(QuestSceneExBonusUserData.from_args(ex_bonus['ex_bonus_table_id'], ex_bonus['quest_clear_flag']))
|
|
|
|
resp.quest_scene_user_data_list.append(tmp)
|
|
return resp.make()
|
|
|
|
async def handle_c902(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes: # for whatever reason, having all entries empty or filled changes nothing
|
|
#quest/get_quest_scene_prev_scan_profile_card
|
|
resp = SaoGetQuestScenePrevScanProfileCardResponse()
|
|
resp.profile_card_data.append(ReadProfileCardData.from_args({}, {}))
|
|
return resp.make()
|
|
|
|
async def handle_c904(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#quest/episode_play_start
|
|
req_data = SaoEpisodePlayStartRequest(header, request)
|
|
|
|
user_id = req_data.user_id
|
|
profile_data = await self.data.profile.get_profile(user_id)
|
|
|
|
sesh_id = await self.data.item.create_session(
|
|
user_id,
|
|
int(req_data.play_start_request_data[0].user_party_id),
|
|
req_data.episode_id,
|
|
req_data.play_mode,
|
|
req_data.play_start_request_data[0].quest_drop_boost_apply_flag
|
|
)
|
|
|
|
resp = SaoEpisodePlayStartResponse()
|
|
resp.play_start_response_data.append(QuestScenePlayStartResponseData.from_args(sesh_id, profile_data['nick_name']))
|
|
resp.multi_play_start_response_data.append(QuestSceneMultiPlayStartResponseData.from_args())
|
|
return resp.make()
|
|
|
|
async def handle_c908(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes: # Level calculation missing for the profile and heroes
|
|
#quest/episode_play_end
|
|
req_data = SaoEpisodePlayEndRequest(header, request)
|
|
resp = SaoEpisodePlayEndResponse()
|
|
|
|
user_id = req_data.user_id
|
|
episode_id = req_data.episode_id
|
|
play_end = req_data.play_end_request_data[0]
|
|
base_get_data = play_end.base_get_data[0]
|
|
score_data = play_end.score_data[0]
|
|
exp = 0
|
|
cleared_mission_ct = 0
|
|
highest_mission_diff_cleared = 0
|
|
num_monsters_defeated = 0
|
|
monsters_defeated_data = {}
|
|
json_data = {"data": []}
|
|
|
|
ep_data = await self.data.static.get_episode_by_id(req_data.episode_id)
|
|
quest_scene = await self.data.static.get_quest_by_id(int(ep_data['QuestSceneId']))
|
|
reward_table = await self.data.static.get_rewards_by_subtable(int(quest_scene['RewardTableSubId']))
|
|
ex_bonus_table = await self.data.static.get_ex_bonuses_by_subtable(int(ep_data['ExBonusTableSubId']))
|
|
|
|
await self.data.profile.add_col(user_id, base_get_data.get_col)
|
|
|
|
quest_clear_flag = score_data.clear_time > 0
|
|
clear_time = score_data.clear_time
|
|
combo_num = score_data.combo_num
|
|
total_damage = score_data.total_damage
|
|
concurrent_destroying_num = score_data.concurrent_destroying_num
|
|
|
|
if quest_clear_flag is True:
|
|
await self.data.profile.add_vp(user_id, quest_scene['SingleRewardVp'])
|
|
await self.data.profile.add_exp(user_id, quest_scene['SuccessPlayerExp'])
|
|
exp = await self.data.profile.get_exp(user_id)
|
|
|
|
else:
|
|
await self.data.profile.add_exp(user_id, quest_scene['FailedPlayerExp'])
|
|
exp = await self.data.profile.get_exp(user_id)
|
|
|
|
# Calculate level based off experience and the CSV list
|
|
player_level_data = self.load_data_csv("PlayerRank")
|
|
|
|
for i in range(0,len(player_level_data)):
|
|
if exp>=int(player_level_data[i]["TotalExp"]) and exp<int(player_level_data[i+1]["TotalExp"]):
|
|
await self.data.profile.set_level(user_id, int(player_level_data[i]["PlayerRankId"]))
|
|
break
|
|
current_data = await self.data.item.get_quest_log(user_id, ep_data['QuestSceneId'])
|
|
if current_data:
|
|
await self.data.item.put_player_quest(
|
|
user_id,
|
|
int(QuestType.EPISODE),
|
|
ep_data['QuestSceneId'],
|
|
False if not quest_clear_flag and not current_data['quest_clear_flag'] else True,
|
|
min(clear_time, current_data['clear_time']) if quest_clear_flag else current_data['clear_time'],
|
|
max(combo_num, current_data['combo_num']),
|
|
max(int(total_damage), current_data['total_damage']),
|
|
max(concurrent_destroying_num, current_data['concurrent_destroying_num'])
|
|
)
|
|
else:
|
|
await self.data.item.put_player_quest(
|
|
user_id,
|
|
int(QuestType.EPISODE),
|
|
ep_data['QuestSceneId'],
|
|
quest_clear_flag,
|
|
clear_time,
|
|
combo_num,
|
|
total_damage,
|
|
concurrent_destroying_num
|
|
)
|
|
|
|
for mission in play_end.mission_data_list:
|
|
if mission.clear_flag == 1:
|
|
cleared_mission_ct += 1
|
|
if mission.mission_difficulty_id > highest_mission_diff_cleared:
|
|
highest_mission_diff_cleared = mission.mission_difficulty_id
|
|
|
|
for monster_data in play_end.discovery_enemy_data_list:
|
|
num_monsters_defeated += monster_data.destroy_num
|
|
monsters_defeated_data[monster_data.enemy_kind_id] = monster_data.destroy_num
|
|
|
|
for bonus in ex_bonus_table:
|
|
table_id = int(bonus['ExBonusTableId'])
|
|
ach_thing = 0
|
|
condition = int(bonus['ExBonusConditionId'])
|
|
val1 = int(bonus['ConditionValue1'])
|
|
val2 = int(bonus['ConditionValue2'])
|
|
if condition == ExBonusCondition.CLEAR_UNDER_X_SECS:
|
|
if quest_clear_flag and int(score_data.clear_time / 1000) < val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.DEFEAT_X_MONSTER_Y_TIMES:
|
|
if monsters_defeated_data.get(val1, 0) >= val2:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.DEFEAT_X_MONSTERS:
|
|
if num_monsters_defeated >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.CLEAR_X_MISSIONS:
|
|
if cleared_mission_ct >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.CLEAR_MISSION_DIFFICULTY_X:
|
|
if highest_mission_diff_cleared >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.COLLECT_X_LOGS:
|
|
if len(play_end.get_unanalyzed_log_tmp_reward_data_list) >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.CLEAR_SKILL_LEVEL_X:
|
|
if score_data.reaching_skill_level >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.NO_LOSSES:
|
|
if score_data.total_loss_num == 0:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.ACCEL_X_TIMES:
|
|
if score_data.acceleration_invocation_num >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.MAX_COMBO_X:
|
|
if score_data.combo_num >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.MULTIPLAYER_CLEAR_X:
|
|
# TODO
|
|
pass
|
|
else:
|
|
self.logger.warn(f"Unhandled EX Bonus condition {condition}")
|
|
|
|
resp.play_end_response_data[0].ex_bonus_data_list.append(QuestScenePlayEndExBonusData.from_args(table_id, ach_thing))
|
|
|
|
self.logger.info(f"User {user_id} {'cleared' if quest_clear_flag else 'ended'} episode {episode_id}")
|
|
|
|
for rare_drop in play_end.get_rare_drop_data_list:
|
|
rewardList = self.load_data_csv("QuestRareDrop")
|
|
for drop in rewardList:
|
|
if int(drop['QuestRareDropId']) == rare_drop.quest_rare_drop_id:
|
|
await self.add_reward(drop, user_id)
|
|
break
|
|
|
|
for unanalyzed_log in play_end.get_unanalyzed_log_tmp_reward_data_list:
|
|
able_rewards: List[Row] = []
|
|
for reward in reward_table:
|
|
if int(reward['UnanalyzedLogGradeId']) == unanalyzed_log.unanalyzed_log_grade_id:
|
|
able_rewards.append(reward)
|
|
randomized_unanalyzed_id = choice(able_rewards)
|
|
|
|
await self.add_reward(randomized_unanalyzed_id._asdict(), user_id)
|
|
json_data["data"].append(randomized_unanalyzed_id._asdict())
|
|
|
|
|
|
trace_table = await self.data.static.get_player_trace_by_subid(quest_scene['PlayerTraceTableSubId'])
|
|
|
|
for trace in play_end.get_player_trace_data_list:
|
|
self.logger.info(f"User {user_id} obtained trace {trace.user_quest_scene_player_trace_id}")
|
|
resp.play_end_response_data[0].play_end_player_trace_reward_data_list.append(QuestScenePlayEndPlayerTraceRewardData.from_args(choice(trace_table)._asdict()))
|
|
|
|
await self.data.item.create_end_session(user_id, ep_data['QuestSceneId'], play_end.play_result_flag, json_data["data"])
|
|
|
|
# Update heroes from the used party
|
|
play_session = await self.data.item.get_session(user_id)
|
|
session_party = await self.data.item.get_hero_party_by_id(play_session["user_party_team_id"])
|
|
if session_party:
|
|
hero_level_data = self.load_data_csv("HeroLogLevel")
|
|
hero_list = []
|
|
hero_list.append(session_party["user_hero_log_id_1"])
|
|
hero_list.append(session_party["user_hero_log_id_2"])
|
|
hero_list.append(session_party["user_hero_log_id_3"])
|
|
|
|
for i in range(0,3):
|
|
await self.data.item.add_hero_xp(hero_list[i], base_get_data.get_hero_log_exp)
|
|
log_exp = await self.data.item.get_hero_xp(hero_list[i])
|
|
|
|
# Calculate hero level based off experience and the CSV list
|
|
if log_exp:
|
|
for e in range(0,len(hero_level_data)):
|
|
if log_exp>=int(hero_level_data[e]["TotalExp"]) and log_exp<int(hero_level_data[e+1]["TotalExp"]):
|
|
self.logger.info(f"Set hero {hero_list[i]} level {hero_level_data[e]['HeroLogLevelId']} ({log_exp} total XP)")
|
|
await self.data.item.set_hero_level(hero_list[i], hero_level_data[e]['HeroLogLevelId'])
|
|
break
|
|
else:
|
|
self.logger.error(f"Failed to get session party {play_session['user_party_team_id']} data for user {user_id}!")
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c90a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#quest/episode_play_end_unanalyzed_log_fixed
|
|
req = SaoEpisodePlayEndUnanalyzedLogFixedRequest(header, request)
|
|
resp = SaoEpisodePlayEndUnanalyzedLogFixedResponse()
|
|
|
|
end_session_data = await self.data.item.get_end_session(req.user_id)
|
|
for data in end_session_data['reward_data']:
|
|
resp.play_end_unanalyzed_log_reward_data_list.append(QuestScenePlayEndUnanalyzedLogRewardData.from_args(data['UnanalyzedLogGradeId'], data))
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c914(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#quest/trial_tower_play_start
|
|
req_data = SaoTrialTowerPlayStartRequest(header, request)
|
|
|
|
user_id = req_data.user_id
|
|
profile_data = await self.data.profile.get_profile(user_id)
|
|
|
|
sesh_id = await self.data.item.create_session(
|
|
user_id,
|
|
int(req_data.play_start_request_data[0].user_party_id),
|
|
req_data.trial_tower_id,
|
|
req_data.play_mode,
|
|
req_data.play_start_request_data[0].quest_drop_boost_apply_flag
|
|
)
|
|
|
|
self.logger.info(f"User {req_data.user_id} started trial tower on floor {req_data.trial_tower_id}")
|
|
resp = SaoTrialTowerPlayStartResponse(sesh_id, profile_data['nick_name'])
|
|
return resp.make()
|
|
|
|
async def handle_c918(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#quest/trial_tower_play_end
|
|
req_data = SaoTrialTowerPlayEndRequest(header, request)
|
|
resp = SaoTrialTowerPlayEndResponse()
|
|
|
|
user_id = req_data.user_id
|
|
trial_tower_id = req_data.trial_tower_id
|
|
play_end = req_data.play_end_request_data[0]
|
|
base_get_data = play_end.base_get_data[0]
|
|
score_data = play_end.score_data[0]
|
|
exp = 0
|
|
cleared_mission_ct = 0
|
|
highest_mission_diff_cleared = 0
|
|
num_monsters_defeated = 0
|
|
monsters_defeated_data = {}
|
|
json_data = {"data": []}
|
|
|
|
ep_data = await self.data.static.get_tower_by_id(trial_tower_id)
|
|
quest_scene = await self.data.static.get_quest_by_id(int(ep_data['QuestSceneId']))
|
|
reward_table = await self.data.static.get_rewards_by_subtable(int(quest_scene['RewardTableSubId']))
|
|
ex_bonus_table = await self.data.static.get_ex_bonuses_by_subtable(int(ep_data['ExBonusTableSubId']))
|
|
|
|
await self.data.profile.add_col(user_id, base_get_data.get_col)
|
|
|
|
quest_clear_flag = score_data.clear_time > 0
|
|
clear_time = score_data.clear_time
|
|
combo_num = score_data.combo_num
|
|
total_damage = score_data.total_damage
|
|
concurrent_destroying_num = score_data.concurrent_destroying_num
|
|
|
|
if quest_clear_flag is True:
|
|
await self.data.profile.add_vp(user_id, quest_scene['SingleRewardVp'])
|
|
await self.data.profile.add_exp(user_id, quest_scene['SuccessPlayerExp'])
|
|
exp = await self.data.profile.get_exp(user_id)
|
|
|
|
else:
|
|
await self.data.profile.add_exp(user_id, quest_scene['FailedPlayerExp'])
|
|
exp = await self.data.profile.get_exp(user_id)
|
|
|
|
# Calculate level based off experience and the CSV list
|
|
player_level_data = self.load_data_csv("PlayerRank")
|
|
|
|
for i in range(0,len(player_level_data)):
|
|
if exp>=int(player_level_data[i]["TotalExp"]) and exp<int(player_level_data[i+1]["TotalExp"]):
|
|
await self.data.profile.set_level(user_id, int(player_level_data[i]["PlayerRankId"]))
|
|
break
|
|
current_data = await self.data.item.get_quest_log(user_id, ep_data['QuestSceneId'])
|
|
if current_data:
|
|
await self.data.item.put_player_quest(
|
|
user_id,
|
|
int(QuestType.TRIAL_TOWER),
|
|
ep_data['QuestSceneId'],
|
|
False if not quest_clear_flag and not current_data['quest_clear_flag'] else True,
|
|
min(clear_time, current_data['clear_time']) if quest_clear_flag else current_data['clear_time'],
|
|
max(combo_num, current_data['combo_num']),
|
|
max(int(total_damage), current_data['total_damage']),
|
|
max(concurrent_destroying_num, current_data['concurrent_destroying_num'])
|
|
)
|
|
else:
|
|
await self.data.item.put_player_quest(
|
|
user_id,
|
|
int(QuestType.TRIAL_TOWER),
|
|
ep_data['QuestSceneId'],
|
|
quest_clear_flag,
|
|
clear_time,
|
|
combo_num,
|
|
total_damage,
|
|
concurrent_destroying_num
|
|
)
|
|
|
|
for mission in play_end.mission_data_list:
|
|
if mission.clear_flag == 1:
|
|
cleared_mission_ct += 1
|
|
if mission.mission_difficulty_id > highest_mission_diff_cleared:
|
|
highest_mission_diff_cleared = mission.mission_difficulty_id
|
|
|
|
for monster_data in play_end.discovery_enemy_data_list:
|
|
num_monsters_defeated += monster_data.destroy_num
|
|
monsters_defeated_data[monster_data.enemy_kind_id] = monster_data.destroy_num
|
|
|
|
for bonus in ex_bonus_table:
|
|
table_id = int(bonus['ExBonusTableId'])
|
|
ach_thing = 0
|
|
condition = int(bonus['ExBonusConditionId'])
|
|
val1 = int(bonus['ConditionValue1'])
|
|
val2 = int(bonus['ConditionValue2'])
|
|
if condition == ExBonusCondition.CLEAR_UNDER_X_SECS:
|
|
if quest_clear_flag and int(score_data.clear_time / 1000) < val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.DEFEAT_X_MONSTER_Y_TIMES:
|
|
if monsters_defeated_data.get(val1, 0) >= val2:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.DEFEAT_X_MONSTERS:
|
|
if num_monsters_defeated >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.CLEAR_X_MISSIONS:
|
|
if cleared_mission_ct >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.CLEAR_MISSION_DIFFICULTY_X:
|
|
if highest_mission_diff_cleared >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.COLLECT_X_LOGS:
|
|
if len(play_end.get_unanalyzed_log_tmp_reward_data_list) >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.CLEAR_SKILL_LEVEL_X:
|
|
if score_data.reaching_skill_level >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.NO_LOSSES:
|
|
if score_data.total_loss_num == 0:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.ACCEL_X_TIMES:
|
|
if score_data.acceleration_invocation_num >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.MAX_COMBO_X:
|
|
if score_data.combo_num >= val1:
|
|
await self.add_reward(bonus._asdict(), user_id)
|
|
await self.data.item.put_ex_bonus(user_id, int(ep_data['QuestSceneId']), table_id, True)
|
|
ach_thing = 2
|
|
elif condition == ExBonusCondition.MULTIPLAYER_CLEAR_X:
|
|
# TODO
|
|
pass
|
|
else:
|
|
self.logger.warn(f"Unhandled EX Bonus condition {condition}")
|
|
|
|
resp.play_end_response_data[0].ex_bonus_data_list.append(QuestScenePlayEndExBonusData.from_args(table_id, ach_thing))
|
|
|
|
self.logger.info(f"User {user_id} {'cleared' if quest_clear_flag else 'ended'} trial tower {trial_tower_id}")
|
|
|
|
for rare_drop in play_end.get_rare_drop_data_list:
|
|
rewardList = self.load_data_csv("QuestRareDrop")
|
|
for drop in rewardList:
|
|
if int(drop['QuestRareDropId']) == rare_drop.quest_rare_drop_id:
|
|
await self.add_reward(drop, user_id)
|
|
break
|
|
|
|
for unanalyzed_log in play_end.get_unanalyzed_log_tmp_reward_data_list:
|
|
able_rewards: List[Row] = []
|
|
for reward in reward_table:
|
|
if int(reward['UnanalyzedLogGradeId']) == unanalyzed_log.unanalyzed_log_grade_id:
|
|
able_rewards.append(reward)
|
|
randomized_unanalyzed_id = choice(able_rewards)
|
|
|
|
await self.add_reward(randomized_unanalyzed_id._asdict(), user_id)
|
|
json_data["data"].append(randomized_unanalyzed_id._asdict())
|
|
|
|
|
|
trace_table = await self.data.static.get_player_trace_by_subid(quest_scene['PlayerTraceTableSubId'])
|
|
|
|
for trace in play_end.get_player_trace_data_list:
|
|
self.logger.info(f"User {user_id} obtained trace {trace.user_quest_scene_player_trace_id}")
|
|
resp.play_end_response_data[0].play_end_player_trace_reward_data_list.append(QuestScenePlayEndPlayerTraceRewardData.from_args(choice(trace_table)._asdict()))
|
|
|
|
await self.data.item.create_end_session(user_id, ep_data['QuestSceneId'], play_end.play_result_flag, json_data["data"])
|
|
|
|
# Update heroes from the used party
|
|
play_session = await self.data.item.get_session(user_id)
|
|
session_party = await self.data.item.get_hero_party_by_id(play_session["user_party_team_id"])
|
|
if session_party:
|
|
hero_level_data = self.load_data_csv("HeroLogLevel")
|
|
hero_list = []
|
|
hero_list.append(session_party["user_hero_log_id_1"])
|
|
hero_list.append(session_party["user_hero_log_id_2"])
|
|
hero_list.append(session_party["user_hero_log_id_3"])
|
|
|
|
for i in range(0,3):
|
|
self.logger.info(f"Give hero {hero_list[i]} {base_get_data.get_hero_log_exp}")
|
|
await self.data.item.add_hero_xp(hero_list[i], base_get_data.get_hero_log_exp)
|
|
log_exp = await self.data.item.get_hero_xp(hero_list[i])
|
|
|
|
# Calculate hero level based off experience and the CSV list
|
|
if log_exp:
|
|
for e in range(0,len(hero_level_data)):
|
|
if log_exp>=int(hero_level_data[e]["TotalExp"]) and log_exp<int(hero_level_data[e+1]["TotalExp"]):
|
|
self.logger.info(f"Set hero {hero_list[i]} level {hero_level_data[e]['HeroLogLevelId']} ({log_exp} total XP)")
|
|
await self.data.item.set_hero_level(hero_list[i], hero_level_data[e]['HeroLogLevelId'])
|
|
break
|
|
else:
|
|
self.logger.error(f"Failed to get session party {play_session['user_party_team_id']} data for user {user_id}!")
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c91a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes: # handler is identical to the episode
|
|
#quest/trial_tower_play_end_unanalyzed_log_fixed
|
|
req = SaoTrialTowerPlayEndUnanalyzedLogFixedRequest(header, request)
|
|
resp = SaoTrialTowerPlayEndUnanalyzedLogFixedResponse()
|
|
|
|
end_session_data = await self.data.item.get_end_session(req.user_id)
|
|
for data in end_session_data['reward_data']:
|
|
resp.play_end_unanalyzed_log_reward_data_list.append(QuestScenePlayEndUnanalyzedLogRewardData.from_args(data['UnanalyzedLogGradeId'], data))
|
|
|
|
return resp.make()
|
|
|
|
async def handle_c930(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# quest/get_chat_side_story_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetChatSideStoryUserDataListResponse()
|
|
|
|
return resp.make()
|
|
|
|
async def handle_ca02(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#quest_multi_play_room/get_quest_scene_multi_play_photon_server
|
|
resp = SaoGetQuestSceneMultiPlayPhotonServerResponse(self.game_cfg.server.photon_app_id)
|
|
return resp.make()
|
|
|
|
async def handle_cb02(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# quest_ranking/get_quest_hierarchy_progress_degrees_ranking_list
|
|
req = SaoGetQuestHierarchyProgressDegreesRankingListRequest(header, request)
|
|
return SaoGetQuestHierarchyProgressDegreesRankingListResponse(GameconnectCmd.GET_QUEST_HIERARCHY_PROGRESS_DEGREES_RANKING_LIST_RESPONSE).make()
|
|
|
|
async def handle_cb04(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# quest_ranking/get_quest_popular_hero_log_ranking_list
|
|
req = SaoGetQuestPopularHeroLogRankingListRequest(header, request)
|
|
return SaoGetQuestPopularHeroLogRankingListResponse(GameconnectCmd.GET_QUEST_POPULAR_HERO_LOG_RANKING_LIST_RESPONSE).make()
|
|
|
|
async def handle_cd00(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#defrag_match/get_defrag_match_basic_data
|
|
resp = SaoGetDefragMatchBasicDataResponse()
|
|
data = DefragMatchBasicUserData.from_args()
|
|
return resp.make()
|
|
|
|
async def handle_cd02(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#defrag_match/get_defrag_match_ranking_user_data
|
|
# TODO: League points
|
|
req = SaoGetDefragMatchRankingUserDataRequest(header, request)
|
|
profile = await self.data.profile.get_profile(req.user_id)
|
|
resp = SaoGetDefragMatchRankingUserDataResponse(profile._asdict())
|
|
return resp.make()
|
|
|
|
async def handle_cd04(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#defrag_match/get_defrag_match_league_point_ranking_list
|
|
resp = SaoGetDefragMatchLeaguePointRankingListResponse()
|
|
return resp.make()
|
|
|
|
async def handle_cd06(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
#defrag_match/get_defrag_match_league_score_ranking_list
|
|
resp = SaoGetDefragMatchLeagueScoreRankingListResponse()
|
|
return resp.make()
|
|
|
|
async def handle_cf0e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# gasha/get_gasha_medal_shop_user_data_list
|
|
# TODO: Get user shop data
|
|
req = GetGashaMedalShopUserDataListRequest(header, request)
|
|
resp = GetGashaMedalShopUserDataListResponse(GameconnectCmd.GET_GASHA_MEDAL_SHOP_USER_DATA_LIST_RESPONSE)
|
|
return resp.make()
|
|
|
|
async def handle_d000(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetAdventureExecUserDataResponse()
|
|
return resp.make()
|
|
|
|
async def handle_d100(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# shop/get_yui_medal_shop_user_data_list
|
|
# TODO: Get user shop data
|
|
req = GetYuiMedalShopUserDataListRequest(header, request)
|
|
resp = GetYuiMedalShopUserDataListResponse(GameconnectCmd.GET_YUI_MEDAL_SHOP_USER_DATA_LIST_RESPONSE)
|
|
return resp.make()
|
|
|
|
async def handle_d200(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# mission/get_beginner_mission_user_data
|
|
req = SaoGetBeginnerMissionUserDataRequest(header, request)
|
|
resp = SaoGetBeginnerMissionUserDataResponse()
|
|
profile = await self.data.profile.get_profile(req.user_id)
|
|
if profile:
|
|
if profile['ad_confirm_date']:
|
|
resp.data[0].ad_confirm_date = profile['ad_confirm_date']
|
|
resp.data[0].ad_confirm_flag = 1
|
|
|
|
return resp.make()
|
|
|
|
async def handle_d202(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# mission/get_beginner_mission_progresses_user_data_list
|
|
req = SaoGetBeginnerMissionProgressesUserDataListRequest(header, request)
|
|
resp = SaoGetBeginnerMissionProgressesUserDataListResponse()
|
|
|
|
return resp.make()
|
|
|
|
async def handle_d204(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# mission/get_beginner_mission_seat_progresses_user_data_list
|
|
req = SaoGetBeginnerMissionSeatProgressesUserDataListRequest(header, request)
|
|
resp = SaoGetBeginnerMissionSeatProgressesUserDataListResponse()
|
|
|
|
return resp.make()
|
|
|
|
async def handle_d206(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# mission/beginner_mission_ad_confirm_notification
|
|
req = SaoBeginnerMissionAdConfirmNotificationRequest(header, request)
|
|
self.logger.info(f"User {req.user_id} confirmed ad for beginner mission {req.beginner_mission_id}")
|
|
await self.data.profile.update_beginner_mission_date(req.user_id)
|
|
|
|
return SaoNoopResponse(GameconnectCmd.BEGINNER_MISSION_AD_CONFIRM_NOTIFICATION_RESPONSE).make()
|
|
|
|
async def handle_d312(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# campaign/get_linked_site_reg_campaign_user_data
|
|
req = SaoGetLinkedSiteRegCampaignUserDataRequest(header, request)
|
|
resp = SaoGetLinkedSiteRegCampaignUserDataResponse()
|
|
|
|
return resp.make()
|
|
|
|
async def handle_d400(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# other/get_hero_log_unit_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetHeroLogUnitUserDataListResponse()
|
|
|
|
return resp.make()
|
|
|
|
async def handle_d402(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# other/get_chara_unit_user_data_list
|
|
req = SaoGenericUserRequest(header, request)
|
|
resp = SaoGetCharaUnitUserDataListResponse()
|
|
|
|
return resp.make()
|
|
|
|
async def handle_d404(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# other/bnid_serial_code_check
|
|
req = SaoBnidSerialCodeCheckRequest()
|
|
resp = SaoBnidSerialCodeCheckResponse()
|
|
return resp.make()
|
|
|
|
async def handle_d404(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# other/bnid_serial_code_entry_by_appendix_card
|
|
req = SaoBnidSerialCodeEntryByAppendixCardRequest()
|
|
resp = SaoBnidSerialCodeEntryByAppendixCardResponse()
|
|
return resp.make()
|
|
|
|
async def handle_d500(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_player_ranks
|
|
tbl = self.load_data_csv('PlayerRank')
|
|
resp = SaoGetMPlayerRanksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d502(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_titles
|
|
tbl = self.load_data_csv('Title')
|
|
resp = SaoGetMTitlesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d504(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_fragments
|
|
tbl = self.load_data_csv('Fragment')
|
|
resp = SaoGetMFragmentsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d506(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_reward_tables
|
|
tbl = self.load_data_csv('RewardTable')
|
|
resp = SaoGetMRewardTablesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d508(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_reward_sets
|
|
tbl = self.load_data_csv('RewardSet')
|
|
resp = SaoGetMRewardSetsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d50a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_unanalyzed_log_grades
|
|
tbl = self.load_data_csv('UnanalyzedLogGrade')
|
|
resp = SaoGetMUnanalyzedLogGradesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d50c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_appoint_leader_params
|
|
tbl = self.load_data_csv('AppointLeaderParam')
|
|
resp = SaoGetMAppointLeaderParamsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d50e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_appoint_leader_effects
|
|
tbl = self.load_data_csv('AppointLeaderEffect')
|
|
resp = SaoGetMAppointLeaderEffectsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d510(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_appoint_leader_effect_types
|
|
tbl = self.load_data_csv('AppointLeaderEffectType')
|
|
resp = SaoGetMAppointLeaderEffectTypesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d512(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_rarities
|
|
tbl = self.load_data_csv('Rarity')
|
|
resp = SaoGetMRaritiesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d514(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_composition_events
|
|
tbl = self.load_data_csv('CompositionEvent')
|
|
resp = SaoGetMCompositionEventsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d516(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_composition_params
|
|
tbl = self.load_data_csv('CompositionParam')
|
|
resp = SaoGetMCompositionParamsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d518(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_game_play_prices
|
|
tbl = self.load_data_csv('GamePlayPrice')
|
|
resp = SaoGetMGamePlayPricesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d51a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_buy_tickets
|
|
tbl = self.load_data_csv('BuyTicket')
|
|
resp = SaoGetMBuyTicketsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d51c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_tips
|
|
tbl = self.load_data_csv('Tips')
|
|
resp = SaoGetMTipsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d51e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_caps
|
|
tbl = self.load_data_csv('Cap')
|
|
resp = SaoGetMCapsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d520(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_hero_log
|
|
tbl = self.load_data_csv('HeroLog')
|
|
resp = SaoGetMHeroLogResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d522(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_hero_log_levels
|
|
tbl = self.load_data_csv('HeroLogLevel')
|
|
resp = SaoGetMHeroLogLevelsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d524(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_hero_log_roles
|
|
tbl = self.load_data_csv('HeroLogRole')
|
|
resp = SaoGetMHeroLogRolesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d526(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_hero_log_trust_ranks
|
|
tbl = self.load_data_csv('HeroLogTrustRank')
|
|
resp = SaoGetMHeroLogTrustRanksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d528(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_charas
|
|
tbl = self.load_data_csv('Chara')
|
|
resp = SaoGetMCharasResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d52a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_chara_friendly_ranks
|
|
tbl = self.load_data_csv('CharaFriendlyRank')
|
|
resp = SaoGetMCharaFriendlyRanksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d52c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_equipments
|
|
tbl = self.load_data_csv('Equipment')
|
|
resp = SaoGetMEquipmentsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d52e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_equipment_levels
|
|
tbl = self.load_data_csv('EquipmentLevel')
|
|
resp = SaoGetMEquipmentLevelsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d530(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_weapon_types
|
|
tbl = self.load_data_csv('WeaponType')
|
|
resp = SaoGetMWeaponTypesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d532(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_items
|
|
tbl = self.load_data_csv('Item')
|
|
resp = SaoGetMItemsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d534(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_item_types
|
|
tbl = self.load_data_csv('ItemType')
|
|
resp = SaoGetMItemTypesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d536(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_buff_items
|
|
tbl = self.load_data_csv('BuffItem')
|
|
resp = SaoGetMBuffItemsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d538(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_enemies
|
|
tbl = self.load_data_csv('Enemy')
|
|
resp = SaoGetMEnemiesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d53a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_enemy_sets
|
|
tbl = self.load_data_csv('EnemySet')
|
|
resp = SaoGetMEnemySetsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d53c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_enemy_kinds
|
|
tbl = self.load_data_csv('EnemyKind')
|
|
resp = SaoGetMEnemyKindsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d53e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_enemy_categories
|
|
tbl = self.load_data_csv('EnemyCategory')
|
|
resp = SaoGetMEnemyCategoriesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d540(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_units
|
|
tbl = self.load_data_csv('Unit')
|
|
resp = SaoGetMUnitsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d542(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_unit_gimmicks
|
|
tbl = self.load_data_csv('UnitGimmick')
|
|
resp = SaoGetMUnitGimmicksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d544(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_unit_collisions
|
|
tbl = self.load_data_csv('UnitCollision')
|
|
resp = SaoGetMUnitCollisionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d546(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_unit_powers
|
|
tbl = self.load_data_csv('UnitPower')
|
|
resp = SaoGetMUnitPowersResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d548(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gimmick_attacks
|
|
tbl = self.load_data_csv('GimmickAttack')
|
|
resp = SaoGetMGimmickAttacksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d54a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_chara_attacks
|
|
tbl = self.load_data_csv('CharaAttack')
|
|
resp = SaoGetMCharaAttacksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d54c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_boss_attacks
|
|
tbl = self.load_data_csv('BossAttack')
|
|
resp = SaoGetMBossAttacksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d54e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_monster_attacks
|
|
tbl = self.load_data_csv('MonsterAttack')
|
|
resp = SaoGetMMonsterAttacksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d550(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_monster_actions
|
|
tbl = self.load_data_csv('MonsterAction')
|
|
resp = SaoGetMMonsterActionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d552(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_properties
|
|
tbl = self.load_data_csv('Property')
|
|
resp = SaoGetMPropertiesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d554(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_property_tables
|
|
tbl = self.load_data_csv('PropertyTable')
|
|
resp = SaoGetMPropertyTablesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d556(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_property_types
|
|
tbl = self.load_data_csv('PropertyType')
|
|
resp = SaoGetMPropertyTypesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d558(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_skills
|
|
tbl = self.load_data_csv('Skill')
|
|
resp = SaoGetMSkillsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d55a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_skill_tables
|
|
tbl = self.load_data_csv('SkillTable')
|
|
resp = SaoGetMSkillTablesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d55c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_skill_levels
|
|
tbl = self.load_data_csv('SkillLevel')
|
|
resp = SaoGetMSkillLevelsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d55e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_awakenings
|
|
tbl = self.load_data_csv('Awakening')
|
|
resp = SaoGetMAwakeningsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d560(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_synchro_skills
|
|
tbl = self.load_data_csv('SynchroSkill')
|
|
resp = SaoGetMSynchroSkillsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d562(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_sound_skill_cut_in_voices
|
|
tbl = self.load_data_csv('Sound_SkillCutInVoice')
|
|
resp = SaoGetMSoundSkillCutInVoicesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d564(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_scenes
|
|
tbl = self.load_data_csv('QuestScene')
|
|
resp = SaoGetMQuestScenesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d566(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_exist_units
|
|
tbl = self.load_data_csv('QuestExistUnit')
|
|
resp = SaoGetMQuestExistUnitsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d568(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_episode_append_rewards
|
|
tbl = self.load_data_csv('QuestEpisodeAppendRewards')
|
|
resp = SaoGetMQuestEpisodeAppendRewardsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d56a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_side_quests
|
|
tbl = self.load_data_csv('SideQuest')
|
|
resp = SaoGetMSideQuestsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d56c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_episodes
|
|
tbl = self.load_data_csv('Episode')
|
|
resp = SaoGetMEpisodesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d56e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_episode_chapters
|
|
tbl = self.load_data_csv('EpisodeChapter')
|
|
resp = SaoGetMEpisodeChaptersResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d570(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_episode_parts
|
|
tbl = self.load_data_csv('EpisodePart')
|
|
resp = SaoGetMEpisodePartsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d572(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_trial_towers
|
|
tbl = self.load_data_csv('TrialTower')
|
|
resp = SaoGetMTrialTowersResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d574(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_ex_towers
|
|
req = SaoGetMExTowersRequest(header, request)
|
|
tbl = self.load_data_csv('ExTowers')
|
|
resp = SaoGetMExTowersResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d576(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_ex_tower_quests
|
|
req = SaoGetMExTowerQuestsRequest(header, request)
|
|
tbl = self.load_data_csv('ExTowerQuests')
|
|
resp = SaoGetMExTowerQuestsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d578(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_menu_display_enemies
|
|
tbl = self.load_data_csv('MenuDisplayEnemy')
|
|
resp = SaoGetMMenuDisplayEnemiesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d57a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_missions
|
|
tbl = self.load_data_csv('Mission')
|
|
resp = SaoGetMMissionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d57c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_mission_tables
|
|
tbl = self.load_data_csv('MissionTable')
|
|
resp = SaoGetMMissionTablesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d57e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_mission_difficulties
|
|
tbl = self.load_data_csv('MissionDifficulty')
|
|
resp = SaoGetMMissionDifficultiesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d580(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_battle_cameras
|
|
tbl = self.load_data_csv('BattleCamera')
|
|
resp = SaoGetMBattleCamerasResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d582(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_chat_main_stories
|
|
tbl = self.load_data_csv('ChatMainStory')
|
|
resp = SaoGetMChatMainStoriesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d584(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_chat_side_stories
|
|
tbl = self.load_data_csv('ChatSideStory')
|
|
resp = SaoGetMChatSideStoriesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d586(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_chat_event_stories
|
|
req = SaoGetMChatEventStoriesRequest(header, request)
|
|
tbl = self.load_data_csv('ChatEventStory')
|
|
resp = SaoGetMChatEventStoriesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d588(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_navigator_charas
|
|
tbl = self.load_data_csv('NavigatorChara')
|
|
resp = SaoGetMNavigatorCharasResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d58a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_navigator_comments
|
|
tbl = self.load_data_csv('NavigatorComment')
|
|
resp = SaoGetMNavigatorCommentsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d58c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_ex_bonus_tables
|
|
tbl = self.load_data_csv('ExBonusTable')
|
|
resp = SaoGetMExBonusTablesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d58e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_ex_bonus_conditions
|
|
tbl = self.load_data_csv('ExBonusCondition')
|
|
resp = SaoGetMExBonusConditionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d590(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_rare_drops
|
|
tbl = self.load_data_csv('QuestRareDrop')
|
|
resp = SaoGetMQuestRareDropsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d592(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_special_rare_drop_settings
|
|
tbl = self.load_data_csv('QuestSpecialRareDropSettings')
|
|
resp = SaoGetMQuestSpecialRareDropSettingsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d594(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_special_rare_drops
|
|
tbl = self.load_data_csv('QuestSpecialRareDrops')
|
|
resp = SaoGetMQuestSpecialRareDropsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d596(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_tutorials
|
|
tbl = self.load_data_csv('QuestTutorial')
|
|
resp = SaoGetMQuestTutorialsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d598(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_player_trace_tables
|
|
tbl = self.load_data_csv('PlayerTraceTable')
|
|
resp = SaoGetMQuestPlayerTraceTablesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d59a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_stills
|
|
tbl = self.load_data_csv('QuestStill')
|
|
resp = SaoGetMQuestStillsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d59c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gashas
|
|
tbl = self.load_data_csv('Gasha')
|
|
resp = SaoGetMGashasResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d59e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_headers
|
|
tbl = self.load_data_csv('GashaHeader')
|
|
resp = SaoGetMGashaHeadersResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5a0(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_lottery_rarities
|
|
tbl = self.load_data_csv('GashaLotteryRarity')
|
|
resp = SaoGetMGashaLotteryRaritiesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5a2(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_prizes
|
|
tbl = self.load_data_csv('GashaPrize')
|
|
resp = SaoGetMGashaPrizesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5a4(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_comeback_events
|
|
tbl = self.load_data_csv('ComebackEvent')
|
|
resp = SaoGetMComebackEventsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5a6(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_ad_banners
|
|
tbl = self.load_data_csv('AdBanners')
|
|
resp = SaoGetMAdBannersResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5a8(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_events
|
|
tbl = self.load_data_csv('Event')
|
|
resp = SaoGetMEventsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5aa(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_treasure_hunts
|
|
req = SaoGetMTreasureHuntsRequest(header, request)
|
|
tbl = self.load_data_csv('TreasureHunt')
|
|
resp = SaoGetMTreasureHuntsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5ac(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_treasure_hunt_whole_tasks
|
|
req = SaoGetMTreasureHuntWholeTasksRequest(header, request)
|
|
tbl = self.load_data_csv('TreasureHuntWholeTask')
|
|
resp = SaoGetMTreasureHuntWholeTasksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5ae(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_treasure_hunt_individual_tasks
|
|
req = SaoGetMTreasureHuntIndividualTasksRequest(header, request)
|
|
tbl = self.load_data_csv('TreasureHuntIndividualTask')
|
|
resp = SaoGetMTreasureHuntIndividualTasksResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5b0(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_treasure_hunt_special_effects
|
|
req = SaoGetMTreasureHuntSpecialEffectsRequest(header, request)
|
|
tbl = self.load_data_csv('TreasureHuntSpecialEffect')
|
|
resp = SaoGetMTreasureHuntSpecialEffectsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5b2(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_treasure_hunt_event_point_reward_common_rewards
|
|
req = SaoGetMTreasureHuntEventPointRewardCommonRewardsRequest(header, request)
|
|
tbl = self.load_data_csv('TreasureHuntEventPointRewardCommonReward')
|
|
resp = SaoGetMTreasureHuntEventPointRewardCommonRewardsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5b4(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_treasure_hunt_event_point_reward_titles
|
|
req = SaoGetMTreasureHuntEventPointRewardTitlesRequest(header, request)
|
|
tbl = self.load_data_csv('TreasureHuntEventPointRewardTitle')
|
|
resp = SaoGetMTreasureHuntEventPointRewardTitlesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5b6(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_treasure_hunt_task_texts
|
|
tbl = self.load_data_csv('TreasureHuntTaskText')
|
|
resp = SaoGetMTreasureHuntTaskTextsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5b8(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_bnid_serial_codes
|
|
tbl = self.load_data_csv('BnidSerialCodes')
|
|
resp = SaoGetMBnidSerialCodesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5ba(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_bnid_serial_code_rewards
|
|
tbl = self.load_data_csv('BnidSerialCodeRewards')
|
|
resp = SaoGetMBnidSerialCodeRewardsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5bc(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_support_log
|
|
tbl = self.load_data_csv('SupportLog')
|
|
resp = SaoGetMSupportLogResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5be(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_support_log_types
|
|
tbl = self.load_data_csv('SupportLogType')
|
|
resp = SaoGetMSupportLogTypesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5c0(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_episode_appends
|
|
tbl = self.load_data_csv('EpisodeAppends')
|
|
resp = SaoGetMEpisodeAppendsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5c2(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_defrag_match_quests
|
|
tbl = self.load_data_csv('DefragMatchQuest')
|
|
resp = SaoGetMQuestDefragMatchQuestsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5c4(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_quest_defrag_match_quest_boss_tables
|
|
tbl = self.load_data_csv('DefragMatchBossTable')
|
|
resp = SaoGetMQuestDefragMatchQuestBossTablesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5c6(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_matches
|
|
req = SaoGetMDefragMatchesRequest(header, request)
|
|
tbl = self.load_data_csv('DefragMatchs')
|
|
resp = SaoGetMDefragMatchesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5c8(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_seed
|
|
req = SaoGetMDefragMatchSeedRequest(header, request)
|
|
tbl = self.load_data_csv('DefragMatchSeed')
|
|
resp = SaoGetMDefragMatchSeedResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5ca(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_special_effects
|
|
req = SaoGetMDefragMatchSpecialEffectsRequest(header, request)
|
|
tbl = self.load_data_csv('DefragMatchSpecialEffects')
|
|
resp = SaoGetMDefragMatchSpecialEffectsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5cc(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_grades
|
|
req = SaoGetMDefragMatchGradesRequest(header, request)
|
|
tbl = self.load_data_csv('DefragMatchGrade')
|
|
resp = SaoGetMDefragMatchGradesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5ce(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_cpu_units
|
|
tbl = self.load_data_csv('DefragMatchCpuUnits')
|
|
resp = SaoGetMDefragMatchCpuUnitsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5d0(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_cpu_support_logs
|
|
tbl = self.load_data_csv('DefragMatchCpuSupportLogs')
|
|
resp = SaoGetMDefragMatchCpuSupportLogsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5d2(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_period_bonuses
|
|
req = SaoGetMDefragMatchPeriodBonusesRequest(header, request)
|
|
tbl = self.load_data_csv('DefragMatchPeriodBonuses')
|
|
resp = SaoGetMDefragMatchPeriodBonusesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5d4(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_random_bonus_tables
|
|
req = SaoGetMDefragMatchRandomBonusTablesRequest(header, request)
|
|
tbl = self.load_data_csv('DefragMatchRandomBonusTables')
|
|
resp = SaoGetMDefragMatchRandomBonusTablesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5d6(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_random_bonus_conditions
|
|
tbl = self.load_data_csv('DefragMatchRandomBonusConditions')
|
|
resp = SaoGetMDefragMatchRandomBonusConditionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5d8(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_defrag_match_rare_drops
|
|
req = SaoGetMDefragMatchRareDropsRequest(header, request)
|
|
tbl = self.load_data_csv('DefragMatchRareDrops')
|
|
resp = SaoGetMDefragMatchRareDropsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5da(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_yui_medal_shops
|
|
tbl = self.load_data_csv('YuiMedalShops')
|
|
resp = SaoGetMYuiMedalShopsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5dc(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_yui_medal_shop_items
|
|
tbl = self.load_data_csv('YuiMedalShopItems')
|
|
resp = SaoGetMYuiMedalShopItemsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5de(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_event_scenes
|
|
req = SaoGetMEventScenesRequest(header, request)
|
|
tbl = self.load_data_csv('EventScenes')
|
|
resp = SaoGetMEventScenesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5e0(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_generic_campaign_periods
|
|
tbl = self.load_data_csv('GenericCampaignPeriods')
|
|
resp = SaoGetMGenericCampaignPeriodsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5e2(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_beginner_missions
|
|
tbl = self.load_data_csv('BeginnerMissions')
|
|
resp = SaoGetMBeginnerMissionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5e4(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_beginner_mission_conditions
|
|
req = SaoGetMBeginnerMissionConditionsRequest(header, request)
|
|
tbl = self.load_data_csv('BeginnerMissionConditions')
|
|
resp = SaoGetMBeginnerMissionConditionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5e6(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_beginner_mission_rewards
|
|
req = SaoGetMBeginnerMissionRewardsRequest(header, request)
|
|
tbl = self.load_data_csv('BeginnerMissionRewards')
|
|
resp = SaoGetMBeginnerMissionRewardsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5e8(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_beginner_mission_seat_conditions
|
|
req = SaoGetMBeginnerMissionSeatConditionsRequest(header, request)
|
|
tbl = self.load_data_csv('BeginnerMissionSeatConditions')
|
|
resp = SaoGetMBeginnerMissionSeatConditionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5ea(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_beginner_mission_seat_rewards
|
|
req = SaoGetMBeginnerMissionSeatRewardsRequest(header, request)
|
|
tbl = self.load_data_csv('BeginnerMissionSeatRewards')
|
|
resp = SaoGetMBeginnerMissionSeatRewardsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5ec(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_event_items
|
|
tbl = self.load_data_csv('EventItems')
|
|
resp = SaoGetMEventItemsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5ee(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_event_monsters
|
|
req = SaoGetMEventMonstersRequest(header, request)
|
|
tbl = self.load_data_csv('EventMonsters')
|
|
resp = SaoGetMEventMonstersResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5f0(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_yui_medal_bonuses
|
|
tbl = self.load_data_csv('YuiMedalBonus')
|
|
resp = SaoGetMYuiMedalBonusesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5f2(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_yui_medal_bonus_conditions
|
|
tbl = self.load_data_csv('YuiMedalBonusCondition')
|
|
resp = SaoGetMYuiMedalBonusConditionsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5f4(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_medals
|
|
tbl = self.load_data_csv('GashaMedals')
|
|
resp = SaoGetMGashaMedalsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5f6(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_medal_types
|
|
tbl = self.load_data_csv('GashaMedalTypes')
|
|
resp = SaoGetMGashaMedalTypesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5f8(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_medal_settings
|
|
req = SaoGetMGashaMedalSettingsRequest(header, request)
|
|
tbl = self.load_data_csv('GashaMedalSettings')
|
|
resp = SaoGetMGashaMedalSettingsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5fa(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_medal_bonuses
|
|
tbl = self.load_data_csv('GashaMedalBonuses')
|
|
resp = SaoGetMGashaMedalBonusesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5fc(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_medal_shops
|
|
tbl = self.load_data_csv('GashaMedalShops')
|
|
resp = SaoGetMGashaMedalShopsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d5fe(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data/get_m_gasha_medal_shop_items
|
|
req = SaoGetMGashaMedalShopItemsRequest(header, request)
|
|
tbl = self.load_data_csv('GashaMedalShopItems')
|
|
resp = SaoGetMGashaMedalShopItemsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d600(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mres_earn_campaign_applications
|
|
tbl = self.load_data_csv('ResEarnCampaignApplications')
|
|
resp = SaoGetMResEarnCampaignApplicationsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d602(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mres_earn_campaign_application_products
|
|
req = SaoGetMResEarnCampaignApplicationProductsRequest(header, request)
|
|
tbl = self.load_data_csv('ResEarnCampaignApplicationProducts')
|
|
resp = SaoGetMResEarnCampaignApplicationProductsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d604(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mres_earn_campaign_shops
|
|
tbl = self.load_data_csv('ResEarnCampaignShops')
|
|
resp = SaoGetMResEarnCampaignShopsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d606(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mres_earn_campaign_shop_items
|
|
req = SaoGetMResEarnCampaignShopItemsRequest(header, request)
|
|
tbl = self.load_data_csv('ResEarnCampaignShopItems')
|
|
resp = SaoGetMResEarnCampaignShopItemsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d608(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mpaying_yui_medal_bonuses
|
|
tbl = self.load_data_csv('PayingYuiMedalBonuses')
|
|
resp = SaoGetMPayingYuiMedalBonusesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d60a(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mac_login_bonuses
|
|
tbl = self.load_data_csv('AcLoginBonuses')
|
|
resp = SaoGetMAcLoginBonusesResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d60c(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mplay_campaigns
|
|
tbl = self.load_data_csv('PlayCampaigns')
|
|
resp = SaoGetMPlayCampaignsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d60e(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mplay_campaign_rewards
|
|
req = SaoGetMPlayCampaignRewardsRequest(header, request)
|
|
tbl = self.load_data_csv('PlayCampaignRewards')
|
|
resp = SaoGetMPlayCampaignRewardsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d610(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mgasha_free_campaigns
|
|
tbl = self.load_data_csv('GashaFreeCampaigns')
|
|
resp = SaoGetMGashaFreeCampaignsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d612(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mquest_drop_boost_campaigns
|
|
tbl = self.load_data_csv('QuestDropBoostCampaigns')
|
|
resp = SaoGetMQuestDropBoostCampaignsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d614(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mfirst_ticket_purchase_campaigns
|
|
tbl = self.load_data_csv('FirstTicketPurchaseCampaigns')
|
|
resp = SaoGetMFirstTicketPurchaseCampaignsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d616(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mlinked_site_reg_campaigns
|
|
tbl = self.load_data_csv('LinkedSiteRegCampaigns')
|
|
resp = SaoGetMLinkedSiteRegCampaignsResponse(tbl)
|
|
return resp.make()
|
|
|
|
async def handle_d618(self, header: SaoRequestHeader, request: bytes, src_ip: str) -> bytes:
|
|
# master_data2/get_mlinked_site_reg_campaign_rewards
|
|
req = SaoGetMLinkedSiteRegCampaignRewardsRequest(header, request)
|
|
tbl = self.load_data_csv('LinkedSiteRegCampaignRewards')
|
|
resp = SaoGetMLinkedSiteRegCampaignRewardsResponse(tbl)
|
|
return resp.make()
|