forked from Hay1tsme/artemis
reformat with black in preperation for merge to master
This commit is contained in:
parent
9d23d59e43
commit
238d437519
@ -105,9 +105,11 @@ class AllnetServlet:
|
|||||||
|
|
||||||
resp.stat = 0
|
resp.stat = 0
|
||||||
return self.dict_to_http_form_string([vars(resp)])
|
return self.dict_to_http_form_string([vars(resp)])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.info(f"Allowed unknown game {req.game_id} v{req.ver} to authenticate from {request_ip} due to 'is_develop' being enabled. S/N: {req.serial}")
|
self.logger.info(
|
||||||
|
f"Allowed unknown game {req.game_id} v{req.ver} to authenticate from {request_ip} due to 'is_develop' being enabled. S/N: {req.serial}"
|
||||||
|
)
|
||||||
resp.uri = f"http://{self.config.title.hostname}:{self.config.title.port}/{req.game_id}/{req.ver.replace('.', '')}/"
|
resp.uri = f"http://{self.config.title.hostname}:{self.config.title.port}/{req.game_id}/{req.ver.replace('.', '')}/"
|
||||||
resp.host = f"{self.config.title.hostname}:{self.config.title.port}"
|
resp.host = f"{self.config.title.hostname}:{self.config.title.port}"
|
||||||
return self.dict_to_http_form_string([vars(resp)])
|
return self.dict_to_http_form_string([vars(resp)])
|
||||||
@ -189,35 +191,49 @@ class AllnetServlet:
|
|||||||
self.logger.error(e)
|
self.logger.error(e)
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
self.logger.info(f"DownloadOrder from {request_ip} -> {req.game_id} v{req.ver} serial {req.serial}")
|
self.logger.info(
|
||||||
|
f"DownloadOrder from {request_ip} -> {req.game_id} v{req.ver} serial {req.serial}"
|
||||||
|
)
|
||||||
resp = AllnetDownloadOrderResponse()
|
resp = AllnetDownloadOrderResponse()
|
||||||
|
|
||||||
if not self.config.allnet.allow_online_updates or not self.config.allnet.update_cfg_folder:
|
if (
|
||||||
|
not self.config.allnet.allow_online_updates
|
||||||
|
or not self.config.allnet.update_cfg_folder
|
||||||
|
):
|
||||||
return self.dict_to_http_form_string([vars(resp)])
|
return self.dict_to_http_form_string([vars(resp)])
|
||||||
|
|
||||||
else: # TODO: Keychip check
|
else: # TODO: Keychip check
|
||||||
if path.exists(f"{self.config.allnet.update_cfg_folder}/{req.game_id}-{req.ver}-app.ini"):
|
if path.exists(
|
||||||
|
f"{self.config.allnet.update_cfg_folder}/{req.game_id}-{req.ver}-app.ini"
|
||||||
|
):
|
||||||
resp.uri = f"http://{self.config.title.hostname}:{self.config.title.port}/dl/ini/{req.game_id}-{req.ver.replace('.', '')}-app.ini"
|
resp.uri = f"http://{self.config.title.hostname}:{self.config.title.port}/dl/ini/{req.game_id}-{req.ver.replace('.', '')}-app.ini"
|
||||||
|
|
||||||
if path.exists(f"{self.config.allnet.update_cfg_folder}/{req.game_id}-{req.ver}-opt.ini"):
|
if path.exists(
|
||||||
|
f"{self.config.allnet.update_cfg_folder}/{req.game_id}-{req.ver}-opt.ini"
|
||||||
|
):
|
||||||
resp.uri += f"|http://{self.config.title.hostname}:{self.config.title.port}/dl/ini/{req.game_id}-{req.ver.replace('.', '')}-opt.ini"
|
resp.uri += f"|http://{self.config.title.hostname}:{self.config.title.port}/dl/ini/{req.game_id}-{req.ver.replace('.', '')}-opt.ini"
|
||||||
|
|
||||||
self.logger.debug(f"Sending download uri {resp.uri}")
|
self.logger.debug(f"Sending download uri {resp.uri}")
|
||||||
return self.dict_to_http_form_string([vars(resp)])
|
return self.dict_to_http_form_string([vars(resp)])
|
||||||
|
|
||||||
def handle_dlorder_ini(self, request:Request, match: Dict) -> bytes:
|
def handle_dlorder_ini(self, request: Request, match: Dict) -> bytes:
|
||||||
if "file" not in match: return b""
|
if "file" not in match:
|
||||||
|
return b""
|
||||||
|
|
||||||
|
req_file = match["file"].replace("%0A", "")
|
||||||
|
|
||||||
req_file = match['file'].replace('%0A', '')
|
|
||||||
|
|
||||||
if path.exists(f"{self.config.allnet.update_cfg_folder}/{req_file}"):
|
if path.exists(f"{self.config.allnet.update_cfg_folder}/{req_file}"):
|
||||||
return open(f"{self.config.allnet.update_cfg_folder}/{req_file}", "rb").read()
|
return open(
|
||||||
|
f"{self.config.allnet.update_cfg_folder}/{req_file}", "rb"
|
||||||
|
).read()
|
||||||
|
|
||||||
self.logger.info(f"DL INI File {req_file} not found")
|
self.logger.info(f"DL INI File {req_file} not found")
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
def handle_dlorder_report(self, request:Request, match: Dict) -> bytes:
|
def handle_dlorder_report(self, request: Request, match: Dict) -> bytes:
|
||||||
self.logger.info(f"DLI Report from {Utils.get_ip_addr(request)}: {request.content.getvalue()}")
|
self.logger.info(
|
||||||
|
f"DLI Report from {Utils.get_ip_addr(request)}: {request.content.getvalue()}"
|
||||||
|
)
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
def handle_billing_request(self, request: Request, _: Dict):
|
def handle_billing_request(self, request: Request, _: Dict):
|
||||||
|
@ -194,6 +194,7 @@ class AllnetConfig:
|
|||||||
self.__config, "core", "allnet", "update_cfg_folder", default=""
|
self.__config, "core", "allnet", "update_cfg_folder", default=""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BillingConfig:
|
class BillingConfig:
|
||||||
def __init__(self, parent_config: "CoreConfig") -> None:
|
def __init__(self, parent_config: "CoreConfig") -> None:
|
||||||
self.__config = parent_config
|
self.__config = parent_config
|
||||||
|
@ -71,7 +71,9 @@ class Data:
|
|||||||
games = Utils.get_all_titles()
|
games = Utils.get_all_titles()
|
||||||
for game_dir, game_mod in games.items():
|
for game_dir, game_mod in games.items():
|
||||||
try:
|
try:
|
||||||
if hasattr(game_mod, "database") and hasattr(game_mod, "current_schema_version"):
|
if hasattr(game_mod, "database") and hasattr(
|
||||||
|
game_mod, "current_schema_version"
|
||||||
|
):
|
||||||
game_mod.database(self.config)
|
game_mod.database(self.config)
|
||||||
metadata.create_all(self.__engine.connect())
|
metadata.create_all(self.__engine.connect())
|
||||||
|
|
||||||
@ -135,21 +137,26 @@ class Data:
|
|||||||
if version is None:
|
if version is None:
|
||||||
if not game == "CORE":
|
if not game == "CORE":
|
||||||
titles = Utils.get_all_titles()
|
titles = Utils.get_all_titles()
|
||||||
|
|
||||||
for folder, mod in titles.items():
|
for folder, mod in titles.items():
|
||||||
if not mod.game_codes[0] == game: continue
|
if not mod.game_codes[0] == game:
|
||||||
|
continue
|
||||||
|
|
||||||
if hasattr(mod, "current_schema_version"):
|
if hasattr(mod, "current_schema_version"):
|
||||||
version = mod.current_schema_version
|
version = mod.current_schema_version
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.warn(f"current_schema_version not found for {folder}")
|
self.logger.warn(
|
||||||
|
f"current_schema_version not found for {folder}"
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
version = self.current_schema_version
|
version = self.current_schema_version
|
||||||
|
|
||||||
if version is None:
|
if version is None:
|
||||||
self.logger.warn(f"Could not determine latest version for {game}, please specify --version")
|
self.logger.warn(
|
||||||
|
f"Could not determine latest version for {game}, please specify --version"
|
||||||
|
)
|
||||||
|
|
||||||
if old_ver is None:
|
if old_ver is None:
|
||||||
self.logger.error(
|
self.logger.error(
|
||||||
@ -184,7 +191,7 @@ class Data:
|
|||||||
if result is None:
|
if result is None:
|
||||||
self.logger.error("Error execuing sql script!")
|
self.logger.error("Error execuing sql script!")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for x in range(old_ver, version, -1):
|
for x in range(old_ver, version, -1):
|
||||||
if not os.path.exists(
|
if not os.path.exists(
|
||||||
@ -285,13 +292,13 @@ class Data:
|
|||||||
if all_game_versions is None:
|
if all_game_versions is None:
|
||||||
self.logger.warn("Failed to get schema versions")
|
self.logger.warn("Failed to get schema versions")
|
||||||
return
|
return
|
||||||
|
|
||||||
all_games = Utils.get_all_titles()
|
all_games = Utils.get_all_titles()
|
||||||
all_games_list: Dict[str, int] = {}
|
all_games_list: Dict[str, int] = {}
|
||||||
for _, mod in all_games.items():
|
for _, mod in all_games.items():
|
||||||
if hasattr(mod, "current_schema_version"):
|
if hasattr(mod, "current_schema_version"):
|
||||||
all_games_list[mod.game_codes[0]] = mod.current_schema_version
|
all_games_list[mod.game_codes[0]] = mod.current_schema_version
|
||||||
|
|
||||||
for x in all_game_versions:
|
for x in all_game_versions:
|
||||||
failed = False
|
failed = False
|
||||||
game = x["game"].upper()
|
game = x["game"].upper()
|
||||||
@ -299,27 +306,30 @@ class Data:
|
|||||||
latest_ver = all_games_list.get(game, 1)
|
latest_ver = all_games_list.get(game, 1)
|
||||||
if game == "CORE":
|
if game == "CORE":
|
||||||
latest_ver = self.current_schema_version
|
latest_ver = self.current_schema_version
|
||||||
|
|
||||||
if update_ver == latest_ver:
|
if update_ver == latest_ver:
|
||||||
self.logger.info(f"{game} is already latest version")
|
self.logger.info(f"{game} is already latest version")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for y in range(update_ver + 1, latest_ver + 1):
|
for y in range(update_ver + 1, latest_ver + 1):
|
||||||
if os.path.exists(f"core/data/schema/versions/{game}_{y}_upgrade.sql"):
|
if os.path.exists(f"core/data/schema/versions/{game}_{y}_upgrade.sql"):
|
||||||
with open(
|
with open(
|
||||||
f"core/data/schema/versions/{game}_{y}_upgrade.sql",
|
f"core/data/schema/versions/{game}_{y}_upgrade.sql",
|
||||||
"r",
|
"r",
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
) as f:
|
) as f:
|
||||||
sql = f.read()
|
sql = f.read()
|
||||||
|
|
||||||
result = self.base.execute(sql)
|
result = self.base.execute(sql)
|
||||||
if result is None:
|
if result is None:
|
||||||
self.logger.error(f"Error execuing sql script for game {game} v{y}!")
|
self.logger.error(
|
||||||
|
f"Error execuing sql script for game {game} v{y}!"
|
||||||
|
)
|
||||||
failed = True
|
failed = True
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self.logger.warning(f"Could not find script {game}_{y}_upgrade.sql")
|
self.logger.warning(f"Could not find script {game}_{y}_upgrade.sql")
|
||||||
failed = True
|
failed = True
|
||||||
|
|
||||||
if not failed: self.base.set_schema_ver(latest_ver, game)
|
if not failed:
|
||||||
|
self.base.set_schema_ver(latest_ver, game)
|
||||||
|
@ -81,7 +81,7 @@ class BaseData:
|
|||||||
Generate a random 5-7 digit id
|
Generate a random 5-7 digit id
|
||||||
"""
|
"""
|
||||||
return randrange(10000, 9999999)
|
return randrange(10000, 9999999)
|
||||||
|
|
||||||
def get_all_schema_vers(self) -> Optional[List[Row]]:
|
def get_all_schema_vers(self) -> Optional[List[Row]]:
|
||||||
sql = select(schema_ver)
|
sql = select(schema_ver)
|
||||||
|
|
||||||
|
@ -66,14 +66,16 @@ class FrontendServlet(resource.Resource):
|
|||||||
fe_game = FE_Game(cfg, self.environment)
|
fe_game = FE_Game(cfg, self.environment)
|
||||||
games = Utils.get_all_titles()
|
games = Utils.get_all_titles()
|
||||||
for game_dir, game_mod in games.items():
|
for game_dir, game_mod in games.items():
|
||||||
if hasattr(game_mod, "frontend"):
|
if hasattr(game_mod, "frontend"):
|
||||||
try:
|
try:
|
||||||
game_fe = game_mod.frontend(cfg, self.environment, config_dir)
|
game_fe = game_mod.frontend(cfg, self.environment, config_dir)
|
||||||
self.game_list.append({"url": game_dir, "name": game_fe.nav_name})
|
self.game_list.append({"url": game_dir, "name": game_fe.nav_name})
|
||||||
fe_game.putChild(game_dir.encode(), game_fe)
|
fe_game.putChild(game_dir.encode(), game_fe)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Failed to import frontend from {game_dir} because {e}")
|
self.logger.error(
|
||||||
|
f"Failed to import frontend from {game_dir} because {e}"
|
||||||
|
)
|
||||||
|
|
||||||
self.environment.globals["game_list"] = self.game_list
|
self.environment.globals["game_list"] = self.game_list
|
||||||
self.putChild(b"gate", FE_Gate(cfg, self.environment))
|
self.putChild(b"gate", FE_Gate(cfg, self.environment))
|
||||||
|
@ -46,9 +46,7 @@ class MuchaServlet:
|
|||||||
if enabled:
|
if enabled:
|
||||||
self.mucha_registry.append(game_cd)
|
self.mucha_registry.append(game_cd)
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(f"Serving {len(self.mucha_registry)} games")
|
||||||
f"Serving {len(self.mucha_registry)} games"
|
|
||||||
)
|
|
||||||
|
|
||||||
def handle_boardauth(self, request: Request, _: Dict) -> bytes:
|
def handle_boardauth(self, request: Request, _: Dict) -> bytes:
|
||||||
req_dict = self.mucha_preprocess(request.content.getvalue())
|
req_dict = self.mucha_preprocess(request.content.getvalue())
|
||||||
@ -62,9 +60,7 @@ class MuchaServlet:
|
|||||||
|
|
||||||
req = MuchaAuthRequest(req_dict)
|
req = MuchaAuthRequest(req_dict)
|
||||||
self.logger.debug(f"Mucha request {vars(req)}")
|
self.logger.debug(f"Mucha request {vars(req)}")
|
||||||
self.logger.info(
|
self.logger.info(f"Boardauth request from {client_ip} for {req.gameVer}")
|
||||||
f"Boardauth request from {client_ip} for {req.gameVer}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if req.gameCd not in self.mucha_registry:
|
if req.gameCd not in self.mucha_registry:
|
||||||
self.logger.warn(f"Unknown gameCd {req.gameCd}")
|
self.logger.warn(f"Unknown gameCd {req.gameCd}")
|
||||||
@ -92,9 +88,7 @@ class MuchaServlet:
|
|||||||
|
|
||||||
req = MuchaUpdateRequest(req_dict)
|
req = MuchaUpdateRequest(req_dict)
|
||||||
self.logger.debug(f"Mucha request {vars(req)}")
|
self.logger.debug(f"Mucha request {vars(req)}")
|
||||||
self.logger.info(
|
self.logger.info(f"Updatecheck request from {client_ip} for {req.gameVer}")
|
||||||
f"Updatecheck request from {client_ip} for {req.gameVer}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if req.gameCd not in self.mucha_registry:
|
if req.gameCd not in self.mucha_registry:
|
||||||
self.logger.warn(f"Unknown gameCd {req.gameCd}")
|
self.logger.warn(f"Unknown gameCd {req.gameCd}")
|
||||||
|
@ -16,14 +16,20 @@ class Utils:
|
|||||||
if not dir.startswith("__"):
|
if not dir.startswith("__"):
|
||||||
try:
|
try:
|
||||||
mod = importlib.import_module(f"titles.{dir}")
|
mod = importlib.import_module(f"titles.{dir}")
|
||||||
if hasattr(mod, "game_codes") and hasattr(mod, "index"): # Minimum required to function
|
if hasattr(mod, "game_codes") and hasattr(
|
||||||
|
mod, "index"
|
||||||
|
): # Minimum required to function
|
||||||
ret[dir] = mod
|
ret[dir] = mod
|
||||||
|
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
logging.getLogger("core").error(f"get_all_titles: {dir} - {e}")
|
logging.getLogger("core").error(f"get_all_titles: {dir} - {e}")
|
||||||
raise
|
raise
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ip_addr(cls, req: Request) -> str:
|
def get_ip_addr(cls, req: Request) -> str:
|
||||||
return req.getAllHeaders()[b"x-forwarded-for"].decode() if b"x-forwarded-for" in req.getAllHeaders() else req.getClientAddress().host
|
return (
|
||||||
|
req.getAllHeaders()[b"x-forwarded-for"].decode()
|
||||||
|
if b"x-forwarded-for" in req.getAllHeaders()
|
||||||
|
else req.getClientAddress().host
|
||||||
|
)
|
||||||
|
19
dbutils.py
19
dbutils.py
@ -34,12 +34,12 @@ if __name__ == "__main__":
|
|||||||
cfg = CoreConfig()
|
cfg = CoreConfig()
|
||||||
if path.exists(f"{args.config}/core.yaml"):
|
if path.exists(f"{args.config}/core.yaml"):
|
||||||
cfg_dict = yaml.safe_load(open(f"{args.config}/core.yaml"))
|
cfg_dict = yaml.safe_load(open(f"{args.config}/core.yaml"))
|
||||||
cfg_dict.get('database', {})['loglevel'] = 'info'
|
cfg_dict.get("database", {})["loglevel"] = "info"
|
||||||
cfg.update(cfg_dict)
|
cfg.update(cfg_dict)
|
||||||
|
|
||||||
if not path.exists(cfg.server.log_dir):
|
if not path.exists(cfg.server.log_dir):
|
||||||
mkdir(cfg.server.log_dir)
|
mkdir(cfg.server.log_dir)
|
||||||
|
|
||||||
if not access(cfg.server.log_dir, W_OK):
|
if not access(cfg.server.log_dir, W_OK):
|
||||||
print(
|
print(
|
||||||
f"Log directory {cfg.server.log_dir} NOT writable, please check permissions"
|
f"Log directory {cfg.server.log_dir} NOT writable, please check permissions"
|
||||||
@ -47,7 +47,6 @@ if __name__ == "__main__":
|
|||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
data = Data(cfg)
|
data = Data(cfg)
|
||||||
|
|
||||||
|
|
||||||
if args.action == "create":
|
if args.action == "create":
|
||||||
data.create_database()
|
data.create_database()
|
||||||
@ -61,10 +60,18 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
if args.game is None:
|
if args.game is None:
|
||||||
data.logger.warn("No game set, upgrading core schema")
|
data.logger.warn("No game set, upgrading core schema")
|
||||||
data.migrate_database("CORE", int(args.version) if args.version is not None else None, args.action)
|
data.migrate_database(
|
||||||
|
"CORE",
|
||||||
|
int(args.version) if args.version is not None else None,
|
||||||
|
args.action,
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
data.migrate_database(args.game, int(args.version) if args.version is not None else None, args.action)
|
data.migrate_database(
|
||||||
|
args.game,
|
||||||
|
int(args.version) if args.version is not None else None,
|
||||||
|
args.action,
|
||||||
|
)
|
||||||
|
|
||||||
elif args.action == "autoupgrade":
|
elif args.action == "autoupgrade":
|
||||||
data.autoupgrade()
|
data.autoupgrade()
|
||||||
|
3
index.py
3
index.py
@ -25,7 +25,7 @@ class HttpDispatcher(resource.Resource):
|
|||||||
self.allnet = AllnetServlet(cfg, config_dir)
|
self.allnet = AllnetServlet(cfg, config_dir)
|
||||||
self.title = TitleServlet(cfg, config_dir)
|
self.title = TitleServlet(cfg, config_dir)
|
||||||
self.mucha = MuchaServlet(cfg, config_dir)
|
self.mucha = MuchaServlet(cfg, config_dir)
|
||||||
|
|
||||||
self.map_get.connect(
|
self.map_get.connect(
|
||||||
"allnet_downloadorder_ini",
|
"allnet_downloadorder_ini",
|
||||||
"/dl/ini/{file}",
|
"/dl/ini/{file}",
|
||||||
@ -109,7 +109,6 @@ class HttpDispatcher(resource.Resource):
|
|||||||
conditions=dict(method=["POST"]),
|
conditions=dict(method=["POST"]),
|
||||||
requirements=dict(game=R"S..."),
|
requirements=dict(game=R"S..."),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def render_GET(self, request: Request) -> bytes:
|
def render_GET(self, request: Request) -> bytes:
|
||||||
self.logger.debug(request.uri)
|
self.logger.debug(request.uri)
|
||||||
|
3
read.py
3
read.py
@ -135,8 +135,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
for dir, mod in titles.items():
|
for dir, mod in titles.items():
|
||||||
if args.series in mod.game_codes:
|
if args.series in mod.game_codes:
|
||||||
handler = mod.reader(config, args.version,
|
handler = mod.reader(config, args.version, bin_arg, opt_arg, args.extra)
|
||||||
bin_arg, opt_arg, args.extra)
|
|
||||||
handler.read()
|
handler.read()
|
||||||
|
|
||||||
logger.info("Done")
|
logger.info("Done")
|
||||||
|
@ -82,21 +82,33 @@ class ChuniServlet:
|
|||||||
level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str
|
level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str
|
||||||
)
|
)
|
||||||
self.logger.inited = True
|
self.logger.inited = True
|
||||||
|
|
||||||
for version, keys in self.game_cfg.crypto.keys.items():
|
for version, keys in self.game_cfg.crypto.keys.items():
|
||||||
if len(keys) < 3:
|
if len(keys) < 3:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.hash_table[version] = {}
|
self.hash_table[version] = {}
|
||||||
|
|
||||||
method_list = [method for method in dir(self.versions[version]) if not method.startswith('__')]
|
method_list = [
|
||||||
|
method
|
||||||
|
for method in dir(self.versions[version])
|
||||||
|
if not method.startswith("__")
|
||||||
|
]
|
||||||
for method in method_list:
|
for method in method_list:
|
||||||
method_fixed = inflection.camelize(method)[6:-7]
|
method_fixed = inflection.camelize(method)[6:-7]
|
||||||
hash = PBKDF2(method_fixed, bytes.fromhex(keys[2]), 128, count=44, hmac_hash_module=SHA1)
|
hash = PBKDF2(
|
||||||
|
method_fixed,
|
||||||
|
bytes.fromhex(keys[2]),
|
||||||
|
128,
|
||||||
|
count=44,
|
||||||
|
hmac_hash_module=SHA1,
|
||||||
|
)
|
||||||
|
|
||||||
self.hash_table[version][hash.hex()] = method_fixed
|
self.hash_table[version][hash.hex()] = method_fixed
|
||||||
|
|
||||||
self.logger.debug(f"Hashed v{version} method {method_fixed} with {bytes.fromhex(keys[2])} to get {hash.hex()}")
|
self.logger.debug(
|
||||||
|
f"Hashed v{version} method {method_fixed} with {bytes.fromhex(keys[2])} to get {hash.hex()}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_allnet_info(
|
def get_allnet_info(
|
||||||
@ -164,18 +176,22 @@ class ChuniServlet:
|
|||||||
# technically not 0
|
# technically not 0
|
||||||
if internal_ver < ChuniConstants.VER_CHUNITHM_NEW:
|
if internal_ver < ChuniConstants.VER_CHUNITHM_NEW:
|
||||||
endpoint = request.getHeader("User-Agent").split("#")[0]
|
endpoint = request.getHeader("User-Agent").split("#")[0]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if internal_ver not in self.hash_table:
|
if internal_ver not in self.hash_table:
|
||||||
self.logger.error(f"v{version} does not support encryption or no keys entered")
|
self.logger.error(
|
||||||
|
f"v{version} does not support encryption or no keys entered"
|
||||||
|
)
|
||||||
return zlib.compress(b'{"stat": "0"}')
|
return zlib.compress(b'{"stat": "0"}')
|
||||||
|
|
||||||
elif endpoint.lower() not in self.hash_table[internal_ver]:
|
elif endpoint.lower() not in self.hash_table[internal_ver]:
|
||||||
self.logger.error(f"No hash found for v{version} endpoint {endpoint}")
|
self.logger.error(
|
||||||
|
f"No hash found for v{version} endpoint {endpoint}"
|
||||||
|
)
|
||||||
return zlib.compress(b'{"stat": "0"}')
|
return zlib.compress(b'{"stat": "0"}')
|
||||||
|
|
||||||
endpoint = self.hash_table[internal_ver][endpoint.lower()]
|
endpoint = self.hash_table[internal_ver][endpoint.lower()]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
crypt = AES.new(
|
crypt = AES.new(
|
||||||
bytes.fromhex(self.game_cfg.crypto.keys[internal_ver][0]),
|
bytes.fromhex(self.game_cfg.crypto.keys[internal_ver][0]),
|
||||||
@ -193,7 +209,11 @@ class ChuniServlet:
|
|||||||
|
|
||||||
encrtped = True
|
encrtped = True
|
||||||
|
|
||||||
if not encrtped and self.game_cfg.crypto.encrypted_only and internal_ver >= ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS:
|
if (
|
||||||
|
not encrtped
|
||||||
|
and self.game_cfg.crypto.encrypted_only
|
||||||
|
and internal_ver >= ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS
|
||||||
|
):
|
||||||
self.logger.error(
|
self.logger.error(
|
||||||
f"Unencrypted v{version} {endpoint} request, but config is set to encrypted only: {req_raw}"
|
f"Unencrypted v{version} {endpoint} request, but config is set to encrypted only: {req_raw}"
|
||||||
)
|
)
|
||||||
@ -210,9 +230,7 @@ class ChuniServlet:
|
|||||||
|
|
||||||
req_data = json.loads(unzip)
|
req_data = json.loads(unzip)
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(f"v{version} {endpoint} request from {client_ip}")
|
||||||
f"v{version} {endpoint} request from {client_ip}"
|
|
||||||
)
|
|
||||||
self.logger.debug(req_data)
|
self.logger.debug(req_data)
|
||||||
|
|
||||||
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
|
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
|
||||||
|
@ -13,8 +13,12 @@ class ChuniNewPlus(ChuniNew):
|
|||||||
|
|
||||||
def handle_get_game_setting_api_request(self, data: Dict) -> Dict:
|
def handle_get_game_setting_api_request(self, data: Dict) -> Dict:
|
||||||
ret = super().handle_get_game_setting_api_request(data)
|
ret = super().handle_get_game_setting_api_request(data)
|
||||||
ret["gameSetting"]["romVersion"] = self.game_cfg.version.version(self.version)["rom"]
|
ret["gameSetting"]["romVersion"] = self.game_cfg.version.version(self.version)[
|
||||||
ret["gameSetting"]["dataVersion"] = self.game_cfg.version.version(self.version)["data"]
|
"rom"
|
||||||
|
]
|
||||||
|
ret["gameSetting"]["dataVersion"] = self.game_cfg.version.version(self.version)[
|
||||||
|
"data"
|
||||||
|
]
|
||||||
ret["gameSetting"][
|
ret["gameSetting"][
|
||||||
"matchingUri"
|
"matchingUri"
|
||||||
] = f"http://{self.core_cfg.title.hostname}:{self.core_cfg.title.port}/SDHD/205/ChuniServlet/"
|
] = f"http://{self.core_cfg.title.hostname}:{self.core_cfg.title.port}/SDHD/205/ChuniServlet/"
|
||||||
|
@ -200,7 +200,9 @@ class ChuniStaticData(BaseData):
|
|||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
def get_login_bonus(
|
def get_login_bonus(
|
||||||
self, version: int, preset_id: int,
|
self,
|
||||||
|
version: int,
|
||||||
|
preset_id: int,
|
||||||
) -> Optional[List[Row]]:
|
) -> Optional[List[Row]]:
|
||||||
sql = login_bonus.select(
|
sql = login_bonus.select(
|
||||||
and_(
|
and_(
|
||||||
|
@ -109,9 +109,7 @@ class CardMakerServlet:
|
|||||||
|
|
||||||
req_data = json.loads(unzip)
|
req_data = json.loads(unzip)
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(f"v{version} {endpoint} request from {client_ip}")
|
||||||
f"v{version} {endpoint} request from {client_ip}"
|
|
||||||
)
|
|
||||||
self.logger.debug(req_data)
|
self.logger.debug(req_data)
|
||||||
|
|
||||||
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
|
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
|
||||||
|
@ -90,7 +90,7 @@ class CardMakerReader(BaseReader):
|
|||||||
"v2_00": ChuniConstants.VER_CHUNITHM_NEW,
|
"v2_00": ChuniConstants.VER_CHUNITHM_NEW,
|
||||||
"v2_05": ChuniConstants.VER_CHUNITHM_NEW_PLUS,
|
"v2_05": ChuniConstants.VER_CHUNITHM_NEW_PLUS,
|
||||||
# Chunithm SUN, ignore for now
|
# Chunithm SUN, ignore for now
|
||||||
"v2_10": ChuniConstants.VER_CHUNITHM_NEW_PLUS + 1
|
"v2_10": ChuniConstants.VER_CHUNITHM_NEW_PLUS + 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
for root, dirs, files in os.walk(base_dir):
|
for root, dirs, files in os.walk(base_dir):
|
||||||
|
@ -101,9 +101,7 @@ class CxbServlet(resource.Resource):
|
|||||||
f"Ready on ports {self.game_cfg.server.port} & {self.game_cfg.server.port_secure}"
|
f"Ready on ports {self.game_cfg.server.port} & {self.game_cfg.server.port_secure}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.logger.info(
|
self.logger.info(f"Ready on port {self.game_cfg.server.port}")
|
||||||
f"Ready on port {self.game_cfg.server.port}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def render_POST(self, request: Request):
|
def render_POST(self, request: Request):
|
||||||
version = 0
|
version = 0
|
||||||
|
@ -46,15 +46,21 @@ class IDZPortsConfig:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def userdb(self) -> int:
|
def userdb(self) -> int:
|
||||||
return CoreConfig.get_config_field(self.__config, "idz", "ports", "userdb", default=10000)
|
return CoreConfig.get_config_field(
|
||||||
|
self.__config, "idz", "ports", "userdb", default=10000
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def match(self) -> int:
|
def match(self) -> int:
|
||||||
return CoreConfig.get_config_field(self.__config, "idz", "ports", "match", default=10010)
|
return CoreConfig.get_config_field(
|
||||||
|
self.__config, "idz", "ports", "match", default=10010
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def echo(self) -> int:
|
def echo(self) -> int:
|
||||||
return CoreConfig.get_config_field(self.__config, "idz", "ports", "echo", default=10020)
|
return CoreConfig.get_config_field(
|
||||||
|
self.__config, "idz", "ports", "echo", default=10020
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class IDZConfig(dict):
|
class IDZConfig(dict):
|
||||||
@ -64,4 +70,4 @@ class IDZConfig(dict):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def rsa_keys(self) -> List[Dict]:
|
def rsa_keys(self) -> List[Dict]:
|
||||||
return CoreConfig.get_config_field(self, "idz", "rsa_keys", default=[])
|
return CoreConfig.get_config_field(self, "idz", "rsa_keys", default=[])
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class IDZConstants:
|
class IDZConstants:
|
||||||
GAME_CODE = "SDDF"
|
GAME_CODE = "SDDF"
|
||||||
|
|
||||||
@ -22,14 +23,26 @@ class IDZConstants:
|
|||||||
LOCKED = 0
|
LOCKED = 0
|
||||||
UNLOCKED = 1
|
UNLOCKED = 1
|
||||||
OLD = 2
|
OLD = 2
|
||||||
|
|
||||||
HASH_LUT = [
|
HASH_LUT = [
|
||||||
# No clue
|
# No clue
|
||||||
0x9C82E674, 0x5A4738D9, 0x8B8D7AE0, 0x29EC9D81,
|
0x9C82E674,
|
||||||
|
0x5A4738D9,
|
||||||
|
0x8B8D7AE0,
|
||||||
|
0x29EC9D81,
|
||||||
# These three are from AES TE0
|
# These three are from AES TE0
|
||||||
0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E,
|
0x1209091B,
|
||||||
0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB,
|
0x1D83839E,
|
||||||
0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE,
|
0x582C2C74,
|
||||||
|
0x341A1A2E,
|
||||||
|
0x361B1B2D,
|
||||||
|
0xDC6E6EB2,
|
||||||
|
0xB45A5AEE,
|
||||||
|
0x5BA0A0FB,
|
||||||
|
0xA45252F6,
|
||||||
|
0x763B3B4D,
|
||||||
|
0xB7D6D661,
|
||||||
|
0x7DB3B3CE,
|
||||||
]
|
]
|
||||||
HASH_NUM = 0
|
HASH_NUM = 0
|
||||||
HASH_MUL = [5, 7, 11, 12][HASH_NUM]
|
HASH_MUL = [5, 7, 11, 12][HASH_NUM]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from core.data import Data
|
from core.data import Data
|
||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZData(Data):
|
class IDZData(Data):
|
||||||
def __init__(self, cfg: CoreConfig) -> None:
|
def __init__(self, cfg: CoreConfig) -> None:
|
||||||
super().__init__(cfg)
|
super().__init__(cfg)
|
||||||
|
@ -4,6 +4,7 @@ import logging
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from .config import IDZConfig
|
from .config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZEcho(DatagramProtocol):
|
class IDZEcho(DatagramProtocol):
|
||||||
def __init__(self, cfg: CoreConfig, game_cfg: IDZConfig) -> None:
|
def __init__(self, cfg: CoreConfig, game_cfg: IDZConfig) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -12,5 +13,7 @@ class IDZEcho(DatagramProtocol):
|
|||||||
self.logger = logging.getLogger("idz")
|
self.logger = logging.getLogger("idz")
|
||||||
|
|
||||||
def datagramReceived(self, data, addr):
|
def datagramReceived(self, data, addr):
|
||||||
self.logger.debug(f"Echo from from {addr[0]}:{addr[1]} -> {self.transport.getHost().port} - {data.hex()}")
|
self.logger.debug(
|
||||||
self.transport.write(data, addr)
|
f"Echo from from {addr[0]}:{addr[1]} -> {self.transport.getHost().port} - {data.hex()}"
|
||||||
|
)
|
||||||
|
self.transport.write(data, addr)
|
||||||
|
@ -5,7 +5,8 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
class IDZHandlerBase():
|
|
||||||
|
class IDZHandlerBase:
|
||||||
name = "generic"
|
name = "generic"
|
||||||
cmd_codes = [0x0000] * IDZConstants.NUM_VERS
|
cmd_codes = [0x0000] * IDZConstants.NUM_VERS
|
||||||
rsp_codes = [0x0001] * IDZConstants.NUM_VERS
|
rsp_codes = [0x0001] * IDZConstants.NUM_VERS
|
||||||
@ -18,8 +19,8 @@ class IDZHandlerBase():
|
|||||||
self.game = IDZConstants.GAME_CODE
|
self.game = IDZConstants.GAME_CODE
|
||||||
self.version = version
|
self.version = version
|
||||||
self.size = 0x30
|
self.size = 0x30
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = bytearray([0] * self.size)
|
ret = bytearray([0] * self.size)
|
||||||
struct.pack_into("<H", ret, 0x0, self.rsp_codes[self.version])
|
struct.pack_into("<H", ret, 0x0, self.rsp_codes[self.version])
|
||||||
return ret
|
return ret
|
||||||
|
@ -4,15 +4,16 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerCheckTeamName(IDZHandlerBase):
|
class IDZHandlerCheckTeamName(IDZHandlerBase):
|
||||||
cmd_codes = [0x00a2, 0x00a2, 0x0097, 0x0097]
|
cmd_codes = [0x00A2, 0x00A2, 0x0097, 0x0097]
|
||||||
rsp_codes = [0x00a3, 0x00a3, 0x0098, 0x0098]
|
rsp_codes = [0x00A3, 0x00A3, 0x0098, 0x0098]
|
||||||
name = "check_team_name"
|
name = "check_team_name"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0010
|
self.size = 0x0010
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
struct.pack_into("<I", ret, 0x4, 0x1)
|
struct.pack_into("<I", ret, 0x4, 0x1)
|
||||||
|
@ -8,37 +8,51 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
AUTO_TEAM_NAMES = ["スピードスターズ", "レッドサンズ", "ナイトキッズ"]
|
AUTO_TEAM_NAMES = ["スピードスターズ", "レッドサンズ", "ナイトキッズ"]
|
||||||
FULL_WIDTH_NUMS = ["\uff10", "\uff11", "\uff12", "\uff13", "\uff14", "\uff15", "\uff16", "\uff17", "\uff18", "\uff19"]
|
FULL_WIDTH_NUMS = [
|
||||||
|
"\uff10",
|
||||||
|
"\uff11",
|
||||||
|
"\uff12",
|
||||||
|
"\uff13",
|
||||||
|
"\uff14",
|
||||||
|
"\uff15",
|
||||||
|
"\uff16",
|
||||||
|
"\uff17",
|
||||||
|
"\uff18",
|
||||||
|
"\uff19",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerCreateAutoTeam(IDZHandlerBase):
|
class IDZHandlerCreateAutoTeam(IDZHandlerBase):
|
||||||
cmd_codes = [0x007b, 0x007b, 0x0077, 0x0077]
|
cmd_codes = [0x007B, 0x007B, 0x0077, 0x0077]
|
||||||
rsp_codes = [0x007c, 0x007c, 0x0078, 0x0078]
|
rsp_codes = [0x007C, 0x007C, 0x0078, 0x0078]
|
||||||
name = "create_auto_team"
|
name = "create_auto_team"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0ca0
|
self.size = 0x0CA0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
aime_id = struct.unpack_from("<I", data, 0x04)[0]
|
aime_id = struct.unpack_from("<I", data, 0x04)[0]
|
||||||
name = choice(AUTO_TEAM_NAMES)
|
name = choice(AUTO_TEAM_NAMES)
|
||||||
bg = indexOf(AUTO_TEAM_NAMES, name)
|
bg = indexOf(AUTO_TEAM_NAMES, name)
|
||||||
number = choice(FULL_WIDTH_NUMS) + choice(FULL_WIDTH_NUMS) + choice(FULL_WIDTH_NUMS)
|
number = (
|
||||||
|
choice(FULL_WIDTH_NUMS) + choice(FULL_WIDTH_NUMS) + choice(FULL_WIDTH_NUMS)
|
||||||
|
)
|
||||||
|
|
||||||
tdata = {
|
tdata = {
|
||||||
"id": aime_id,
|
"id": aime_id,
|
||||||
"bg": bg,
|
"bg": bg,
|
||||||
"fx": 0,
|
"fx": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
tdata = {
|
tdata = {
|
||||||
"id": aime_id,
|
"id": aime_id,
|
||||||
"name": (name + number),
|
"name": (name + number),
|
||||||
"bg": bg,
|
"bg": bg,
|
||||||
"fx": 0,
|
"fx": 0,
|
||||||
}
|
}
|
||||||
tname = tdata['name'].encode("shift-jis")
|
tname = tdata["name"].encode("shift-jis")
|
||||||
|
|
||||||
struct.pack_into("<I", ret, 0x0C, tdata["id"])
|
struct.pack_into("<I", ret, 0x0C, tdata["id"])
|
||||||
struct.pack_into(f"{len(tname)}s", ret, 0x24, tname)
|
struct.pack_into(f"{len(tname)}s", ret, 0x24, tname)
|
||||||
|
@ -6,6 +6,7 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerCreateProfile(IDZHandlerBase):
|
class IDZHandlerCreateProfile(IDZHandlerBase):
|
||||||
cmd_codes = [0x0066, 0x0066, 0x0064, 0x0064]
|
cmd_codes = [0x0066, 0x0066, 0x0064, 0x0064]
|
||||||
rsp_codes = [0x0067, 0x0065, 0x0065, 0x0065]
|
rsp_codes = [0x0067, 0x0065, 0x0065, 0x0065]
|
||||||
@ -14,34 +15,26 @@ class IDZHandlerCreateProfile(IDZHandlerBase):
|
|||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0020
|
self.size = 0x0020
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
|
|
||||||
aime_id = struct.unpack_from("<L", data, 0x04)[0]
|
aime_id = struct.unpack_from("<L", data, 0x04)[0]
|
||||||
name = data[0x1E:0x0034].decode("shift-jis").replace("\x00", "")
|
name = data[0x1E:0x0034].decode("shift-jis").replace("\x00", "")
|
||||||
car = data[0x40:0xa0].hex()
|
car = data[0x40:0xA0].hex()
|
||||||
chara = data[0xa8:0xbc].hex()
|
chara = data[0xA8:0xBC].hex()
|
||||||
|
|
||||||
self.logger.info(f"Create profile for {name} (aime id {aime_id})")
|
self.logger.info(f"Create profile for {name} (aime id {aime_id})")
|
||||||
|
|
||||||
auto_team = None
|
auto_team = None
|
||||||
if not auto_team:
|
if not auto_team:
|
||||||
team = {
|
team = {"bg": 0, "id": 0, "shop": ""}
|
||||||
"bg": 0,
|
|
||||||
"id": 0,
|
|
||||||
"shop": ""
|
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
tdata = json.loads(auto_team["data"])
|
tdata = json.loads(auto_team["data"])
|
||||||
|
|
||||||
team = {
|
|
||||||
"bg": tdata["bg"],
|
|
||||||
"id": tdata["fx"],
|
|
||||||
"shop": ""
|
|
||||||
}
|
|
||||||
|
|
||||||
profile_data={
|
team = {"bg": tdata["bg"], "id": tdata["fx"], "shop": ""}
|
||||||
|
|
||||||
|
profile_data = {
|
||||||
"profile": {
|
"profile": {
|
||||||
"xp": 0,
|
"xp": 0,
|
||||||
"lv": 1,
|
"lv": 1,
|
||||||
@ -50,30 +43,19 @@ class IDZHandlerCreateProfile(IDZHandlerBase):
|
|||||||
"milage": 0,
|
"milage": 0,
|
||||||
"playstamps": 0,
|
"playstamps": 0,
|
||||||
"last_login": int(datetime.now().timestamp()),
|
"last_login": int(datetime.now().timestamp()),
|
||||||
"car_str": car, # These should probably be chaged to dicts
|
"car_str": car, # These should probably be chaged to dicts
|
||||||
"chara_str": chara, # But this works for now...
|
"chara_str": chara, # But this works for now...
|
||||||
},
|
},
|
||||||
|
|
||||||
"options": {
|
"options": {
|
||||||
"music": 0,
|
"music": 0,
|
||||||
"pack": 13640,
|
"pack": 13640,
|
||||||
"aura": 0,
|
"aura": 0,
|
||||||
"paper_cup": 0,
|
"paper_cup": 0,
|
||||||
"gauges": 5,
|
"gauges": 5,
|
||||||
"driving_style": 0
|
"driving_style": 0,
|
||||||
},
|
},
|
||||||
|
"missions": {"team": [], "solo": []},
|
||||||
"missions": {
|
"story": {"x": 0, "y": 0, "rows": {}},
|
||||||
"team": [],
|
|
||||||
"solo": []
|
|
||||||
},
|
|
||||||
|
|
||||||
"story": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"rows": {}
|
|
||||||
},
|
|
||||||
|
|
||||||
"unlocks": {
|
"unlocks": {
|
||||||
"auras": 1,
|
"auras": 1,
|
||||||
"cup": 0,
|
"cup": 0,
|
||||||
@ -81,9 +63,9 @@ class IDZHandlerCreateProfile(IDZHandlerBase):
|
|||||||
"music": 0,
|
"music": 0,
|
||||||
"last_mileage_reward": 0,
|
"last_mileage_reward": 0,
|
||||||
},
|
},
|
||||||
"team": team
|
"team": team,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.version > 2:
|
if self.version > 2:
|
||||||
struct.pack_into("<L", ret, 0x04, aime_id)
|
struct.pack_into("<L", ret, 0x04, aime_id)
|
||||||
else:
|
else:
|
||||||
|
@ -5,15 +5,16 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerDiscoverProfile(IDZHandlerBase):
|
class IDZHandlerDiscoverProfile(IDZHandlerBase):
|
||||||
cmd_codes = [0x006b, 0x0067]
|
cmd_codes = [0x006B, 0x0067]
|
||||||
rsp_codes = [0x006c, 0x0068, 0x0068,0x0068]
|
rsp_codes = [0x006C, 0x0068, 0x0068, 0x0068]
|
||||||
name = "discover_profile"
|
name = "discover_profile"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0010
|
self.size = 0x0010
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
user_id = struct.unpack_from("<I", data, 0x04)[0]
|
user_id = struct.unpack_from("<I", data, 0x04)[0]
|
||||||
|
@ -5,21 +5,23 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoad2on2A(IDZHandlerBase):
|
class IDZHandlerLoad2on2A(IDZHandlerBase):
|
||||||
cmd_codes = [0x00b0, 0x00b0, 0x00a3, 0x00a3]
|
cmd_codes = [0x00B0, 0x00B0, 0x00A3, 0x00A3]
|
||||||
rsp_codes = [0x00b1, 0x00b1, 0x00a4, 0x00a4]
|
rsp_codes = [0x00B1, 0x00B1, 0x00A4, 0x00A4]
|
||||||
name = "load_2on2A"
|
name = "load_2on2A"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x04c0
|
self.size = 0x04C0
|
||||||
|
|
||||||
if version >= IDZConstants.VER_IDZ_210:
|
if version >= IDZConstants.VER_IDZ_210:
|
||||||
self.size = 0x1290
|
self.size = 0x1290
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoad2on2B(IDZHandlerBase):
|
class IDZHandlerLoad2on2B(IDZHandlerBase):
|
||||||
cmd_codes = [0x0132] * 4
|
cmd_codes = [0x0132] * 4
|
||||||
rsp_codes = [0x0133] * 4
|
rsp_codes = [0x0133] * 4
|
||||||
@ -27,10 +29,10 @@ class IDZHandlerLoad2on2B(IDZHandlerBase):
|
|||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x04c0
|
self.size = 0x04C0
|
||||||
|
|
||||||
if version >= IDZConstants.VER_IDZ_210:
|
if version >= IDZConstants.VER_IDZ_210:
|
||||||
self.size = 0x0540
|
self.size = 0x0540
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
@ -5,6 +5,7 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadConfigA(IDZHandlerBase):
|
class IDZHandlerLoadConfigA(IDZHandlerBase):
|
||||||
cmd_codes = [0x0004] * IDZConstants.NUM_VERS
|
cmd_codes = [0x0004] * IDZConstants.NUM_VERS
|
||||||
rsp_codes = [0x0005] * IDZConstants.NUM_VERS
|
rsp_codes = [0x0005] * IDZConstants.NUM_VERS
|
||||||
@ -12,29 +13,30 @@ class IDZHandlerLoadConfigA(IDZHandlerBase):
|
|||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x01a0
|
self.size = 0x01A0
|
||||||
|
|
||||||
if self.version > 1:
|
if self.version > 1:
|
||||||
self.size = 0x05e0
|
self.size = 0x05E0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
struct.pack_into("<H", ret, 0x02, 1)
|
struct.pack_into("<H", ret, 0x02, 1)
|
||||||
struct.pack_into("<I", ret, 0x16, 230)
|
struct.pack_into("<I", ret, 0x16, 230)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadConfigB(IDZHandlerBase):
|
class IDZHandlerLoadConfigB(IDZHandlerBase):
|
||||||
cmd_codes = [0x00ab, 0x00ab, 0x00a0, 0x00a0]
|
cmd_codes = [0x00AB, 0x00AB, 0x00A0, 0x00A0]
|
||||||
rsp_codes = [0x00ac, 0x00ac, 0x00a1, 0x00a1]
|
rsp_codes = [0x00AC, 0x00AC, 0x00A1, 0x00A1]
|
||||||
name = "load_config_b"
|
name = "load_config_b"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0230
|
self.size = 0x0230
|
||||||
|
|
||||||
if self.version > 1:
|
if self.version > 1:
|
||||||
self.size = 0x0240
|
self.size = 0x0240
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
struct.pack_into("<H", ret, 0x02, 1)
|
struct.pack_into("<H", ret, 0x02, 1)
|
||||||
|
@ -4,15 +4,16 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadGhost(IDZHandlerBase):
|
class IDZHandlerLoadGhost(IDZHandlerBase):
|
||||||
cmd_codes = [0x00a0, 0x00a0, 0x0095, 0x0095]
|
cmd_codes = [0x00A0, 0x00A0, 0x0095, 0x0095]
|
||||||
rsp_codes = [0x00a1, 0x00a1, 0x0096, 0x0096]
|
rsp_codes = [0x00A1, 0x00A1, 0x0096, 0x0096]
|
||||||
name = "load_ghost"
|
name = "load_ghost"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0070
|
self.size = 0x0070
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
struct.pack_into("<I", ret, 0x02, 0x5)
|
struct.pack_into("<I", ret, 0x02, 0x5)
|
||||||
|
@ -5,23 +5,24 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadProfile(IDZHandlerBase):
|
class IDZHandlerLoadProfile(IDZHandlerBase):
|
||||||
cmd_codes = [0x0067, 0x012f, 0x012f, 0x0142]
|
cmd_codes = [0x0067, 0x012F, 0x012F, 0x0142]
|
||||||
rsp_codes = [0x0065, 0x012e, 0x012e, 0x0141]
|
rsp_codes = [0x0065, 0x012E, 0x012E, 0x0141]
|
||||||
name = "load_profile"
|
name = "load_profile"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
|
|
||||||
if self.version == IDZConstants.VER_IDZ_110:
|
if self.version == IDZConstants.VER_IDZ_110:
|
||||||
self.size = 0x0d30
|
self.size = 0x0D30
|
||||||
elif self.version == IDZConstants.VER_IDZ_130:
|
elif self.version == IDZConstants.VER_IDZ_130:
|
||||||
self.size = 0x0ea0
|
self.size = 0x0EA0
|
||||||
elif self.version == IDZConstants.VER_IDZ_210:
|
elif self.version == IDZConstants.VER_IDZ_210:
|
||||||
self.size = 0x1360
|
self.size = 0x1360
|
||||||
elif self.version == IDZConstants.VER_IDZ_230:
|
elif self.version == IDZConstants.VER_IDZ_230:
|
||||||
self.size = 0x1640
|
self.size = 0x1640
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
aime_id = struct.unpack_from("<L", data, 0x04)[0]
|
aime_id = struct.unpack_from("<L", data, 0x04)[0]
|
||||||
|
@ -4,6 +4,7 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadRewardTable(IDZHandlerBase):
|
class IDZHandlerLoadRewardTable(IDZHandlerBase):
|
||||||
cmd_codes = [0x0086, 0x0086, 0x007F, 0x007F]
|
cmd_codes = [0x0086, 0x0086, 0x007F, 0x007F]
|
||||||
rsp_codes = [0x0087, 0x0087, 0x0080, 0x0080]
|
rsp_codes = [0x0087, 0x0087, 0x0080, 0x0080]
|
||||||
@ -11,7 +12,7 @@ class IDZHandlerLoadRewardTable(IDZHandlerBase):
|
|||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x01c0
|
self.size = 0x01C0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
@ -5,6 +5,7 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadServerInfo(IDZHandlerBase):
|
class IDZHandlerLoadServerInfo(IDZHandlerBase):
|
||||||
cmd_codes = [0x0006] * IDZConstants.NUM_VERS
|
cmd_codes = [0x0006] * IDZConstants.NUM_VERS
|
||||||
rsp_codes = [0x0007] * IDZConstants.NUM_VERS
|
rsp_codes = [0x0007] * IDZConstants.NUM_VERS
|
||||||
@ -12,14 +13,14 @@ class IDZHandlerLoadServerInfo(IDZHandlerBase):
|
|||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x04b0
|
self.size = 0x04B0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
offset = 0
|
offset = 0
|
||||||
if self.version >= IDZConstants.VER_IDZ_210:
|
if self.version >= IDZConstants.VER_IDZ_210:
|
||||||
offset = 2
|
offset = 2
|
||||||
|
|
||||||
news_str = f"http://{self.core_config.title.hostname}:{self.core_config.title.port}/SDDF/230/news/news80**.txt"
|
news_str = f"http://{self.core_config.title.hostname}:{self.core_config.title.port}/SDDF/230/news/news80**.txt"
|
||||||
err_str = f"http://{self.core_config.title.hostname}:{self.core_config.title.port}/SDDF/230/error"
|
err_str = f"http://{self.core_config.title.hostname}:{self.core_config.title.port}/SDDF/230/error"
|
||||||
|
|
||||||
@ -27,34 +28,69 @@ class IDZHandlerLoadServerInfo(IDZHandlerBase):
|
|||||||
len_news = len(news_str)
|
len_news = len(news_str)
|
||||||
len_error = len(err_str)
|
len_error = len(err_str)
|
||||||
|
|
||||||
struct.pack_into("<I", ret, 0x2 + offset, 1) # Status
|
struct.pack_into("<I", ret, 0x2 + offset, 1) # Status
|
||||||
struct.pack_into(f"{len_hostname}s", ret, 0x4 + offset, self.core_config.title.hostname.encode())
|
struct.pack_into(
|
||||||
|
f"{len_hostname}s",
|
||||||
|
ret,
|
||||||
|
0x4 + offset,
|
||||||
|
self.core_config.title.hostname.encode(),
|
||||||
|
)
|
||||||
struct.pack_into("<I", ret, 0x84 + offset, self.game_cfg.ports.userdb)
|
struct.pack_into("<I", ret, 0x84 + offset, self.game_cfg.ports.userdb)
|
||||||
struct.pack_into("<I", ret, 0x86 + offset, self.game_cfg.ports.userdb + 1)
|
struct.pack_into("<I", ret, 0x86 + offset, self.game_cfg.ports.userdb + 1)
|
||||||
|
|
||||||
struct.pack_into(f"{len_hostname}s", ret, 0x88 + offset, self.core_config.title.hostname.encode())
|
struct.pack_into(
|
||||||
|
f"{len_hostname}s",
|
||||||
|
ret,
|
||||||
|
0x88 + offset,
|
||||||
|
self.core_config.title.hostname.encode(),
|
||||||
|
)
|
||||||
struct.pack_into("<I", ret, 0x108 + offset, self.game_cfg.ports.match - 1)
|
struct.pack_into("<I", ret, 0x108 + offset, self.game_cfg.ports.match - 1)
|
||||||
struct.pack_into("<I", ret, 0x10a + offset, self.game_cfg.ports.match - 3)
|
struct.pack_into("<I", ret, 0x10A + offset, self.game_cfg.ports.match - 3)
|
||||||
struct.pack_into("<I", ret, 0x10c + offset, self.game_cfg.ports.match - 2)
|
struct.pack_into("<I", ret, 0x10C + offset, self.game_cfg.ports.match - 2)
|
||||||
|
|
||||||
struct.pack_into("<I", ret, 0x10e + offset, self.game_cfg.ports.match + 2)
|
struct.pack_into("<I", ret, 0x10E + offset, self.game_cfg.ports.match + 2)
|
||||||
struct.pack_into("<I", ret, 0x110 + offset, self.game_cfg.ports.match + 3)
|
struct.pack_into("<I", ret, 0x110 + offset, self.game_cfg.ports.match + 3)
|
||||||
struct.pack_into("<I", ret, 0x112 + offset, self.game_cfg.ports.match + 1)
|
struct.pack_into("<I", ret, 0x112 + offset, self.game_cfg.ports.match + 1)
|
||||||
|
|
||||||
struct.pack_into(f"{len_hostname}s", ret, 0x114 + offset, self.core_config.title.hostname.encode())
|
struct.pack_into(
|
||||||
|
f"{len_hostname}s",
|
||||||
|
ret,
|
||||||
|
0x114 + offset,
|
||||||
|
self.core_config.title.hostname.encode(),
|
||||||
|
)
|
||||||
struct.pack_into("<I", ret, 0x194 + offset, self.game_cfg.ports.echo + 2)
|
struct.pack_into("<I", ret, 0x194 + offset, self.game_cfg.ports.echo + 2)
|
||||||
|
|
||||||
struct.pack_into(f"{len_hostname}s", ret, 0x0199 + offset, self.core_config.title.hostname.encode())
|
struct.pack_into(
|
||||||
|
f"{len_hostname}s",
|
||||||
|
ret,
|
||||||
|
0x0199 + offset,
|
||||||
|
self.core_config.title.hostname.encode(),
|
||||||
|
)
|
||||||
struct.pack_into("<I", ret, 0x0219 + offset, self.game_cfg.ports.echo + 3)
|
struct.pack_into("<I", ret, 0x0219 + offset, self.game_cfg.ports.echo + 3)
|
||||||
|
|
||||||
struct.pack_into(f"{len_hostname}s", ret, 0x021c + offset, self.core_config.title.hostname.encode())
|
struct.pack_into(
|
||||||
struct.pack_into(f"{len_hostname}s", ret, 0x029c + offset, self.core_config.title.hostname.encode())
|
f"{len_hostname}s",
|
||||||
struct.pack_into(f"{len_hostname}s", ret, 0x031c + offset, self.core_config.title.hostname.encode())
|
ret,
|
||||||
|
0x021C + offset,
|
||||||
|
self.core_config.title.hostname.encode(),
|
||||||
|
)
|
||||||
|
struct.pack_into(
|
||||||
|
f"{len_hostname}s",
|
||||||
|
ret,
|
||||||
|
0x029C + offset,
|
||||||
|
self.core_config.title.hostname.encode(),
|
||||||
|
)
|
||||||
|
struct.pack_into(
|
||||||
|
f"{len_hostname}s",
|
||||||
|
ret,
|
||||||
|
0x031C + offset,
|
||||||
|
self.core_config.title.hostname.encode(),
|
||||||
|
)
|
||||||
|
|
||||||
struct.pack_into("<I", ret, 0x39c + offset, self.game_cfg.ports.echo)
|
struct.pack_into("<I", ret, 0x39C + offset, self.game_cfg.ports.echo)
|
||||||
struct.pack_into("<I", ret, 0x39e + offset, self.game_cfg.ports.echo + 1)
|
struct.pack_into("<I", ret, 0x39E + offset, self.game_cfg.ports.echo + 1)
|
||||||
|
|
||||||
struct.pack_into(f"{len_news}s", ret, 0x03a0 + offset, news_str.encode())
|
struct.pack_into(f"{len_news}s", ret, 0x03A0 + offset, news_str.encode())
|
||||||
struct.pack_into(f"{len_error}s", ret, 0x0424 + offset, err_str.encode())
|
struct.pack_into(f"{len_error}s", ret, 0x0424 + offset, err_str.encode())
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
@ -4,26 +4,28 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadTeamRankingA(IDZHandlerBase):
|
class IDZHandlerLoadTeamRankingA(IDZHandlerBase):
|
||||||
cmd_codes = [0x00b9, 0x00b9, 0x00a7, 0x00a7]
|
cmd_codes = [0x00B9, 0x00B9, 0x00A7, 0x00A7]
|
||||||
rsp_codes = [0x00b1] * 4
|
rsp_codes = [0x00B1] * 4
|
||||||
name = "load_team_ranking_a"
|
name = "load_team_ranking_a"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0ba0
|
self.size = 0x0BA0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadTeamRankingB(IDZHandlerBase):
|
class IDZHandlerLoadTeamRankingB(IDZHandlerBase):
|
||||||
cmd_codes = [0x00bb, 0x00bb, 0x00a9, 0x00a9]
|
cmd_codes = [0x00BB, 0x00BB, 0x00A9, 0x00A9]
|
||||||
rsp_codes = [0x00a8] * 4
|
rsp_codes = [0x00A8] * 4
|
||||||
name = "load_team_ranking_b"
|
name = "load_team_ranking_b"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0ba0
|
self.size = 0x0BA0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
@ -5,9 +5,10 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLoadTopTen(IDZHandlerBase):
|
class IDZHandlerLoadTopTen(IDZHandlerBase):
|
||||||
cmd_codes = [0x012c] * 4
|
cmd_codes = [0x012C] * 4
|
||||||
rsp_codes = [0x00ce] * 4
|
rsp_codes = [0x00CE] * 4
|
||||||
name = "load_top_ten"
|
name = "load_top_ten"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
@ -19,12 +20,16 @@ class IDZHandlerLoadTopTen(IDZHandlerBase):
|
|||||||
tracks_dates: List[Tuple[int, int]] = []
|
tracks_dates: List[Tuple[int, int]] = []
|
||||||
for i in range(32):
|
for i in range(32):
|
||||||
tracks_dates.append(
|
tracks_dates.append(
|
||||||
(struct.unpack_from("<H", data, 0x04 + (2 * i))[0], "little",
|
(
|
||||||
struct.unpack_from("<I", data, 0x44 + (4 * i))[0], "little")
|
struct.unpack_from("<H", data, 0x04 + (2 * i))[0],
|
||||||
|
"little",
|
||||||
|
struct.unpack_from("<I", data, 0x44 + (4 * i))[0],
|
||||||
|
"little",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
# TODO: Best scores
|
# TODO: Best scores
|
||||||
for i in range (3):
|
for i in range(3):
|
||||||
offset = 0x16c0 + 0x1c * i
|
offset = 0x16C0 + 0x1C * i
|
||||||
struct.pack_into("<B", ret, offset + 0x02, 0xff)
|
struct.pack_into("<B", ret, offset + 0x02, 0xFF)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
@ -7,20 +7,23 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerLockProfile(IDZHandlerBase):
|
class IDZHandlerLockProfile(IDZHandlerBase):
|
||||||
cmd_codes = [0x0069, 0x0069, 0x0065, 0x0065]
|
cmd_codes = [0x0069, 0x0069, 0x0065, 0x0065]
|
||||||
rsp_codes = [0x006a, 0x006a, 0x0066, 0x0066]
|
rsp_codes = [0x006A, 0x006A, 0x0066, 0x0066]
|
||||||
name = "lock_profile"
|
name = "lock_profile"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0020
|
self.size = 0x0020
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
profile_data = {
|
profile_data = {
|
||||||
"status": IDZConstants.PROFILE_STATUS.UNLOCKED.value,
|
"status": IDZConstants.PROFILE_STATUS.UNLOCKED.value,
|
||||||
"expire_time": int((datetime.now() + timedelta(hours=1)).timestamp() / 1000)
|
"expire_time": int(
|
||||||
|
(datetime.now() + timedelta(hours=1)).timestamp() / 1000
|
||||||
|
),
|
||||||
}
|
}
|
||||||
user_id = struct.unpack_from("<I", data, 0x04)[0]
|
user_id = struct.unpack_from("<I", data, 0x04)[0]
|
||||||
profile = None
|
profile = None
|
||||||
@ -29,11 +32,11 @@ class IDZHandlerLockProfile(IDZHandlerBase):
|
|||||||
old_profile = None
|
old_profile = None
|
||||||
if old_profile is not None:
|
if old_profile is not None:
|
||||||
profile_data["status"] = IDZConstants.PROFILE_STATUS.OLD.value
|
profile_data["status"] = IDZConstants.PROFILE_STATUS.OLD.value
|
||||||
|
|
||||||
return self.handle_common(profile_data, ret)
|
return self.handle_common(profile_data, ret)
|
||||||
|
|
||||||
def handle_common(cls, data: Dict, ret: bytearray) -> bytearray:
|
def handle_common(cls, data: Dict, ret: bytearray) -> bytearray:
|
||||||
struct.pack_into("<B", ret, 0x18, data["status"])
|
struct.pack_into("<B", ret, 0x18, data["status"])
|
||||||
struct.pack_into("<h", ret, 0x1a, -1)
|
struct.pack_into("<h", ret, 0x1A, -1)
|
||||||
struct.pack_into("<I", ret, 0x1c, data["expire_time"])
|
struct.pack_into("<I", ret, 0x1C, data["expire_time"])
|
||||||
return ret
|
return ret
|
||||||
|
@ -3,12 +3,13 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerSaveExpedition(IDZHandlerBase):
|
class IDZHandlerSaveExpedition(IDZHandlerBase):
|
||||||
cmd_codes = [0x008c, 0x013f]
|
cmd_codes = [0x008C, 0x013F]
|
||||||
name = "save_expedition"
|
name = "save_expedition"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
@ -4,12 +4,13 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerSaveProfile(IDZHandlerBase):
|
class IDZHandlerSaveProfile(IDZHandlerBase):
|
||||||
cmd_codes = [0x0068, 0x0138, 0x0138, 0x0143]
|
cmd_codes = [0x0068, 0x0138, 0x0138, 0x0143]
|
||||||
name = "save_profile"
|
name = "save_profile"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
@ -5,18 +5,19 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerSaveTimeAttack(IDZHandlerBase):
|
class IDZHandlerSaveTimeAttack(IDZHandlerBase):
|
||||||
cmd_codes = [0x00CD, 0x0136, 0x0136, 0x0136]
|
cmd_codes = [0x00CD, 0x0136, 0x0136, 0x0136]
|
||||||
rsp_codes = [0x00ce, 0x00ce, 0x00cd, 0x00cd]
|
rsp_codes = [0x00CE, 0x00CE, 0x00CD, 0x00CD]
|
||||||
name = "save_time_attack"
|
name = "save_time_attack"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x00b0
|
self.size = 0x00B0
|
||||||
|
|
||||||
if self.version > IDZConstants.VER_IDZ_130:
|
if self.version > IDZConstants.VER_IDZ_130:
|
||||||
self.size = 0x00f0
|
self.size = 0x00F0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
return ret
|
return ret
|
||||||
|
@ -4,6 +4,7 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerSaveTopic(IDZHandlerBase):
|
class IDZHandlerSaveTopic(IDZHandlerBase):
|
||||||
cmd_codes = [0x009A, 0x009A, 0x0091, 0x0091]
|
cmd_codes = [0x009A, 0x009A, 0x0091, 0x0091]
|
||||||
rsp_codes = [0x009B, 0x009B, 0x0092, 0x0092]
|
rsp_codes = [0x009B, 0x009B, 0x0092, 0x0092]
|
||||||
@ -11,7 +12,7 @@ class IDZHandlerSaveTopic(IDZHandlerBase):
|
|||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x05d0
|
self.size = 0x05D0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
@ -4,8 +4,9 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerUnknown(IDZHandlerBase):
|
class IDZHandlerUnknown(IDZHandlerBase):
|
||||||
cmd_codes = [0x00ad, 0x00ad, 0x00a2, 0x00a2]
|
cmd_codes = [0x00AD, 0x00AD, 0x00A2, 0x00A2]
|
||||||
name = "unknown"
|
name = "unknown"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
|
@ -5,16 +5,17 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerUnlockProfile(IDZHandlerBase):
|
class IDZHandlerUnlockProfile(IDZHandlerBase):
|
||||||
cmd_codes = [0x006f, 0x006f, 0x006b, 0x006b]
|
cmd_codes = [0x006F, 0x006F, 0x006B, 0x006B]
|
||||||
rsp_codes = [0x0070, 0x0070, 0x006c, 0x006c]
|
rsp_codes = [0x0070, 0x0070, 0x006C, 0x006C]
|
||||||
name = "unlock_profile"
|
name = "unlock_profile"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x0010
|
self.size = 0x0010
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
struct.pack_into("<H", ret, 0x4, 1)
|
struct.pack_into("<H", ret, 0x4, 1)
|
||||||
return ret
|
return ret
|
||||||
|
@ -4,6 +4,7 @@ from .base import IDZHandlerBase
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerUpdateProvisionalStoreRank(IDZHandlerBase):
|
class IDZHandlerUpdateProvisionalStoreRank(IDZHandlerBase):
|
||||||
cmd_codes = [0x0082, 0x0082, 0x007C, 0x007C]
|
cmd_codes = [0x0082, 0x0082, 0x007C, 0x007C]
|
||||||
rsp_codes = [0x0083, 0x0083, 0x007D, 0x007D]
|
rsp_codes = [0x0083, 0x0083, 0x007D, 0x007D]
|
||||||
@ -11,10 +12,10 @@ class IDZHandlerUpdateProvisionalStoreRank(IDZHandlerBase):
|
|||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
self.size = 0x02b0
|
self.size = 0x02B0
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
|
||||||
def handle_common(cls, aime_id: int, ret: bytearray) -> bytearray:
|
def handle_common(cls, aime_id: int, ret: bytearray) -> bytearray:
|
||||||
pass
|
pass
|
||||||
|
@ -5,22 +5,23 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandlerUpdateStoryClearNum(IDZHandlerBase):
|
class IDZHandlerUpdateStoryClearNum(IDZHandlerBase):
|
||||||
cmd_codes = [0x007f, 0x097f, 0x013d, 0x0144]
|
cmd_codes = [0x007F, 0x097F, 0x013D, 0x0144]
|
||||||
rsp_codes = [0x0080, 0x013e, 0x013e, 0x0145]
|
rsp_codes = [0x0080, 0x013E, 0x013E, 0x0145]
|
||||||
name = "update_story_clear_num"
|
name = "update_story_clear_num"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
|
|
||||||
if self.version == IDZConstants.VER_IDZ_110:
|
if self.version == IDZConstants.VER_IDZ_110:
|
||||||
self.size = 0x0220
|
self.size = 0x0220
|
||||||
elif self.version == IDZConstants.VER_IDZ_130:
|
elif self.version == IDZConstants.VER_IDZ_130:
|
||||||
self.size = 0x04f0
|
self.size = 0x04F0
|
||||||
elif self.version == IDZConstants.VER_IDZ_210:
|
elif self.version == IDZConstants.VER_IDZ_210:
|
||||||
self.size = 0x0510
|
self.size = 0x0510
|
||||||
elif self.version == IDZConstants.VER_IDZ_230:
|
elif self.version == IDZConstants.VER_IDZ_230:
|
||||||
self.size = 0x0800
|
self.size = 0x0800
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
return super().handle(data)
|
return super().handle(data)
|
||||||
|
@ -5,13 +5,14 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandleUpdateTeamPoints(IDZHandlerBase):
|
class IDZHandleUpdateTeamPoints(IDZHandlerBase):
|
||||||
cmd_codes = [0x0081, 0x0081, 0x007b, 0x007b]
|
cmd_codes = [0x0081, 0x0081, 0x007B, 0x007B]
|
||||||
name = "unlock_profile"
|
name = "unlock_profile"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
return ret
|
return ret
|
||||||
|
@ -5,13 +5,14 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandleUpdateUIReport(IDZHandlerBase):
|
class IDZHandleUpdateUIReport(IDZHandlerBase):
|
||||||
cmd_codes = [0x0084, 0x0084, 0x007e, 0x007e]
|
cmd_codes = [0x0084, 0x0084, 0x007E, 0x007E]
|
||||||
name = "update_ui_report"
|
name = "update_ui_report"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
return ret
|
return ret
|
||||||
|
@ -5,13 +5,14 @@ from core.config import CoreConfig
|
|||||||
from ..config import IDZConfig
|
from ..config import IDZConfig
|
||||||
from ..const import IDZConstants
|
from ..const import IDZConstants
|
||||||
|
|
||||||
|
|
||||||
class IDZHandleUpdateUserLog(IDZHandlerBase):
|
class IDZHandleUpdateUserLog(IDZHandlerBase):
|
||||||
cmd_codes = [0x00bd, 0x00bd, 0x00ab, 0x00b3]
|
cmd_codes = [0x00BD, 0x00BD, 0x00AB, 0x00B3]
|
||||||
name = "update_user_log"
|
name = "update_user_log"
|
||||||
|
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, version: int) -> None:
|
||||||
super().__init__(core_cfg, game_cfg, version)
|
super().__init__(core_cfg, game_cfg, version)
|
||||||
|
|
||||||
def handle(self, data: bytes) -> bytearray:
|
def handle(self, data: bytes) -> bytearray:
|
||||||
ret = super().handle(data)
|
ret = super().handle(data)
|
||||||
return ret
|
return ret
|
||||||
|
@ -16,6 +16,7 @@ from .userdb import IDZUserDBFactory, IDZUserDBWeb, IDZKey
|
|||||||
from .echo import IDZEcho
|
from .echo import IDZEcho
|
||||||
from .handlers import IDZHandlerLoadConfigB
|
from .handlers import IDZHandlerLoadConfigB
|
||||||
|
|
||||||
|
|
||||||
class IDZServlet:
|
class IDZServlet:
|
||||||
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
|
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
|
||||||
self.core_cfg = core_cfg
|
self.core_cfg = core_cfg
|
||||||
@ -51,13 +52,16 @@ class IDZServlet:
|
|||||||
level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str
|
level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str
|
||||||
)
|
)
|
||||||
self.logger.inited = True
|
self.logger.inited = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def rsaHashKeyN(cls, data):
|
def rsaHashKeyN(cls, data):
|
||||||
hash_ = 0
|
hash_ = 0
|
||||||
for i in data:
|
for i in data:
|
||||||
hash_ = hash_ * IDZConstants.HASH_MUL + (i ^ IDZConstants.HASH_XOR) ^ IDZConstants.HASH_LUT[i & 0xf]
|
hash_ = (
|
||||||
hash_ &= 0xffffffff
|
hash_ * IDZConstants.HASH_MUL + (i ^ IDZConstants.HASH_XOR)
|
||||||
|
^ IDZConstants.HASH_LUT[i & 0xF]
|
||||||
|
)
|
||||||
|
hash_ &= 0xFFFFFFFF
|
||||||
return hash_
|
return hash_
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -77,14 +81,18 @@ class IDZServlet:
|
|||||||
logging.getLogger("idz").error("IDZ: No RSA/AES keys! IDZ cannot start")
|
logging.getLogger("idz").error("IDZ: No RSA/AES keys! IDZ cannot start")
|
||||||
return (False, "", "")
|
return (False, "", "")
|
||||||
|
|
||||||
hostname = core_cfg.title.hostname if not game_cfg.server.hostname else game_cfg.server.hostname
|
hostname = (
|
||||||
|
core_cfg.title.hostname
|
||||||
|
if not game_cfg.server.hostname
|
||||||
|
else game_cfg.server.hostname
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
True,
|
True,
|
||||||
f"",
|
f"",
|
||||||
f"{hostname}:{game_cfg.ports.userdb}",
|
f"{hostname}:{game_cfg.ports.userdb}",
|
||||||
)
|
)
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
for key in self.game_cfg.rsa_keys:
|
for key in self.game_cfg.rsa_keys:
|
||||||
if "N" not in key or "d" not in key or "e" not in key:
|
if "N" not in key or "d" not in key or "e" not in key:
|
||||||
self.logger.error(f"Invalid IDZ key {key}")
|
self.logger.error(f"Invalid IDZ key {key}")
|
||||||
@ -92,14 +100,14 @@ class IDZServlet:
|
|||||||
|
|
||||||
hashN = self.rsaHashKeyN(str(key["N"]).encode())
|
hashN = self.rsaHashKeyN(str(key["N"]).encode())
|
||||||
self.rsa_keys.append(IDZKey(key["N"], key["d"], key["e"], hashN))
|
self.rsa_keys.append(IDZKey(key["N"], key["d"], key["e"], hashN))
|
||||||
|
|
||||||
if len(self.rsa_keys) <= 0:
|
if len(self.rsa_keys) <= 0:
|
||||||
self.logger.error("No valid RSA keys provided! IDZ cannot start!")
|
self.logger.error("No valid RSA keys provided! IDZ cannot start!")
|
||||||
return
|
return
|
||||||
|
|
||||||
handler_map = [{} for _ in range(IDZConstants.NUM_VERS)]
|
handler_map = [{} for _ in range(IDZConstants.NUM_VERS)]
|
||||||
handler_mod = mod = importlib.import_module(f"titles.idz.handlers")
|
handler_mod = mod = importlib.import_module(f"titles.idz.handlers")
|
||||||
|
|
||||||
for cls_name in dir(handler_mod):
|
for cls_name in dir(handler_mod):
|
||||||
if cls_name.startswith("__"):
|
if cls_name.startswith("__"):
|
||||||
continue
|
continue
|
||||||
@ -109,7 +117,7 @@ class IDZServlet:
|
|||||||
mod_cmds: List = getattr(mod, "cmd_codes")
|
mod_cmds: List = getattr(mod, "cmd_codes")
|
||||||
while len(mod_cmds) < IDZConstants.NUM_VERS:
|
while len(mod_cmds) < IDZConstants.NUM_VERS:
|
||||||
mod_cmds.append(None)
|
mod_cmds.append(None)
|
||||||
|
|
||||||
for i in range(len(mod_cmds)):
|
for i in range(len(mod_cmds)):
|
||||||
if mod_cmds[i] is None:
|
if mod_cmds[i] is None:
|
||||||
mod_cmds[i] = mod_cmds[i - 1]
|
mod_cmds[i] = mod_cmds[i - 1]
|
||||||
@ -119,27 +127,47 @@ class IDZServlet:
|
|||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
endpoints.serverFromString(reactor, f"tcp:{self.game_cfg.ports.userdb}:interface={self.core_cfg.server.listen_address}")\
|
endpoints.serverFromString(
|
||||||
.listen(IDZUserDBFactory(self.core_cfg, self.game_cfg, self.rsa_keys, handler_map))
|
reactor,
|
||||||
|
f"tcp:{self.game_cfg.ports.userdb}:interface={self.core_cfg.server.listen_address}",
|
||||||
reactor.listenUDP(self.game_cfg.ports.echo, IDZEcho(self.core_cfg, self.game_cfg))
|
).listen(
|
||||||
reactor.listenUDP(self.game_cfg.ports.echo + 1, IDZEcho(self.core_cfg, self.game_cfg))
|
IDZUserDBFactory(self.core_cfg, self.game_cfg, self.rsa_keys, handler_map)
|
||||||
reactor.listenUDP(self.game_cfg.ports.match, IDZEcho(self.core_cfg, self.game_cfg))
|
)
|
||||||
reactor.listenUDP(self.game_cfg.ports.userdb + 1, IDZEcho(self.core_cfg, self.game_cfg))
|
|
||||||
|
reactor.listenUDP(
|
||||||
|
self.game_cfg.ports.echo, IDZEcho(self.core_cfg, self.game_cfg)
|
||||||
|
)
|
||||||
|
reactor.listenUDP(
|
||||||
|
self.game_cfg.ports.echo + 1, IDZEcho(self.core_cfg, self.game_cfg)
|
||||||
|
)
|
||||||
|
reactor.listenUDP(
|
||||||
|
self.game_cfg.ports.match, IDZEcho(self.core_cfg, self.game_cfg)
|
||||||
|
)
|
||||||
|
reactor.listenUDP(
|
||||||
|
self.game_cfg.ports.userdb + 1, IDZEcho(self.core_cfg, self.game_cfg)
|
||||||
|
)
|
||||||
|
|
||||||
self.logger.info(f"UserDB Listening on port {self.game_cfg.ports.userdb}")
|
self.logger.info(f"UserDB Listening on port {self.game_cfg.ports.userdb}")
|
||||||
|
|
||||||
def render_POST(self, request: Request, version: int, url_path: str) -> bytes:
|
def render_POST(self, request: Request, version: int, url_path: str) -> bytes:
|
||||||
req_raw = request.content.getvalue()
|
req_raw = request.content.getvalue()
|
||||||
self.logger.info(f"IDZ POST request: {url_path} - {req_raw}")
|
self.logger.info(f"IDZ POST request: {url_path} - {req_raw}")
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
def render_GET(self, request: Request, version: int, url_path: str) -> bytes:
|
def render_GET(self, request: Request, version: int, url_path: str) -> bytes:
|
||||||
self.logger.info(f"IDZ GET request: {url_path}")
|
self.logger.info(f"IDZ GET request: {url_path}")
|
||||||
request.responseHeaders.setRawHeaders('Content-Type', [b"text/plain; charset=utf-8"])
|
request.responseHeaders.setRawHeaders(
|
||||||
request.responseHeaders.setRawHeaders("Last-Modified", [b"Sun, 23 Apr 2023 05:33:20 GMT"])
|
"Content-Type", [b"text/plain; charset=utf-8"]
|
||||||
|
)
|
||||||
news = self.game_cfg.server.news if self.game_cfg.server.news else f"Welcome to Initial D Arcade Stage Zero on {self.core_cfg.server.name}!"
|
request.responseHeaders.setRawHeaders(
|
||||||
|
"Last-Modified", [b"Sun, 23 Apr 2023 05:33:20 GMT"]
|
||||||
|
)
|
||||||
|
|
||||||
|
news = (
|
||||||
|
self.game_cfg.server.news
|
||||||
|
if self.game_cfg.server.news
|
||||||
|
else f"Welcome to Initial D Arcade Stage Zero on {self.core_cfg.server.name}!"
|
||||||
|
)
|
||||||
news += "\r\n"
|
news += "\r\n"
|
||||||
news = "1979/01/01 00:00:00 2099/12/31 23:59:59 " + news
|
news = "1979/01/01 00:00:00 2099/12/31 23:59:59 " + news
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ from .handlers import IDZHandlerBase
|
|||||||
|
|
||||||
HANDLER_MAP: List[Dict]
|
HANDLER_MAP: List[Dict]
|
||||||
|
|
||||||
|
|
||||||
class IDZKey:
|
class IDZKey:
|
||||||
def __init__(self, n, d, e, hashN: int) -> None:
|
def __init__(self, n, d, e, hashN: int) -> None:
|
||||||
self.N = n
|
self.N = n
|
||||||
@ -26,9 +27,16 @@ class IDZKey:
|
|||||||
self.e = e
|
self.e = e
|
||||||
self.hashN = hashN
|
self.hashN = hashN
|
||||||
|
|
||||||
|
|
||||||
class IDZUserDBProtocol(Protocol):
|
class IDZUserDBProtocol(Protocol):
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig, keys: List[IDZKey], handlers: List[Dict]) -> None:
|
def __init__(
|
||||||
self.logger = logging.getLogger('idz')
|
self,
|
||||||
|
core_cfg: CoreConfig,
|
||||||
|
game_cfg: IDZConfig,
|
||||||
|
keys: List[IDZKey],
|
||||||
|
handlers: List[Dict],
|
||||||
|
) -> None:
|
||||||
|
self.logger = logging.getLogger("idz")
|
||||||
self.core_config = core_cfg
|
self.core_config = core_cfg
|
||||||
self.game_config = game_cfg
|
self.game_config = game_cfg
|
||||||
self.rsa_keys = keys
|
self.rsa_keys = keys
|
||||||
@ -37,14 +45,14 @@ class IDZUserDBProtocol(Protocol):
|
|||||||
self.version = None
|
self.version = None
|
||||||
self.version_internal = None
|
self.version_internal = None
|
||||||
self.skip_next = False
|
self.skip_next = False
|
||||||
|
|
||||||
def append_padding(self, data: bytes):
|
def append_padding(self, data: bytes):
|
||||||
"""Appends 0s to the end of the data until it's at the correct size"""
|
"""Appends 0s to the end of the data until it's at the correct size"""
|
||||||
length = struct.unpack_from("<H", data, 6)
|
length = struct.unpack_from("<H", data, 6)
|
||||||
padding_size = length[0] - len(data)
|
padding_size = length[0] - len(data)
|
||||||
data += bytes(padding_size)
|
data += bytes(padding_size)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def connectionMade(self) -> None:
|
def connectionMade(self) -> None:
|
||||||
self.logger.debug(f"{self.transport.getPeer().host} Connected")
|
self.logger.debug(f"{self.transport.getPeer().host} Connected")
|
||||||
base = 0
|
base = 0
|
||||||
@ -57,13 +65,17 @@ class IDZUserDBProtocol(Protocol):
|
|||||||
|
|
||||||
rsa_key = random.choice(self.rsa_keys)
|
rsa_key = random.choice(self.rsa_keys)
|
||||||
key_enc: int = pow(base, rsa_key.e, rsa_key.N)
|
key_enc: int = pow(base, rsa_key.e, rsa_key.N)
|
||||||
result = key_enc.to_bytes(0x40, "little") + struct.pack("<I", 0x01020304) + rsa_key.hashN.to_bytes(4, "little")
|
result = (
|
||||||
|
key_enc.to_bytes(0x40, "little")
|
||||||
|
+ struct.pack("<I", 0x01020304)
|
||||||
|
+ rsa_key.hashN.to_bytes(4, "little")
|
||||||
|
)
|
||||||
|
|
||||||
self.logger.debug(f"Send handshake {result.hex()}")
|
self.logger.debug(f"Send handshake {result.hex()}")
|
||||||
|
|
||||||
self.transport.write(result)
|
self.transport.write(result)
|
||||||
|
|
||||||
def connectionLost(self, reason) -> None:
|
def connectionLost(self, reason) -> None:
|
||||||
self.logger.debug(
|
self.logger.debug(
|
||||||
f"{self.transport.getPeer().host} Disconnected - {reason.value}"
|
f"{self.transport.getPeer().host} Disconnected - {reason.value}"
|
||||||
)
|
)
|
||||||
@ -84,7 +96,7 @@ class IDZUserDBProtocol(Protocol):
|
|||||||
self.transport.write(b"\x00")
|
self.transport.write(b"\x00")
|
||||||
return
|
return
|
||||||
|
|
||||||
elif magic == 0x01020304:
|
elif magic == 0x01020304:
|
||||||
self.version = int(data_dec[16:19].decode())
|
self.version = int(data_dec[16:19].decode())
|
||||||
|
|
||||||
if self.version == 110:
|
if self.version == 110:
|
||||||
@ -99,10 +111,12 @@ class IDZUserDBProtocol(Protocol):
|
|||||||
self.logger.warn(f"Bad version v{self.version}")
|
self.logger.warn(f"Bad version v{self.version}")
|
||||||
self.version = None
|
self.version = None
|
||||||
self.version_internal = None
|
self.version_internal = None
|
||||||
|
|
||||||
self.logger.debug(f"Userdb v{self.version} handshake response from {self.transport.getPeer().host}")
|
self.logger.debug(
|
||||||
|
f"Userdb v{self.version} handshake response from {self.transport.getPeer().host}"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
elif self.skip_next:
|
elif self.skip_next:
|
||||||
self.skip_next = False
|
self.skip_next = False
|
||||||
self.transport.write(b"\x00")
|
self.transport.write(b"\x00")
|
||||||
@ -110,19 +124,25 @@ class IDZUserDBProtocol(Protocol):
|
|||||||
|
|
||||||
elif self.version is None:
|
elif self.version is None:
|
||||||
# We didn't get a handshake before, and this isn't one now, so we're up the creek
|
# We didn't get a handshake before, and this isn't one now, so we're up the creek
|
||||||
self.logger.info(f"Bad UserDB request from from {self.transport.getPeer().host}")
|
self.logger.info(
|
||||||
|
f"Bad UserDB request from from {self.transport.getPeer().host}"
|
||||||
|
)
|
||||||
self.transport.write(b"\x00")
|
self.transport.write(b"\x00")
|
||||||
return
|
return
|
||||||
|
|
||||||
cmd = struct.unpack_from("<H", data_dec, 0)[0]
|
cmd = struct.unpack_from("<H", data_dec, 0)[0]
|
||||||
|
|
||||||
handler_cls: Optional[Type[IDZHandlerBase]] = self.handlers[self.version_internal].get(cmd, None)
|
handler_cls: Optional[Type[IDZHandlerBase]] = self.handlers[
|
||||||
|
self.version_internal
|
||||||
|
].get(cmd, None)
|
||||||
if handler_cls is None:
|
if handler_cls is None:
|
||||||
self.logger.warn(f"No handler for v{self.version} {hex(cmd)} cmd")
|
self.logger.warn(f"No handler for v{self.version} {hex(cmd)} cmd")
|
||||||
handler_cls = IDZHandlerBase
|
handler_cls = IDZHandlerBase
|
||||||
|
|
||||||
handler = handler_cls(self.core_config, self.game_config, self.version_internal)
|
handler = handler_cls(self.core_config, self.game_config, self.version_internal)
|
||||||
self.logger.info(f"Userdb v{self.version} {handler.name} request from {self.transport.getPeer().host}")
|
self.logger.info(
|
||||||
|
f"Userdb v{self.version} {handler.name} request from {self.transport.getPeer().host}"
|
||||||
|
)
|
||||||
response = handler.handle(data_dec)
|
response = handler.handle(data_dec)
|
||||||
|
|
||||||
self.logger.debug(f"Response: {response.hex()}")
|
self.logger.debug(f"Response: {response.hex()}")
|
||||||
@ -136,14 +156,23 @@ class IDZUserDBProtocol(Protocol):
|
|||||||
class IDZUserDBFactory(Factory):
|
class IDZUserDBFactory(Factory):
|
||||||
protocol = IDZUserDBProtocol
|
protocol = IDZUserDBProtocol
|
||||||
|
|
||||||
def __init__(self, cfg: CoreConfig, game_cfg: IDZConfig, keys: List[IDZKey], handlers: List[Dict]) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
cfg: CoreConfig,
|
||||||
|
game_cfg: IDZConfig,
|
||||||
|
keys: List[IDZKey],
|
||||||
|
handlers: List[Dict],
|
||||||
|
) -> None:
|
||||||
self.core_config = cfg
|
self.core_config = cfg
|
||||||
self.game_config = game_cfg
|
self.game_config = game_cfg
|
||||||
self.keys = keys
|
self.keys = keys
|
||||||
self.handlers = handlers
|
self.handlers = handlers
|
||||||
|
|
||||||
def buildProtocol(self, addr):
|
def buildProtocol(self, addr):
|
||||||
return IDZUserDBProtocol(self.core_config, self.game_config, self.keys, self.handlers)
|
return IDZUserDBProtocol(
|
||||||
|
self.core_config, self.game_config, self.keys, self.handlers
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class IDZUserDBWeb(resource.Resource):
|
class IDZUserDBWeb(resource.Resource):
|
||||||
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig):
|
def __init__(self, core_cfg: CoreConfig, game_cfg: IDZConfig):
|
||||||
@ -151,12 +180,16 @@ class IDZUserDBWeb(resource.Resource):
|
|||||||
self.isLeaf = True
|
self.isLeaf = True
|
||||||
self.core_config = core_cfg
|
self.core_config = core_cfg
|
||||||
self.game_config = game_cfg
|
self.game_config = game_cfg
|
||||||
self.logger = logging.getLogger('idz')
|
self.logger = logging.getLogger("idz")
|
||||||
|
|
||||||
def render_POST(self, request: Request) -> bytes:
|
def render_POST(self, request: Request) -> bytes:
|
||||||
self.logger.info(f"IDZUserDBWeb POST from {request.getClientAddress().host} to {request.uri} with data {request.content.getvalue()}")
|
self.logger.info(
|
||||||
|
f"IDZUserDBWeb POST from {request.getClientAddress().host} to {request.uri} with data {request.content.getvalue()}"
|
||||||
|
)
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
def render_GET(self, request: Request) -> bytes:
|
def render_GET(self, request: Request) -> bytes:
|
||||||
self.logger.info(f"IDZUserDBWeb GET from {request.getClientAddress().host} to {request.uri}")
|
self.logger.info(
|
||||||
return b""
|
f"IDZUserDBWeb GET from {request.getClientAddress().host} to {request.uri}"
|
||||||
|
)
|
||||||
|
return b""
|
||||||
|
@ -300,7 +300,9 @@ class Mai2Base:
|
|||||||
):
|
):
|
||||||
for fsr in upsert["userFriendSeasonRankingList"]:
|
for fsr in upsert["userFriendSeasonRankingList"]:
|
||||||
fsr["recordDate"] = (
|
fsr["recordDate"] = (
|
||||||
datetime.strptime(fsr["recordDate"], f"{Mai2Constants.DATE_TIME_FORMAT}.0"),
|
datetime.strptime(
|
||||||
|
fsr["recordDate"], f"{Mai2Constants.DATE_TIME_FORMAT}.0"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
self.data.item.put_friend_season_ranking(user_id, fsr)
|
self.data.item.put_friend_season_ranking(user_id, fsr)
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class Mai2Constants:
|
|||||||
"maimai DX Splash PLUS",
|
"maimai DX Splash PLUS",
|
||||||
"maimai DX Universe",
|
"maimai DX Universe",
|
||||||
"maimai DX Universe PLUS",
|
"maimai DX Universe PLUS",
|
||||||
"maimai DX Festival"
|
"maimai DX Festival",
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -38,7 +38,7 @@ class Mai2Servlet:
|
|||||||
Mai2SplashPlus,
|
Mai2SplashPlus,
|
||||||
Mai2Universe,
|
Mai2Universe,
|
||||||
Mai2UniversePlus,
|
Mai2UniversePlus,
|
||||||
Mai2Festival
|
Mai2Festival,
|
||||||
]
|
]
|
||||||
|
|
||||||
self.logger = logging.getLogger("mai2")
|
self.logger = logging.getLogger("mai2")
|
||||||
@ -134,9 +134,7 @@ class Mai2Servlet:
|
|||||||
|
|
||||||
req_data = json.loads(unzip)
|
req_data = json.loads(unzip)
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(f"v{version} {endpoint} request from {client_ip}")
|
||||||
f"v{version} {endpoint} request from {client_ip}"
|
|
||||||
)
|
|
||||||
self.logger.debug(req_data)
|
self.logger.debug(req_data)
|
||||||
|
|
||||||
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
|
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
|
||||||
|
@ -402,7 +402,7 @@ class Mai2ItemData(BaseData):
|
|||||||
if result is None:
|
if result is None:
|
||||||
self.logger.warn(
|
self.logger.warn(
|
||||||
f"put_friend_season_ranking: failed to insert",
|
f"put_friend_season_ranking: failed to insert",
|
||||||
f"friend_season_ranking! aime_id: {aime_id}"
|
f"friend_season_ranking! aime_id: {aime_id}",
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
@ -299,9 +299,11 @@ class Mai2ProfileData(BaseData):
|
|||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
def get_profile_detail(self, user_id: int, version: int) -> Optional[Row]:
|
def get_profile_detail(self, user_id: int, version: int) -> Optional[Row]:
|
||||||
sql = select(detail).where(
|
sql = (
|
||||||
and_(detail.c.user == user_id, detail.c.version <= version)
|
select(detail)
|
||||||
).order_by(detail.c.version.desc())
|
.where(and_(detail.c.user == user_id, detail.c.version <= version))
|
||||||
|
.order_by(detail.c.version.desc())
|
||||||
|
)
|
||||||
|
|
||||||
result = self.execute(sql)
|
result = self.execute(sql)
|
||||||
if result is None:
|
if result is None:
|
||||||
@ -324,9 +326,11 @@ class Mai2ProfileData(BaseData):
|
|||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
def get_profile_ghost(self, user_id: int, version: int) -> Optional[Row]:
|
def get_profile_ghost(self, user_id: int, version: int) -> Optional[Row]:
|
||||||
sql = select(ghost).where(
|
sql = (
|
||||||
and_(ghost.c.user == user_id, ghost.c.version_int <= version)
|
select(ghost)
|
||||||
).order_by(ghost.c.version.desc())
|
.where(and_(ghost.c.user == user_id, ghost.c.version_int <= version))
|
||||||
|
.order_by(ghost.c.version.desc())
|
||||||
|
)
|
||||||
|
|
||||||
result = self.execute(sql)
|
result = self.execute(sql)
|
||||||
if result is None:
|
if result is None:
|
||||||
@ -349,9 +353,11 @@ class Mai2ProfileData(BaseData):
|
|||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
def get_profile_extend(self, user_id: int, version: int) -> Optional[Row]:
|
def get_profile_extend(self, user_id: int, version: int) -> Optional[Row]:
|
||||||
sql = select(extend).where(
|
sql = (
|
||||||
and_(extend.c.user == user_id, extend.c.version <= version)
|
select(extend)
|
||||||
).order_by(extend.c.version.desc())
|
.where(and_(extend.c.user == user_id, extend.c.version <= version))
|
||||||
|
.order_by(extend.c.version.desc())
|
||||||
|
)
|
||||||
|
|
||||||
result = self.execute(sql)
|
result = self.execute(sql)
|
||||||
if result is None:
|
if result is None:
|
||||||
@ -374,9 +380,11 @@ class Mai2ProfileData(BaseData):
|
|||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
def get_profile_option(self, user_id: int, version: int) -> Optional[Row]:
|
def get_profile_option(self, user_id: int, version: int) -> Optional[Row]:
|
||||||
sql = select(option).where(
|
sql = (
|
||||||
and_(option.c.user == user_id, option.c.version <= version)
|
select(option)
|
||||||
).order_by(option.c.version.desc())
|
.where(and_(option.c.user == user_id, option.c.version <= version))
|
||||||
|
.order_by(option.c.version.desc())
|
||||||
|
)
|
||||||
|
|
||||||
result = self.execute(sql)
|
result = self.execute(sql)
|
||||||
if result is None:
|
if result is None:
|
||||||
@ -399,9 +407,11 @@ class Mai2ProfileData(BaseData):
|
|||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
def get_profile_rating(self, user_id: int, version: int) -> Optional[Row]:
|
def get_profile_rating(self, user_id: int, version: int) -> Optional[Row]:
|
||||||
sql = select(rating).where(
|
sql = (
|
||||||
and_(rating.c.user == user_id, rating.c.version <= version)
|
select(rating)
|
||||||
).order_by(rating.c.version.desc())
|
.where(and_(rating.c.user == user_id, rating.c.version <= version))
|
||||||
|
.order_by(rating.c.version.desc())
|
||||||
|
)
|
||||||
|
|
||||||
result = self.execute(sql)
|
result = self.execute(sql)
|
||||||
if result is None:
|
if result is None:
|
||||||
|
@ -452,8 +452,7 @@ class OngekiBase:
|
|||||||
tmp.pop("id")
|
tmp.pop("id")
|
||||||
items.append(tmp)
|
items.append(tmp)
|
||||||
|
|
||||||
xout = kind * 10000000000 + \
|
xout = kind * 10000000000 + (data["nextIndex"] % 10000000000) + len(items)
|
||||||
(data["nextIndex"] % 10000000000) + len(items)
|
|
||||||
|
|
||||||
if len(items) < data["maxCount"] or data["maxCount"] == 0:
|
if len(items) < data["maxCount"] or data["maxCount"] == 0:
|
||||||
nextIndex = 0
|
nextIndex = 0
|
||||||
@ -852,8 +851,7 @@ class OngekiBase:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if "userOption" in upsert and len(upsert["userOption"]) > 0:
|
if "userOption" in upsert and len(upsert["userOption"]) > 0:
|
||||||
self.data.profile.put_profile_options(
|
self.data.profile.put_profile_options(user_id, upsert["userOption"][0])
|
||||||
user_id, upsert["userOption"][0])
|
|
||||||
|
|
||||||
if "userPlaylogList" in upsert:
|
if "userPlaylogList" in upsert:
|
||||||
for playlog in upsert["userPlaylogList"]:
|
for playlog in upsert["userPlaylogList"]:
|
||||||
|
@ -97,7 +97,7 @@ class OngekiBright(OngekiBase):
|
|||||||
"userId": data["userId"],
|
"userId": data["userId"],
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"nextIndex": 0,
|
"nextIndex": 0,
|
||||||
"userCharacterList": []
|
"userCharacterList": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
max_ct = data["maxCount"]
|
max_ct = data["maxCount"]
|
||||||
@ -548,7 +548,7 @@ class OngekiBright(OngekiBase):
|
|||||||
"returnCode": 1,
|
"returnCode": 1,
|
||||||
"orderId": 0,
|
"orderId": 0,
|
||||||
"serialId": "11111111111111111111",
|
"serialId": "11111111111111111111",
|
||||||
"apiName": "CMUpsertUserPrintPlaylogApi"
|
"apiName": "CMUpsertUserPrintPlaylogApi",
|
||||||
}
|
}
|
||||||
|
|
||||||
def handle_cm_upsert_user_printlog_api_request(self, data: Dict) -> Dict:
|
def handle_cm_upsert_user_printlog_api_request(self, data: Dict) -> Dict:
|
||||||
@ -556,7 +556,7 @@ class OngekiBright(OngekiBase):
|
|||||||
"returnCode": 1,
|
"returnCode": 1,
|
||||||
"orderId": 0,
|
"orderId": 0,
|
||||||
"serialId": "11111111111111111111",
|
"serialId": "11111111111111111111",
|
||||||
"apiName": "CMUpsertUserPrintlogApi"
|
"apiName": "CMUpsertUserPrintlogApi",
|
||||||
}
|
}
|
||||||
|
|
||||||
def handle_cm_upsert_user_print_api_request(self, data: Dict) -> Dict:
|
def handle_cm_upsert_user_print_api_request(self, data: Dict) -> Dict:
|
||||||
|
@ -705,9 +705,7 @@ class OngekiItemData(BaseData):
|
|||||||
user=aime_id, serialId=serial_id, **user_print_data
|
user=aime_id, serialId=serial_id, **user_print_data
|
||||||
)
|
)
|
||||||
|
|
||||||
conflict = sql.on_duplicate_key_update(
|
conflict = sql.on_duplicate_key_update(user=aime_id, **user_print_data)
|
||||||
user=aime_id, **user_print_data
|
|
||||||
)
|
|
||||||
result = self.execute(conflict)
|
result = self.execute(conflict)
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
|
@ -74,27 +74,21 @@ class PokkenBase:
|
|||||||
|
|
||||||
return res.SerializeToString()
|
return res.SerializeToString()
|
||||||
|
|
||||||
def handle_save_client_log(
|
def handle_save_client_log(self, request: jackal_pb2.Request) -> bytes:
|
||||||
self, request: jackal_pb2.Request
|
|
||||||
) -> bytes:
|
|
||||||
res = jackal_pb2.Response()
|
res = jackal_pb2.Response()
|
||||||
res.result = 1
|
res.result = 1
|
||||||
res.type = jackal_pb2.MessageType.SAVE_CLIENT_LOG
|
res.type = jackal_pb2.MessageType.SAVE_CLIENT_LOG
|
||||||
|
|
||||||
return res.SerializeToString()
|
return res.SerializeToString()
|
||||||
|
|
||||||
def handle_check_diagnosis(
|
def handle_check_diagnosis(self, request: jackal_pb2.Request) -> bytes:
|
||||||
self, request: jackal_pb2.Request
|
|
||||||
) -> bytes:
|
|
||||||
res = jackal_pb2.Response()
|
res = jackal_pb2.Response()
|
||||||
res.result = 1
|
res.result = 1
|
||||||
res.type = jackal_pb2.MessageType.CHECK_DIAGNOSIS
|
res.type = jackal_pb2.MessageType.CHECK_DIAGNOSIS
|
||||||
|
|
||||||
return res.SerializeToString()
|
return res.SerializeToString()
|
||||||
|
|
||||||
def handle_load_client_settings(
|
def handle_load_client_settings(self, request: jackal_pb2.Request) -> bytes:
|
||||||
self, request: jackal_pb2.Request
|
|
||||||
) -> bytes:
|
|
||||||
res = jackal_pb2.Response()
|
res = jackal_pb2.Response()
|
||||||
res.result = 1
|
res.result = 1
|
||||||
res.type = jackal_pb2.MessageType.LOAD_CLIENT_SETTINGS
|
res.type = jackal_pb2.MessageType.LOAD_CLIENT_SETTINGS
|
||||||
@ -129,26 +123,28 @@ class PokkenBase:
|
|||||||
ranking.modify_date = int(datetime.now().timestamp() / 1000)
|
ranking.modify_date = int(datetime.now().timestamp() / 1000)
|
||||||
res.load_ranking.CopyFrom(ranking)
|
res.load_ranking.CopyFrom(ranking)
|
||||||
return res.SerializeToString()
|
return res.SerializeToString()
|
||||||
|
|
||||||
def handle_load_user(self, request: jackal_pb2.Request) -> bytes:
|
def handle_load_user(self, request: jackal_pb2.Request) -> bytes:
|
||||||
res = jackal_pb2.Response()
|
res = jackal_pb2.Response()
|
||||||
res.result = 1
|
res.result = 1
|
||||||
res.type = jackal_pb2.MessageType.LOAD_USER
|
res.type = jackal_pb2.MessageType.LOAD_USER
|
||||||
access_code = request.load_user.access_code
|
access_code = request.load_user.access_code
|
||||||
load_usr = jackal_pb2.LoadUserResponseData()
|
load_usr = jackal_pb2.LoadUserResponseData()
|
||||||
user_id = self.data.card.get_user_id_from_card(access_code)
|
user_id = self.data.card.get_user_id_from_card(access_code)
|
||||||
|
|
||||||
if user_id is None and self.game_cfg.server.auto_register:
|
if user_id is None and self.game_cfg.server.auto_register:
|
||||||
user_id = self.data.user.create_user()
|
user_id = self.data.user.create_user()
|
||||||
card_id = self.data.card.create_card(user_id, access_code)
|
card_id = self.data.card.create_card(user_id, access_code)
|
||||||
|
|
||||||
self.logger.info(f"Register new card {access_code} (UserId {user_id}, CardId {card_id})")
|
self.logger.info(
|
||||||
|
f"Register new card {access_code} (UserId {user_id}, CardId {card_id})"
|
||||||
|
)
|
||||||
|
|
||||||
elif user_id is None:
|
elif user_id is None:
|
||||||
self.logger.info(f"Registration of card {access_code} blocked!")
|
self.logger.info(f"Registration of card {access_code} blocked!")
|
||||||
res.load_user.CopyFrom(load_usr)
|
res.load_user.CopyFrom(load_usr)
|
||||||
return res.SerializeToString()
|
return res.SerializeToString()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
TODO: Add repeated values
|
TODO: Add repeated values
|
||||||
tutorial_progress_flag
|
tutorial_progress_flag
|
||||||
@ -168,12 +164,12 @@ class PokkenBase:
|
|||||||
load_usr.load_hash = 1
|
load_usr.load_hash = 1
|
||||||
load_usr.cardlock_status = False
|
load_usr.cardlock_status = False
|
||||||
load_usr.banapass_id = user_id
|
load_usr.banapass_id = user_id
|
||||||
load_usr.access_code = access_code
|
load_usr.access_code = access_code
|
||||||
load_usr.precedent_release_flag = 0xFFFFFFFF
|
load_usr.precedent_release_flag = 0xFFFFFFFF
|
||||||
|
|
||||||
if profile is None:
|
if profile is None:
|
||||||
profile_id = self.data.profile.create_profile(user_id)
|
profile_id = self.data.profile.create_profile(user_id)
|
||||||
profile_dict = {'id': profile_id, 'user': user_id}
|
profile_dict = {"id": profile_id, "user": user_id}
|
||||||
pokemon_data = []
|
pokemon_data = []
|
||||||
tutorial_progress = []
|
tutorial_progress = []
|
||||||
rankmatch_progress = []
|
rankmatch_progress = []
|
||||||
@ -181,10 +177,12 @@ class PokkenBase:
|
|||||||
event_achievement_flag = []
|
event_achievement_flag = []
|
||||||
event_achievement_param = []
|
event_achievement_param = []
|
||||||
load_usr.new_card_flag = True
|
load_usr.new_card_flag = True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
profile_dict = { k: v for k, v in profile._asdict().items() if v is not None }
|
profile_dict = {k: v for k, v in profile._asdict().items() if v is not None}
|
||||||
self.logger.info(f"Card-in user {user_id} (Trainer name {profile_dict.get('trainer_name', '')})")
|
self.logger.info(
|
||||||
|
f"Card-in user {user_id} (Trainer name {profile_dict.get('trainer_name', '')})"
|
||||||
|
)
|
||||||
pokemon_data = self.data.profile.get_all_pokemon_data(user_id)
|
pokemon_data = self.data.profile.get_all_pokemon_data(user_id)
|
||||||
tutorial_progress = []
|
tutorial_progress = []
|
||||||
rankmatch_progress = []
|
rankmatch_progress = []
|
||||||
@ -193,76 +191,78 @@ class PokkenBase:
|
|||||||
event_achievement_param = []
|
event_achievement_param = []
|
||||||
load_usr.new_card_flag = False
|
load_usr.new_card_flag = False
|
||||||
|
|
||||||
load_usr.navi_newbie_flag = profile_dict.get('navi_newbie_flag', True)
|
load_usr.navi_newbie_flag = profile_dict.get("navi_newbie_flag", True)
|
||||||
load_usr.navi_enable_flag = profile_dict.get('navi_enable_flag', True)
|
load_usr.navi_enable_flag = profile_dict.get("navi_enable_flag", True)
|
||||||
load_usr.pad_vibrate_flag = profile_dict.get('pad_vibrate_flag', True)
|
load_usr.pad_vibrate_flag = profile_dict.get("pad_vibrate_flag", True)
|
||||||
load_usr.home_region_code = profile_dict.get('home_region_code', 0)
|
load_usr.home_region_code = profile_dict.get("home_region_code", 0)
|
||||||
load_usr.home_loc_name = profile_dict.get('home_loc_name', "")
|
load_usr.home_loc_name = profile_dict.get("home_loc_name", "")
|
||||||
load_usr.pref_code = profile_dict.get('pref_code', 0)
|
load_usr.pref_code = profile_dict.get("pref_code", 0)
|
||||||
load_usr.trainer_name = profile_dict.get('trainer_name', "Newb" + str(random.randint(1111,999999)))
|
load_usr.trainer_name = profile_dict.get(
|
||||||
load_usr.trainer_rank_point = profile_dict.get('trainer_rank_point', 0)
|
"trainer_name", "Newb" + str(random.randint(1111, 999999))
|
||||||
load_usr.wallet = profile_dict.get('wallet', 0)
|
)
|
||||||
load_usr.fight_money = profile_dict.get('fight_money', 0)
|
load_usr.trainer_rank_point = profile_dict.get("trainer_rank_point", 0)
|
||||||
load_usr.score_point = profile_dict.get('score_point', 0)
|
load_usr.wallet = profile_dict.get("wallet", 0)
|
||||||
load_usr.grade_max_num = profile_dict.get('grade_max_num', 0)
|
load_usr.fight_money = profile_dict.get("fight_money", 0)
|
||||||
load_usr.extra_counter = profile_dict.get('extra_counter', 0)
|
load_usr.score_point = profile_dict.get("score_point", 0)
|
||||||
load_usr.total_play_days = profile_dict.get('total_play_days', 0)
|
load_usr.grade_max_num = profile_dict.get("grade_max_num", 0)
|
||||||
load_usr.play_date_time = profile_dict.get('play_date_time', 0)
|
load_usr.extra_counter = profile_dict.get("extra_counter", 0)
|
||||||
load_usr.lucky_box_fail_num = profile_dict.get('lucky_box_fail_num', 0)
|
load_usr.total_play_days = profile_dict.get("total_play_days", 0)
|
||||||
load_usr.event_reward_get_flag = profile_dict.get('event_reward_get_flag', 0)
|
load_usr.play_date_time = profile_dict.get("play_date_time", 0)
|
||||||
load_usr.rank_pvp_all = profile_dict.get('rank_pvp_all', 0)
|
load_usr.lucky_box_fail_num = profile_dict.get("lucky_box_fail_num", 0)
|
||||||
load_usr.rank_pvp_loc = profile_dict.get('rank_pvp_loc', 0)
|
load_usr.event_reward_get_flag = profile_dict.get("event_reward_get_flag", 0)
|
||||||
load_usr.rank_cpu_all = profile_dict.get('rank_cpu_all', 0)
|
load_usr.rank_pvp_all = profile_dict.get("rank_pvp_all", 0)
|
||||||
load_usr.rank_cpu_loc = profile_dict.get('rank_cpu_loc', 0)
|
load_usr.rank_pvp_loc = profile_dict.get("rank_pvp_loc", 0)
|
||||||
load_usr.rank_event = profile_dict.get('rank_event', 0)
|
load_usr.rank_cpu_all = profile_dict.get("rank_cpu_all", 0)
|
||||||
load_usr.awake_num = profile_dict.get('awake_num', 0)
|
load_usr.rank_cpu_loc = profile_dict.get("rank_cpu_loc", 0)
|
||||||
load_usr.use_support_num = profile_dict.get('use_support_num', 0)
|
load_usr.rank_event = profile_dict.get("rank_event", 0)
|
||||||
load_usr.rankmatch_flag = profile_dict.get('rankmatch_flag', 0)
|
load_usr.awake_num = profile_dict.get("awake_num", 0)
|
||||||
load_usr.rankmatch_max = profile_dict.get('rankmatch_max', 0)
|
load_usr.use_support_num = profile_dict.get("use_support_num", 0)
|
||||||
load_usr.rankmatch_success = profile_dict.get('rankmatch_success', 0)
|
load_usr.rankmatch_flag = profile_dict.get("rankmatch_flag", 0)
|
||||||
load_usr.beat_num = profile_dict.get('beat_num', 0)
|
load_usr.rankmatch_max = profile_dict.get("rankmatch_max", 0)
|
||||||
load_usr.title_text_id = profile_dict.get('title_text_id', 0)
|
load_usr.rankmatch_success = profile_dict.get("rankmatch_success", 0)
|
||||||
load_usr.title_plate_id = profile_dict.get('title_plate_id', 0)
|
load_usr.beat_num = profile_dict.get("beat_num", 0)
|
||||||
load_usr.title_decoration_id = profile_dict.get('title_decoration_id', 0)
|
load_usr.title_text_id = profile_dict.get("title_text_id", 0)
|
||||||
load_usr.navi_trainer = profile_dict.get('navi_trainer', 0)
|
load_usr.title_plate_id = profile_dict.get("title_plate_id", 0)
|
||||||
load_usr.navi_version_id = profile_dict.get('navi_version_id', 0)
|
load_usr.title_decoration_id = profile_dict.get("title_decoration_id", 0)
|
||||||
load_usr.aid_skill = profile_dict.get('aid_skill', 0)
|
load_usr.navi_trainer = profile_dict.get("navi_trainer", 0)
|
||||||
load_usr.comment_text_id = profile_dict.get('comment_text_id', 0)
|
load_usr.navi_version_id = profile_dict.get("navi_version_id", 0)
|
||||||
load_usr.comment_word_id = profile_dict.get('comment_word_id', 0)
|
load_usr.aid_skill = profile_dict.get("aid_skill", 0)
|
||||||
load_usr.latest_use_pokemon = profile_dict.get('latest_use_pokemon', 0)
|
load_usr.comment_text_id = profile_dict.get("comment_text_id", 0)
|
||||||
load_usr.ex_ko_num = profile_dict.get('ex_ko_num', 0)
|
load_usr.comment_word_id = profile_dict.get("comment_word_id", 0)
|
||||||
load_usr.wko_num = profile_dict.get('wko_num', 0)
|
load_usr.latest_use_pokemon = profile_dict.get("latest_use_pokemon", 0)
|
||||||
load_usr.timeup_win_num = profile_dict.get('timeup_win_num', 0)
|
load_usr.ex_ko_num = profile_dict.get("ex_ko_num", 0)
|
||||||
load_usr.cool_ko_num = profile_dict.get('cool_ko_num', 0)
|
load_usr.wko_num = profile_dict.get("wko_num", 0)
|
||||||
load_usr.perfect_ko_num = profile_dict.get('perfect_ko_num', 0)
|
load_usr.timeup_win_num = profile_dict.get("timeup_win_num", 0)
|
||||||
load_usr.record_flag = profile_dict.get('record_flag', 0)
|
load_usr.cool_ko_num = profile_dict.get("cool_ko_num", 0)
|
||||||
load_usr.site_register_status = profile_dict.get('site_register_status', 0)
|
load_usr.perfect_ko_num = profile_dict.get("perfect_ko_num", 0)
|
||||||
load_usr.continue_num = profile_dict.get('continue_num', 0)
|
load_usr.record_flag = profile_dict.get("record_flag", 0)
|
||||||
|
load_usr.site_register_status = profile_dict.get("site_register_status", 0)
|
||||||
|
load_usr.continue_num = profile_dict.get("continue_num", 0)
|
||||||
|
|
||||||
load_usr.avatar_body = profile_dict.get('avatar_body', 0)
|
load_usr.avatar_body = profile_dict.get("avatar_body", 0)
|
||||||
load_usr.avatar_gender = profile_dict.get('avatar_gender', 0)
|
load_usr.avatar_gender = profile_dict.get("avatar_gender", 0)
|
||||||
load_usr.avatar_background = profile_dict.get('avatar_background', 0)
|
load_usr.avatar_background = profile_dict.get("avatar_background", 0)
|
||||||
load_usr.avatar_head = profile_dict.get('avatar_head', 0)
|
load_usr.avatar_head = profile_dict.get("avatar_head", 0)
|
||||||
load_usr.avatar_battleglass = profile_dict.get('avatar_battleglass', 0)
|
load_usr.avatar_battleglass = profile_dict.get("avatar_battleglass", 0)
|
||||||
load_usr.avatar_face0 = profile_dict.get('avatar_face0', 0)
|
load_usr.avatar_face0 = profile_dict.get("avatar_face0", 0)
|
||||||
load_usr.avatar_face1 = profile_dict.get('avatar_face1', 0)
|
load_usr.avatar_face1 = profile_dict.get("avatar_face1", 0)
|
||||||
load_usr.avatar_face2 = profile_dict.get('avatar_face2', 0)
|
load_usr.avatar_face2 = profile_dict.get("avatar_face2", 0)
|
||||||
load_usr.avatar_bodyall = profile_dict.get('avatar_bodyall', 0)
|
load_usr.avatar_bodyall = profile_dict.get("avatar_bodyall", 0)
|
||||||
load_usr.avatar_wear = profile_dict.get('avatar_wear', 0)
|
load_usr.avatar_wear = profile_dict.get("avatar_wear", 0)
|
||||||
load_usr.avatar_accessory = profile_dict.get('avatar_accessory', 0)
|
load_usr.avatar_accessory = profile_dict.get("avatar_accessory", 0)
|
||||||
load_usr.avatar_stamp = profile_dict.get('avatar_stamp', 0)
|
load_usr.avatar_stamp = profile_dict.get("avatar_stamp", 0)
|
||||||
|
|
||||||
load_usr.event_state = profile_dict.get('event_state', 0)
|
load_usr.event_state = profile_dict.get("event_state", 0)
|
||||||
load_usr.event_id = profile_dict.get('event_id', 0)
|
load_usr.event_id = profile_dict.get("event_id", 0)
|
||||||
load_usr.sp_bonus_category_id_1 = profile_dict.get('sp_bonus_category_id_1', 0)
|
load_usr.sp_bonus_category_id_1 = profile_dict.get("sp_bonus_category_id_1", 0)
|
||||||
load_usr.sp_bonus_key_value_1 = profile_dict.get('sp_bonus_key_value_1', 0)
|
load_usr.sp_bonus_key_value_1 = profile_dict.get("sp_bonus_key_value_1", 0)
|
||||||
load_usr.sp_bonus_category_id_2 = profile_dict.get('sp_bonus_category_id_2', 0)
|
load_usr.sp_bonus_category_id_2 = profile_dict.get("sp_bonus_category_id_2", 0)
|
||||||
load_usr.sp_bonus_key_value_2 = profile_dict.get('sp_bonus_key_value_2', 0)
|
load_usr.sp_bonus_key_value_2 = profile_dict.get("sp_bonus_key_value_2", 0)
|
||||||
load_usr.last_play_event_id = profile_dict.get('last_play_event_id', 0)
|
load_usr.last_play_event_id = profile_dict.get("last_play_event_id", 0)
|
||||||
|
|
||||||
res.load_user.CopyFrom(load_usr)
|
res.load_user.CopyFrom(load_usr)
|
||||||
return res.SerializeToString()
|
return res.SerializeToString()
|
||||||
|
|
||||||
def handle_set_bnpassid_lock(self, data: jackal_pb2.Request) -> bytes:
|
def handle_set_bnpassid_lock(self, data: jackal_pb2.Request) -> bytes:
|
||||||
res = jackal_pb2.Response()
|
res = jackal_pb2.Response()
|
||||||
res.result = 1
|
res.result = 1
|
||||||
@ -288,22 +288,30 @@ class PokkenBase:
|
|||||||
res.type = jackal_pb2.MessageType.SAVE_CHARGE
|
res.type = jackal_pb2.MessageType.SAVE_CHARGE
|
||||||
return res.SerializeToString()
|
return res.SerializeToString()
|
||||||
|
|
||||||
def handle_matching_noop(self, data: Dict = {}, client_ip: str = "127.0.0.1") -> Dict:
|
def handle_matching_noop(
|
||||||
return {}
|
self, data: Dict = {}, client_ip: str = "127.0.0.1"
|
||||||
|
) -> Dict:
|
||||||
def handle_matching_start_matching(self, data: Dict = {}, client_ip: str = "127.0.0.1") -> Dict:
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def handle_matching_is_matching(self, data: Dict = {}, client_ip: str = "127.0.0.1") -> Dict:
|
def handle_matching_start_matching(
|
||||||
|
self, data: Dict = {}, client_ip: str = "127.0.0.1"
|
||||||
|
) -> Dict:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def handle_matching_is_matching(
|
||||||
|
self, data: Dict = {}, client_ip: str = "127.0.0.1"
|
||||||
|
) -> Dict:
|
||||||
"""
|
"""
|
||||||
"sessionId":"12345678",
|
"sessionId":"12345678",
|
||||||
"A":{
|
"A":{
|
||||||
"pcb_id": data["data"]["must"]["pcb_id"],
|
"pcb_id": data["data"]["must"]["pcb_id"],
|
||||||
"gip": client_ip
|
"gip": client_ip
|
||||||
},
|
},
|
||||||
"list":[]
|
"list":[]
|
||||||
"""
|
"""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def handle_matching_stop_matching(self, data: Dict = {}, client_ip: str = "127.0.0.1") -> Dict:
|
def handle_matching_stop_matching(
|
||||||
return {}
|
self, data: Dict = {}, client_ip: str = "127.0.0.1"
|
||||||
|
) -> Dict:
|
||||||
|
return {}
|
||||||
|
@ -59,6 +59,7 @@ class PokkenServerConfig:
|
|||||||
self.__config, "pokken", "server", "auto_register", default=True
|
self.__config, "pokken", "server", "auto_register", default=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PokkenConfig(dict):
|
class PokkenConfig(dict):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.server = PokkenServerConfig(self)
|
self.server = PokkenServerConfig(self)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class PokkenConstants:
|
class PokkenConstants:
|
||||||
GAME_CODE = "SDAK"
|
GAME_CODE = "SDAK"
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ from core.config import CoreConfig
|
|||||||
|
|
||||||
from .schema import *
|
from .schema import *
|
||||||
|
|
||||||
|
|
||||||
class PokkenData(Data):
|
class PokkenData(Data):
|
||||||
def __init__(self, cfg: CoreConfig) -> None:
|
def __init__(self, cfg: CoreConfig) -> None:
|
||||||
super().__init__(cfg)
|
super().__init__(cfg)
|
||||||
|
@ -114,19 +114,19 @@ class PokkenServlet(resource.Resource):
|
|||||||
endpoint = jackal_pb2.MessageType.DESCRIPTOR.values_by_number[
|
endpoint = jackal_pb2.MessageType.DESCRIPTOR.values_by_number[
|
||||||
pokken_request.type
|
pokken_request.type
|
||||||
].name.lower()
|
].name.lower()
|
||||||
|
|
||||||
self.logger.debug(pokken_request)
|
self.logger.debug(pokken_request)
|
||||||
|
|
||||||
handler = getattr(self.base, f"handle_{endpoint}", None)
|
handler = getattr(self.base, f"handle_{endpoint}", None)
|
||||||
if handler is None:
|
if handler is None:
|
||||||
self.logger.warn(f"No handler found for message type {endpoint}")
|
self.logger.warn(f"No handler found for message type {endpoint}")
|
||||||
return self.base.handle_noop(pokken_request)
|
return self.base.handle_noop(pokken_request)
|
||||||
|
|
||||||
self.logger.info(f"{endpoint} request from {Utils.get_ip_addr(request)}")
|
self.logger.info(f"{endpoint} request from {Utils.get_ip_addr(request)}")
|
||||||
|
|
||||||
ret = handler(pokken_request)
|
ret = handler(pokken_request)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def handle_matching(self, request: Request) -> bytes:
|
def handle_matching(self, request: Request) -> bytes:
|
||||||
content = request.content.getvalue()
|
content = request.content.getvalue()
|
||||||
client_ip = Utils.get_ip_addr(request)
|
client_ip = Utils.get_ip_addr(request)
|
||||||
@ -135,26 +135,37 @@ class PokkenServlet(resource.Resource):
|
|||||||
self.logger.info("Empty matching request")
|
self.logger.info("Empty matching request")
|
||||||
return json.dumps(self.base.handle_matching_noop()).encode()
|
return json.dumps(self.base.handle_matching_noop()).encode()
|
||||||
|
|
||||||
json_content = ast.literal_eval(content.decode().replace('null', 'None').replace('true', 'True').replace('false', 'False'))
|
json_content = ast.literal_eval(
|
||||||
|
content.decode()
|
||||||
|
.replace("null", "None")
|
||||||
|
.replace("true", "True")
|
||||||
|
.replace("false", "False")
|
||||||
|
)
|
||||||
self.logger.info(f"Matching {json_content['call']} request")
|
self.logger.info(f"Matching {json_content['call']} request")
|
||||||
self.logger.debug(json_content)
|
self.logger.debug(json_content)
|
||||||
|
|
||||||
handler = getattr(self.base, f"handle_matching_{inflection.underscore(json_content['call'])}", None)
|
handler = getattr(
|
||||||
|
self.base,
|
||||||
|
f"handle_matching_{inflection.underscore(json_content['call'])}",
|
||||||
|
None,
|
||||||
|
)
|
||||||
if handler is None:
|
if handler is None:
|
||||||
self.logger.warn(f"No handler found for message type {json_content['call']}")
|
self.logger.warn(
|
||||||
|
f"No handler found for message type {json_content['call']}"
|
||||||
|
)
|
||||||
return json.dumps(self.base.handle_matching_noop()).encode()
|
return json.dumps(self.base.handle_matching_noop()).encode()
|
||||||
|
|
||||||
ret = handler(json_content, client_ip)
|
ret = handler(json_content, client_ip)
|
||||||
|
|
||||||
if ret is None:
|
if ret is None:
|
||||||
ret = {}
|
ret = {}
|
||||||
if "result" not in ret:
|
if "result" not in ret:
|
||||||
ret["result"] = "true"
|
ret["result"] = "true"
|
||||||
if "data" not in ret:
|
if "data" not in ret:
|
||||||
ret["data"] = {}
|
ret["data"] = {}
|
||||||
if "timestamp" not in ret:
|
if "timestamp" not in ret:
|
||||||
ret["timestamp"] = int(datetime.now().timestamp() * 1000)
|
ret["timestamp"] = int(datetime.now().timestamp() * 1000)
|
||||||
|
|
||||||
self.logger.debug(f"Response {ret}")
|
self.logger.debug(f"Response {ret}")
|
||||||
|
|
||||||
return json.dumps(ret).encode()
|
return json.dumps(ret).encode()
|
||||||
|
@ -9,19 +9,26 @@ from sqlalchemy.dialects.mysql import insert
|
|||||||
from core.data.schema import BaseData, metadata
|
from core.data.schema import BaseData, metadata
|
||||||
|
|
||||||
item = Table(
|
item = Table(
|
||||||
'pokken_item',
|
"pokken_item",
|
||||||
metadata,
|
metadata,
|
||||||
Column('id', Integer, primary_key=True, nullable=False),
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
Column('user', ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False, unique=True),
|
Column(
|
||||||
Column('category', Integer),
|
"user",
|
||||||
Column('content', Integer),
|
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
|
||||||
Column('type', Integer),
|
nullable=False,
|
||||||
UniqueConstraint('user', 'category', 'content', 'type', name='pokken_item_uk'),
|
unique=True,
|
||||||
|
),
|
||||||
|
Column("category", Integer),
|
||||||
|
Column("content", Integer),
|
||||||
|
Column("type", Integer),
|
||||||
|
UniqueConstraint("user", "category", "content", "type", name="pokken_item_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PokkenItemData(BaseData):
|
class PokkenItemData(BaseData):
|
||||||
"""
|
"""
|
||||||
Items obtained as rewards
|
Items obtained as rewards
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
@ -10,29 +10,35 @@ from core.data.schema import BaseData, metadata
|
|||||||
|
|
||||||
# Pokken sends depressingly little match data...
|
# Pokken sends depressingly little match data...
|
||||||
match_data = Table(
|
match_data = Table(
|
||||||
'pokken_match_data',
|
"pokken_match_data",
|
||||||
metadata,
|
metadata,
|
||||||
Column('id', Integer, primary_key=True, nullable=False),
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
Column('user', ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
Column(
|
||||||
Column('num_games', Integer),
|
"user",
|
||||||
Column('play_modes', JSON),
|
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
|
||||||
Column('results', JSON),
|
nullable=False,
|
||||||
Column('ex_ko_num', Integer),
|
),
|
||||||
Column('wko_num', Integer),
|
Column("num_games", Integer),
|
||||||
Column('timeup_win_num', Integer),
|
Column("play_modes", JSON),
|
||||||
Column('cool_ko_num', Integer),
|
Column("results", JSON),
|
||||||
Column('perfect_ko_num', Integer),
|
Column("ex_ko_num", Integer),
|
||||||
Column('use_navi', Integer),
|
Column("wko_num", Integer),
|
||||||
Column('use_navi_cloth', Integer),
|
Column("timeup_win_num", Integer),
|
||||||
Column('use_aid_skill', Integer),
|
Column("cool_ko_num", Integer),
|
||||||
Column('play_date', TIMESTAMP),
|
Column("perfect_ko_num", Integer),
|
||||||
|
Column("use_navi", Integer),
|
||||||
|
Column("use_navi_cloth", Integer),
|
||||||
|
Column("use_aid_skill", Integer),
|
||||||
|
Column("play_date", TIMESTAMP),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PokkenMatchData(BaseData):
|
class PokkenMatchData(BaseData):
|
||||||
"""
|
"""
|
||||||
Match logs
|
Match logs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def save_match(self, user_id: int, match_data: Dict) -> Optional[int]:
|
def save_match(self, user_id: int, match_data: Dict) -> Optional[int]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -43,4 +49,4 @@ class PokkenMatchData(BaseData):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def get_matches(self, limit: int = 20) -> Optional[List[Row]]:
|
def get_matches(self, limit: int = 20) -> Optional[List[Row]]:
|
||||||
pass
|
pass
|
||||||
|
@ -12,150 +12,179 @@ from ..const import PokkenConstants
|
|||||||
# Some more of the repeated fields could probably be their own tables, for now I just did the ones that made sense to me
|
# Some more of the repeated fields could probably be their own tables, for now I just did the ones that made sense to me
|
||||||
# Having the profile table be this massive kinda blows for updates but w/e, **kwargs to the rescue
|
# Having the profile table be this massive kinda blows for updates but w/e, **kwargs to the rescue
|
||||||
profile = Table(
|
profile = Table(
|
||||||
'pokken_profile',
|
"pokken_profile",
|
||||||
metadata,
|
metadata,
|
||||||
Column('id', Integer, primary_key=True, nullable=False),
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
Column('user', ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False, unique=True),
|
Column(
|
||||||
Column('trainer_name', String(16)), # optional
|
"user",
|
||||||
Column('home_region_code', Integer),
|
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
|
||||||
Column('home_loc_name', String(255)),
|
nullable=False,
|
||||||
Column('pref_code', Integer),
|
unique=True,
|
||||||
Column('navi_newbie_flag', Boolean),
|
),
|
||||||
Column('navi_enable_flag', Boolean),
|
Column("trainer_name", String(16)), # optional
|
||||||
Column('pad_vibrate_flag', Boolean),
|
Column("home_region_code", Integer),
|
||||||
Column('trainer_rank_point', Integer),
|
Column("home_loc_name", String(255)),
|
||||||
Column('wallet', Integer),
|
Column("pref_code", Integer),
|
||||||
Column('fight_money', Integer),
|
Column("navi_newbie_flag", Boolean),
|
||||||
Column('score_point', Integer),
|
Column("navi_enable_flag", Boolean),
|
||||||
Column('grade_max_num', Integer),
|
Column("pad_vibrate_flag", Boolean),
|
||||||
Column('extra_counter', Integer), # Optional
|
Column("trainer_rank_point", Integer),
|
||||||
Column('tutorial_progress_flag', JSON), # Repeated, Integer
|
Column("wallet", Integer),
|
||||||
Column('total_play_days', Integer),
|
Column("fight_money", Integer),
|
||||||
Column('play_date_time', Integer),
|
Column("score_point", Integer),
|
||||||
Column('achievement_flag', JSON), # Repeated, Integer
|
Column("grade_max_num", Integer),
|
||||||
Column('lucky_box_fail_num', Integer),
|
Column("extra_counter", Integer), # Optional
|
||||||
Column('event_reward_get_flag', Integer),
|
Column("tutorial_progress_flag", JSON), # Repeated, Integer
|
||||||
Column('rank_pvp_all', Integer),
|
Column("total_play_days", Integer),
|
||||||
Column('rank_pvp_loc', Integer),
|
Column("play_date_time", Integer),
|
||||||
Column('rank_cpu_all', Integer),
|
Column("achievement_flag", JSON), # Repeated, Integer
|
||||||
Column('rank_cpu_loc', Integer),
|
Column("lucky_box_fail_num", Integer),
|
||||||
Column('rank_event', Integer),
|
Column("event_reward_get_flag", Integer),
|
||||||
Column('awake_num', Integer),
|
Column("rank_pvp_all", Integer),
|
||||||
Column('use_support_num', Integer),
|
Column("rank_pvp_loc", Integer),
|
||||||
Column('rankmatch_flag', Integer),
|
Column("rank_cpu_all", Integer),
|
||||||
Column('rankmatch_max', Integer), # Optional
|
Column("rank_cpu_loc", Integer),
|
||||||
Column('rankmatch_progress', JSON), # Repeated, Integer
|
Column("rank_event", Integer),
|
||||||
Column('rankmatch_success', Integer), # Optional
|
Column("awake_num", Integer),
|
||||||
Column('beat_num', Integer), # Optional
|
Column("use_support_num", Integer),
|
||||||
Column('title_text_id', Integer),
|
Column("rankmatch_flag", Integer),
|
||||||
Column('title_plate_id', Integer),
|
Column("rankmatch_max", Integer), # Optional
|
||||||
Column('title_decoration_id', Integer),
|
Column("rankmatch_progress", JSON), # Repeated, Integer
|
||||||
Column('support_pokemon_list', JSON), # Repeated, Integer
|
Column("rankmatch_success", Integer), # Optional
|
||||||
Column('support_set_1_1', Integer), # Repeated, Integer
|
Column("beat_num", Integer), # Optional
|
||||||
Column('support_set_1_2', Integer),
|
Column("title_text_id", Integer),
|
||||||
Column('support_set_2_1', Integer), # Repeated, Integer
|
Column("title_plate_id", Integer),
|
||||||
Column('support_set_2_2', Integer),
|
Column("title_decoration_id", Integer),
|
||||||
Column('support_set_3_1', Integer), # Repeated, Integer
|
Column("support_pokemon_list", JSON), # Repeated, Integer
|
||||||
Column('support_set_3_2', Integer),
|
Column("support_set_1_1", Integer), # Repeated, Integer
|
||||||
Column('navi_trainer', Integer),
|
Column("support_set_1_2", Integer),
|
||||||
Column('navi_version_id', Integer),
|
Column("support_set_2_1", Integer), # Repeated, Integer
|
||||||
Column('aid_skill_list', JSON), # Repeated, Integer
|
Column("support_set_2_2", Integer),
|
||||||
Column('aid_skill', Integer),
|
Column("support_set_3_1", Integer), # Repeated, Integer
|
||||||
Column('comment_text_id', Integer),
|
Column("support_set_3_2", Integer),
|
||||||
Column('comment_word_id', Integer),
|
Column("navi_trainer", Integer),
|
||||||
Column('latest_use_pokemon', Integer),
|
Column("navi_version_id", Integer),
|
||||||
Column('ex_ko_num', Integer),
|
Column("aid_skill_list", JSON), # Repeated, Integer
|
||||||
Column('wko_num', Integer),
|
Column("aid_skill", Integer),
|
||||||
Column('timeup_win_num', Integer),
|
Column("comment_text_id", Integer),
|
||||||
Column('cool_ko_num', Integer),
|
Column("comment_word_id", Integer),
|
||||||
Column('perfect_ko_num', Integer),
|
Column("latest_use_pokemon", Integer),
|
||||||
Column('record_flag', Integer),
|
Column("ex_ko_num", Integer),
|
||||||
Column('continue_num', Integer),
|
Column("wko_num", Integer),
|
||||||
Column('avatar_body', Integer), # Optional
|
Column("timeup_win_num", Integer),
|
||||||
Column('avatar_gender', Integer), # Optional
|
Column("cool_ko_num", Integer),
|
||||||
Column('avatar_background', Integer), # Optional
|
Column("perfect_ko_num", Integer),
|
||||||
Column('avatar_head', Integer), # Optional
|
Column("record_flag", Integer),
|
||||||
Column('avatar_battleglass', Integer), # Optional
|
Column("continue_num", Integer),
|
||||||
Column('avatar_face0', Integer), # Optional
|
Column("avatar_body", Integer), # Optional
|
||||||
Column('avatar_face1', Integer), # Optional
|
Column("avatar_gender", Integer), # Optional
|
||||||
Column('avatar_face2', Integer), # Optional
|
Column("avatar_background", Integer), # Optional
|
||||||
Column('avatar_bodyall', Integer), # Optional
|
Column("avatar_head", Integer), # Optional
|
||||||
Column('avatar_wear', Integer), # Optional
|
Column("avatar_battleglass", Integer), # Optional
|
||||||
Column('avatar_accessory', Integer), # Optional
|
Column("avatar_face0", Integer), # Optional
|
||||||
Column('avatar_stamp', Integer), # Optional
|
Column("avatar_face1", Integer), # Optional
|
||||||
Column('event_state', Integer),
|
Column("avatar_face2", Integer), # Optional
|
||||||
Column('event_id', Integer),
|
Column("avatar_bodyall", Integer), # Optional
|
||||||
Column('sp_bonus_category_id_1', Integer),
|
Column("avatar_wear", Integer), # Optional
|
||||||
Column('sp_bonus_key_value_1', Integer),
|
Column("avatar_accessory", Integer), # Optional
|
||||||
Column('sp_bonus_category_id_2', Integer),
|
Column("avatar_stamp", Integer), # Optional
|
||||||
Column('sp_bonus_key_value_2', Integer),
|
Column("event_state", Integer),
|
||||||
Column('last_play_event_id', Integer), # Optional
|
Column("event_id", Integer),
|
||||||
Column('event_achievement_flag', JSON), # Repeated, Integer
|
Column("sp_bonus_category_id_1", Integer),
|
||||||
Column('event_achievement_param', JSON), # Repeated, Integer
|
Column("sp_bonus_key_value_1", Integer),
|
||||||
Column('battle_num_vs_wan', Integer), # 4?
|
Column("sp_bonus_category_id_2", Integer),
|
||||||
Column('win_vs_wan', Integer),
|
Column("sp_bonus_key_value_2", Integer),
|
||||||
Column('battle_num_vs_lan', Integer), # 3?
|
Column("last_play_event_id", Integer), # Optional
|
||||||
Column('win_vs_lan', Integer),
|
Column("event_achievement_flag", JSON), # Repeated, Integer
|
||||||
Column('battle_num_vs_cpu', Integer), # 2
|
Column("event_achievement_param", JSON), # Repeated, Integer
|
||||||
Column('win_cpu', Integer),
|
Column("battle_num_vs_wan", Integer), # 4?
|
||||||
Column('battle_num_tutorial', Integer), # 1?
|
Column("win_vs_wan", Integer),
|
||||||
mysql_charset="utf8mb4"
|
Column("battle_num_vs_lan", Integer), # 3?
|
||||||
|
Column("win_vs_lan", Integer),
|
||||||
|
Column("battle_num_vs_cpu", Integer), # 2
|
||||||
|
Column("win_cpu", Integer),
|
||||||
|
Column("battle_num_tutorial", Integer), # 1?
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
|
|
||||||
pokemon_data = Table(
|
pokemon_data = Table(
|
||||||
'pokken_pokemon_data',
|
"pokken_pokemon_data",
|
||||||
metadata,
|
metadata,
|
||||||
Column('id', Integer, primary_key=True, nullable=False),
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
Column('user', ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), nullable=False),
|
Column(
|
||||||
Column('char_id', Integer, nullable=False),
|
"user",
|
||||||
Column('illustration_book_no', Integer),
|
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
|
||||||
Column('pokemon_exp', Integer),
|
nullable=False,
|
||||||
Column('battle_num_vs_wan', Integer), # 4?
|
),
|
||||||
Column('win_vs_wan', Integer),
|
Column("char_id", Integer, nullable=False),
|
||||||
Column('battle_num_vs_lan', Integer), # 3?
|
Column("illustration_book_no", Integer),
|
||||||
Column('win_vs_lan', Integer),
|
Column("pokemon_exp", Integer),
|
||||||
Column('battle_num_vs_cpu', Integer), # 2
|
Column("battle_num_vs_wan", Integer), # 4?
|
||||||
Column('win_cpu', Integer),
|
Column("win_vs_wan", Integer),
|
||||||
Column('battle_all_num_tutorial', Integer),
|
Column("battle_num_vs_lan", Integer), # 3?
|
||||||
Column('battle_num_tutorial', Integer), # 1?
|
Column("win_vs_lan", Integer),
|
||||||
Column('bp_point_atk', Integer),
|
Column("battle_num_vs_cpu", Integer), # 2
|
||||||
Column('bp_point_res', Integer),
|
Column("win_cpu", Integer),
|
||||||
Column('bp_point_def', Integer),
|
Column("battle_all_num_tutorial", Integer),
|
||||||
Column('bp_point_sp', Integer),
|
Column("battle_num_tutorial", Integer), # 1?
|
||||||
UniqueConstraint('user', 'char_id', name="pokken_pokemon_data_uk"),
|
Column("bp_point_atk", Integer),
|
||||||
mysql_charset="utf8mb4"
|
Column("bp_point_res", Integer),
|
||||||
|
Column("bp_point_def", Integer),
|
||||||
|
Column("bp_point_sp", Integer),
|
||||||
|
UniqueConstraint("user", "char_id", name="pokken_pokemon_data_uk"),
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PokkenProfileData(BaseData):
|
class PokkenProfileData(BaseData):
|
||||||
def create_profile(self, user_id: int) -> Optional[int]:
|
def create_profile(self, user_id: int) -> Optional[int]:
|
||||||
sql = insert(profile).values(user = user_id)
|
sql = insert(profile).values(user=user_id)
|
||||||
conflict = sql.on_duplicate_key_update(user = user_id)
|
conflict = sql.on_duplicate_key_update(user=user_id)
|
||||||
|
|
||||||
result = self.execute(conflict)
|
result = self.execute(conflict)
|
||||||
if result is None:
|
if result is None:
|
||||||
self.logger.error(f"Failed to create pokken profile for user {user_id}!")
|
self.logger.error(f"Failed to create pokken profile for user {user_id}!")
|
||||||
return None
|
return None
|
||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
def set_profile_name(self, user_id: int, new_name: str) -> None:
|
def set_profile_name(self, user_id: int, new_name: str) -> None:
|
||||||
sql = update(profile).where(profile.c.user == user_id).values(trainer_name = new_name)
|
sql = (
|
||||||
|
update(profile)
|
||||||
|
.where(profile.c.user == user_id)
|
||||||
|
.values(trainer_name=new_name)
|
||||||
|
)
|
||||||
result = self.execute(sql)
|
result = self.execute(sql)
|
||||||
if result is None:
|
if result is None:
|
||||||
self.logger.error(f"Failed to update pokken profile name for user {user_id}!")
|
self.logger.error(
|
||||||
|
f"Failed to update pokken profile name for user {user_id}!"
|
||||||
|
)
|
||||||
|
|
||||||
def update_profile_tutorial_flags(self, user_id: int, tutorial_flags: Dict) -> None:
|
def update_profile_tutorial_flags(self, user_id: int, tutorial_flags: Dict) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_profile_points(self, user_id: int, rank_pts: int, money: int, score_pts: int) -> None:
|
def add_profile_points(
|
||||||
|
self, user_id: int, rank_pts: int, money: int, score_pts: int
|
||||||
|
) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_profile(self, user_id: int) -> Optional[Row]:
|
def get_profile(self, user_id: int) -> Optional[Row]:
|
||||||
sql = profile.select(profile.c.user == user_id)
|
sql = profile.select(profile.c.user == user_id)
|
||||||
result = self.execute(sql)
|
result = self.execute(sql)
|
||||||
if result is None: return None
|
if result is None:
|
||||||
|
return None
|
||||||
return result.fetchone()
|
return result.fetchone()
|
||||||
|
|
||||||
def put_pokemon_data(self, user_id: int, pokemon_id: int, illust_no: int, get_exp: int, atk: int, res: int, defe: int, sp: int) -> Optional[int]:
|
def put_pokemon_data(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
pokemon_id: int,
|
||||||
|
illust_no: int,
|
||||||
|
get_exp: int,
|
||||||
|
atk: int,
|
||||||
|
res: int,
|
||||||
|
defe: int,
|
||||||
|
sp: int,
|
||||||
|
) -> Optional[int]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_pokemon_data(self, user_id: int, pokemon_id: int) -> Optional[Row]:
|
def get_pokemon_data(self, user_id: int, pokemon_id: int) -> Optional[Row]:
|
||||||
@ -164,13 +193,24 @@ class PokkenProfileData(BaseData):
|
|||||||
def get_all_pokemon_data(self, user_id: int) -> Optional[List[Row]]:
|
def get_all_pokemon_data(self, user_id: int) -> Optional[List[Row]]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def put_results(self, user_id: int, pokemon_id: int, match_type: int, match_result: int) -> None:
|
def put_results(
|
||||||
|
self, user_id: int, pokemon_id: int, match_type: int, match_result: int
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Records the match stats (type and win/loss) for the pokemon and profile
|
Records the match stats (type and win/loss) for the pokemon and profile
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def put_stats(self, user_id: int, exkos: int, wkos: int, timeout_wins: int, cool_kos: int, perfects: int, continues: int) -> None:
|
def put_stats(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
exkos: int,
|
||||||
|
wkos: int,
|
||||||
|
timeout_wins: int,
|
||||||
|
cool_kos: int,
|
||||||
|
perfects: int,
|
||||||
|
continues: int,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Records profile stats
|
Records profile stats
|
||||||
"""
|
"""
|
||||||
|
@ -8,5 +8,6 @@ from sqlalchemy.dialects.mysql import insert
|
|||||||
|
|
||||||
from core.data.schema import BaseData, metadata
|
from core.data.schema import BaseData, metadata
|
||||||
|
|
||||||
|
|
||||||
class PokkenStaticData(BaseData):
|
class PokkenStaticData(BaseData):
|
||||||
pass
|
pass
|
||||||
|
@ -200,18 +200,24 @@ class WaccaBase:
|
|||||||
self.logger.info(f"User {req.userId} login on {req.chipId}")
|
self.logger.info(f"User {req.userId} login on {req.chipId}")
|
||||||
last_login_time = int(profile["last_login_date"].timestamp())
|
last_login_time = int(profile["last_login_date"].timestamp())
|
||||||
resp.lastLoginDate = last_login_time
|
resp.lastLoginDate = last_login_time
|
||||||
midnight_today_ts = int(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).timestamp())
|
midnight_today_ts = int(
|
||||||
|
datetime.now()
|
||||||
|
.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
.timestamp()
|
||||||
|
)
|
||||||
|
|
||||||
# If somebodies login timestamp < midnight of current day, then they are logging in for the first time today
|
# If somebodies login timestamp < midnight of current day, then they are logging in for the first time today
|
||||||
if last_login_time < midnight_today_ts:
|
if last_login_time < midnight_today_ts:
|
||||||
resp.firstLoginDaily = True
|
resp.firstLoginDaily = True
|
||||||
|
|
||||||
# If the difference between midnight today and their last login is greater then 1 day (86400 seconds) they've broken their streak
|
# If the difference between midnight today and their last login is greater then 1 day (86400 seconds) they've broken their streak
|
||||||
if midnight_today_ts - last_login_time > 86400:
|
if midnight_today_ts - last_login_time > 86400:
|
||||||
is_consec_day = False
|
is_consec_day = False
|
||||||
|
|
||||||
self.data.profile.session_login(req.userId, resp.firstLoginDaily, is_consec_day)
|
self.data.profile.session_login(
|
||||||
|
req.userId, resp.firstLoginDaily, is_consec_day
|
||||||
|
)
|
||||||
|
|
||||||
if resp.firstLoginDaily:
|
if resp.firstLoginDaily:
|
||||||
# TODO: Daily bonus
|
# TODO: Daily bonus
|
||||||
pass
|
pass
|
||||||
@ -624,17 +630,25 @@ class WaccaBase:
|
|||||||
new_tickets.append([ticket["id"], ticket["ticket_id"], 9999999999])
|
new_tickets.append([ticket["id"], ticket["ticket_id"], 9999999999])
|
||||||
|
|
||||||
for item in req.itemsUsed:
|
for item in req.itemsUsed:
|
||||||
if item.itemType == WaccaConstants.ITEM_TYPES["wp"] and not self.game_config.mods.infinite_wp:
|
if (
|
||||||
|
item.itemType == WaccaConstants.ITEM_TYPES["wp"]
|
||||||
|
and not self.game_config.mods.infinite_wp
|
||||||
|
):
|
||||||
if current_wp >= item.quantity:
|
if current_wp >= item.quantity:
|
||||||
current_wp -= item.quantity
|
current_wp -= item.quantity
|
||||||
self.data.profile.spend_wp(req.profileId, item.quantity)
|
self.data.profile.spend_wp(req.profileId, item.quantity)
|
||||||
else:
|
else:
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
elif item.itemType == WaccaConstants.ITEM_TYPES["ticket"] and not self.game_config.mods.infinite_tickets:
|
elif (
|
||||||
|
item.itemType == WaccaConstants.ITEM_TYPES["ticket"]
|
||||||
|
and not self.game_config.mods.infinite_tickets
|
||||||
|
):
|
||||||
for x in range(len(new_tickets)):
|
for x in range(len(new_tickets)):
|
||||||
if new_tickets[x][1] == item.itemId:
|
if new_tickets[x][1] == item.itemId:
|
||||||
self.logger.debug(f"Remove ticket ID {new_tickets[x][0]} type {new_tickets[x][1]} from {user_id}")
|
self.logger.debug(
|
||||||
|
f"Remove ticket ID {new_tickets[x][0]} type {new_tickets[x][1]} from {user_id}"
|
||||||
|
)
|
||||||
self.data.item.spend_ticket(new_tickets[x][0])
|
self.data.item.spend_ticket(new_tickets[x][0])
|
||||||
new_tickets.pop(x)
|
new_tickets.pop(x)
|
||||||
break
|
break
|
||||||
@ -865,7 +879,10 @@ class WaccaBase:
|
|||||||
user_id = profile["user"]
|
user_id = profile["user"]
|
||||||
resp.currentWp = profile["wp"]
|
resp.currentWp = profile["wp"]
|
||||||
|
|
||||||
if req.purchaseType == PurchaseType.PurchaseTypeWP and not self.game_config.mods.infinite_wp:
|
if (
|
||||||
|
req.purchaseType == PurchaseType.PurchaseTypeWP
|
||||||
|
and not self.game_config.mods.infinite_wp
|
||||||
|
):
|
||||||
resp.currentWp -= req.cost
|
resp.currentWp -= req.cost
|
||||||
self.data.profile.spend_wp(req.profileId, req.cost)
|
self.data.profile.spend_wp(req.profileId, req.cost)
|
||||||
|
|
||||||
@ -1055,11 +1072,18 @@ class WaccaBase:
|
|||||||
):
|
):
|
||||||
if item.quantity > WaccaConstants.Difficulty.HARD.value:
|
if item.quantity > WaccaConstants.Difficulty.HARD.value:
|
||||||
old_score = self.data.score.get_best_score(
|
old_score = self.data.score.get_best_score(
|
||||||
user_id, item.itemId, item.quantity
|
user_id, item.itemId, item.quantity
|
||||||
)
|
)
|
||||||
if not old_score:
|
if not old_score:
|
||||||
self.data.score.put_best_score(
|
self.data.score.put_best_score(
|
||||||
user_id, item.itemId, item.quantity, 0, [0] * 5, [0] * 13, 0, 0
|
user_id,
|
||||||
|
item.itemId,
|
||||||
|
item.quantity,
|
||||||
|
0,
|
||||||
|
[0] * 5,
|
||||||
|
[0] * 13,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
if item.quantity == 0:
|
if item.quantity == 0:
|
||||||
|
@ -366,7 +366,7 @@ class UserEventInfo:
|
|||||||
conditions = []
|
conditions = []
|
||||||
for x in self.conditionInfo:
|
for x in self.conditionInfo:
|
||||||
conditions.append(x.make())
|
conditions.append(x.make())
|
||||||
|
|
||||||
return [self.eventId, conditions]
|
return [self.eventId, conditions]
|
||||||
|
|
||||||
|
|
||||||
@ -374,7 +374,7 @@ class UserEventConditionInfo:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.achievementCondition = 0
|
self.achievementCondition = 0
|
||||||
self.progress = 0
|
self.progress = 0
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self) -> List:
|
||||||
return [self.achievementCondition, self.progress]
|
return [self.achievementCondition, self.progress]
|
||||||
|
|
||||||
@ -835,11 +835,13 @@ class LastSongDetail:
|
|||||||
|
|
||||||
|
|
||||||
class FriendScoreDetail:
|
class FriendScoreDetail:
|
||||||
def __init__(self, song_id: int = 0, difficulty: int = 1, best_score: int = 0) -> None:
|
def __init__(
|
||||||
|
self, song_id: int = 0, difficulty: int = 1, best_score: int = 0
|
||||||
|
) -> None:
|
||||||
self.songId = song_id
|
self.songId = song_id
|
||||||
self.difficulty = difficulty
|
self.difficulty = difficulty
|
||||||
self.bestScore = best_score
|
self.bestScore = best_score
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self) -> List:
|
||||||
return [self.songId, self.difficulty, self.bestScore]
|
return [self.songId, self.difficulty, self.bestScore]
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class UserInfoUpdateRequest(BaseRequest):
|
|||||||
self.profileId = int(self.params[0])
|
self.profileId = int(self.params[0])
|
||||||
self.optsUpdated: List[UserOption] = []
|
self.optsUpdated: List[UserOption] = []
|
||||||
self.unknown2: List = self.params[2]
|
self.unknown2: List = self.params[2]
|
||||||
self.datesUpdated: List[DateUpdate] = []
|
self.datesUpdated: List[DateUpdate] = []
|
||||||
self.favoritesRemoved: List[int] = self.params[4]
|
self.favoritesRemoved: List[int] = self.params[4]
|
||||||
self.favoritesAdded: List[int] = self.params[5]
|
self.favoritesAdded: List[int] = self.params[5]
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ class UserStatusGetDetailResponseV2(UserStatusGetDetailResponseV1):
|
|||||||
while len(tut_flg) < 5:
|
while len(tut_flg) < 5:
|
||||||
flag_id = len(tut_flg) + 1
|
flag_id = len(tut_flg) + 1
|
||||||
tut_flg.append([flag_id, 0])
|
tut_flg.append([flag_id, 0])
|
||||||
|
|
||||||
for x in self.eventInfo:
|
for x in self.eventInfo:
|
||||||
evts.append(x.make())
|
evts.append(x.make())
|
||||||
|
|
||||||
@ -267,7 +267,9 @@ class UserStatusLoginResponseV3(UserStatusLoginResponseV2):
|
|||||||
self, is_first_login_daily: bool = False, last_login_date: int = 0
|
self, is_first_login_daily: bool = False, last_login_date: int = 0
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(is_first_login_daily, last_login_date)
|
super().__init__(is_first_login_daily, last_login_date)
|
||||||
self.unk: List = [] # Ticket info, item info, message, title, voice name (not sure how they fit...)
|
self.unk: List = (
|
||||||
|
[]
|
||||||
|
) # Ticket info, item info, message, title, voice name (not sure how they fit...)
|
||||||
|
|
||||||
def make(self) -> Dict:
|
def make(self) -> Dict:
|
||||||
super().make()
|
super().make()
|
||||||
|
@ -73,7 +73,7 @@ class WaccaLily(WaccaS):
|
|||||||
self.logger.info(f"No user exists for aime id {req.aimeId}")
|
self.logger.info(f"No user exists for aime id {req.aimeId}")
|
||||||
resp.profileStatus = ProfileStatus.ProfileRegister
|
resp.profileStatus = ProfileStatus.ProfileRegister
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
opts = self.data.profile.get_options(req.aimeId)
|
opts = self.data.profile.get_options(req.aimeId)
|
||||||
|
|
||||||
self.logger.info(f"User preview for {req.aimeId} from {req.chipId}")
|
self.logger.info(f"User preview for {req.aimeId} from {req.chipId}")
|
||||||
@ -139,7 +139,7 @@ class WaccaLily(WaccaS):
|
|||||||
|
|
||||||
if self.game_config.mods.infinite_wp:
|
if self.game_config.mods.infinite_wp:
|
||||||
resp.userStatus.wp = 999999
|
resp.userStatus.wp = 999999
|
||||||
|
|
||||||
for opt in opts:
|
for opt in opts:
|
||||||
resp.options.append(UserOption(opt["opt_id"], opt["value"]))
|
resp.options.append(UserOption(opt["opt_id"], opt["value"]))
|
||||||
|
|
||||||
@ -165,17 +165,23 @@ class WaccaLily(WaccaS):
|
|||||||
self.logger.info(f"User {req.userId} login on {req.chipId}")
|
self.logger.info(f"User {req.userId} login on {req.chipId}")
|
||||||
last_login_time = int(profile["last_login_date"].timestamp())
|
last_login_time = int(profile["last_login_date"].timestamp())
|
||||||
resp.lastLoginDate = last_login_time
|
resp.lastLoginDate = last_login_time
|
||||||
midnight_today_ts = int(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).timestamp())
|
midnight_today_ts = int(
|
||||||
|
datetime.now()
|
||||||
|
.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
.timestamp()
|
||||||
|
)
|
||||||
|
|
||||||
# If somebodies login timestamp < midnight of current day, then they are logging in for the first time today
|
# If somebodies login timestamp < midnight of current day, then they are logging in for the first time today
|
||||||
if last_login_time < midnight_today_ts:
|
if last_login_time < midnight_today_ts:
|
||||||
resp.firstLoginDaily = True
|
resp.firstLoginDaily = True
|
||||||
|
|
||||||
# If the difference between midnight today and their last login is greater then 1 day (86400 seconds) they've broken their streak
|
# If the difference between midnight today and their last login is greater then 1 day (86400 seconds) they've broken their streak
|
||||||
if midnight_today_ts - last_login_time > 86400:
|
if midnight_today_ts - last_login_time > 86400:
|
||||||
is_consec_day = False
|
is_consec_day = False
|
||||||
|
|
||||||
self.data.profile.session_login(req.userId, resp.firstLoginDaily, is_consec_day)
|
self.data.profile.session_login(
|
||||||
|
req.userId, resp.firstLoginDaily, is_consec_day
|
||||||
|
)
|
||||||
resp.vipInfo.pageYear = datetime.now().year
|
resp.vipInfo.pageYear = datetime.now().year
|
||||||
resp.vipInfo.pageMonth = datetime.now().month
|
resp.vipInfo.pageMonth = datetime.now().month
|
||||||
resp.vipInfo.pageDay = datetime.now().day
|
resp.vipInfo.pageDay = datetime.now().day
|
||||||
|
@ -141,7 +141,7 @@ class WaccaReverse(WaccaLilyR):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# For some fucking reason if this isn't here time play is disabled
|
# For some fucking reason if this isn't here time play is disabled
|
||||||
resp.seasonalPlayModeCounts.append(PlayModeCounts(0, 1, 1))
|
resp.seasonalPlayModeCounts.append(PlayModeCounts(0, 1, 1))
|
||||||
|
|
||||||
for opt in profile_options:
|
for opt in profile_options:
|
||||||
resp.options.append(UserOption(opt["opt_id"], opt["value"]))
|
resp.options.append(UserOption(opt["opt_id"], opt["value"]))
|
||||||
|
Loading…
Reference in New Issue
Block a user