Merge branch 'develop' into fork_develop
This commit is contained in:
commit
b30e9570e7
@ -95,14 +95,19 @@ class AllnetServlet:
|
|||||||
def handle_poweron(self, request: Request, _: Dict):
|
def handle_poweron(self, request: Request, _: Dict):
|
||||||
request_ip = request.getClientAddress().host
|
request_ip = request.getClientAddress().host
|
||||||
try:
|
try:
|
||||||
req = AllnetPowerOnRequest(self.allnet_req_to_dict(request.content.getvalue())[0])
|
req_dict = self.allnet_req_to_dict(request.content.getvalue())
|
||||||
|
if req_dict is None:
|
||||||
|
raise AllnetRequestException()
|
||||||
|
|
||||||
|
req = AllnetPowerOnRequest(req_dict[0])
|
||||||
# Validate the request. Currently we only validate the fields we plan on using
|
# Validate the request. Currently we only validate the fields we plan on using
|
||||||
|
|
||||||
if not req.game_id or not req.ver or not req.token or not req.serial or not req.ip:
|
if not req.game_id or not req.ver or not req.token or not req.serial or not req.ip:
|
||||||
raise AllnetRequestException(f"Bad auth request params from {request_ip} - {vars(req)}")
|
raise AllnetRequestException(f"Bad auth request params from {request_ip} - {vars(req)}")
|
||||||
|
|
||||||
except AllnetRequestException as e:
|
except AllnetRequestException as e:
|
||||||
self.logger.error(e)
|
if e.message != "":
|
||||||
|
self.logger.error(e)
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
if req.format_ver == 3:
|
if req.format_ver == 3:
|
||||||
@ -155,14 +160,19 @@ class AllnetServlet:
|
|||||||
def handle_dlorder(self, request: Request, _: Dict):
|
def handle_dlorder(self, request: Request, _: Dict):
|
||||||
request_ip = request.getClientAddress().host
|
request_ip = request.getClientAddress().host
|
||||||
try:
|
try:
|
||||||
req = AllnetDownloadOrderRequest(self.allnet_req_to_dict(request.content.getvalue())[0])
|
req_dict = self.allnet_req_to_dict(request.content.getvalue())
|
||||||
|
if req_dict is None:
|
||||||
|
raise AllnetRequestException()
|
||||||
|
|
||||||
|
req = AllnetDownloadOrderRequest(req_dict[0])
|
||||||
# Validate the request. Currently we only validate the fields we plan on using
|
# Validate the request. Currently we only validate the fields we plan on using
|
||||||
|
|
||||||
if not req.game_id or not req.ver or not req.serial:
|
if not req.game_id or not req.ver or not req.serial:
|
||||||
raise AllnetRequestException(f"Bad download request params from {request_ip} - {vars(req)}")
|
raise AllnetRequestException(f"Bad download request params from {request_ip} - {vars(req)}")
|
||||||
|
|
||||||
except AllnetRequestException as e:
|
except AllnetRequestException as e:
|
||||||
self.logger.error(e)
|
if e.message != "":
|
||||||
|
self.logger.error(e)
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
resp = AllnetDownloadOrderResponse()
|
resp = AllnetDownloadOrderResponse()
|
||||||
@ -234,6 +244,10 @@ class AllnetServlet:
|
|||||||
self.logger.debug(f"response {vars(resp)}")
|
self.logger.debug(f"response {vars(resp)}")
|
||||||
return resp_str.encode("utf-8")
|
return resp_str.encode("utf-8")
|
||||||
|
|
||||||
|
def handle_naomitest(self, request: Request, _: Dict) -> bytes:
|
||||||
|
self.logger.info(f"Ping from {request.getClientAddress().host}")
|
||||||
|
return b"naomi ok"
|
||||||
|
|
||||||
def kvp_to_dict(self, kvp: List[str]) -> List[Dict[str, Any]]:
|
def kvp_to_dict(self, kvp: List[str]) -> List[Dict[str, Any]]:
|
||||||
ret: List[Dict[str, Any]] = []
|
ret: List[Dict[str, Any]] = []
|
||||||
for x in kvp:
|
for x in kvp:
|
||||||
@ -261,7 +275,7 @@ class AllnetServlet:
|
|||||||
return self.kvp_to_dict(sections)
|
return self.kvp_to_dict(sections)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(e)
|
self.logger.error(f"billing_req_to_dict: {e} while parsing {data}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def allnet_req_to_dict(self, data: str) -> Optional[List[Dict[str, Any]]]:
|
def allnet_req_to_dict(self, data: str) -> Optional[List[Dict[str, Any]]]:
|
||||||
@ -276,7 +290,7 @@ class AllnetServlet:
|
|||||||
return self.kvp_to_dict(sections)
|
return self.kvp_to_dict(sections)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(e)
|
self.logger.error(f"allnet_req_to_dict: {e} while parsing {data}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def dict_to_http_form_string(self, data:List[Dict[str, Any]], crlf: bool = False, trailing_newline: bool = True) -> Optional[str]:
|
def dict_to_http_form_string(self, data:List[Dict[str, Any]], crlf: bool = False, trailing_newline: bool = True) -> Optional[str]:
|
||||||
@ -303,7 +317,7 @@ class AllnetServlet:
|
|||||||
return urlencode
|
return urlencode
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(e)
|
self.logger.error(f"dict_to_http_form_string: {e} while parsing {data}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
class AllnetPowerOnRequest():
|
class AllnetPowerOnRequest():
|
||||||
@ -403,6 +417,6 @@ class BillingResponse():
|
|||||||
# YYYY -> 4 digit year, MM -> 2 digit month, C -> Playcount during that period
|
# YYYY -> 4 digit year, MM -> 2 digit month, C -> Playcount during that period
|
||||||
|
|
||||||
class AllnetRequestException(Exception):
|
class AllnetRequestException(Exception):
|
||||||
def __init__(self, message="Allnet Request Error") -> None:
|
def __init__(self, message="") -> None:
|
||||||
self.message = message
|
self.message = message
|
||||||
super().__init__(self.message)
|
super().__init__(self.message)
|
||||||
|
@ -194,6 +194,7 @@ class CoreConfig(dict):
|
|||||||
self.allnet = AllnetConfig(self)
|
self.allnet = AllnetConfig(self)
|
||||||
self.billing = BillingConfig(self)
|
self.billing = BillingConfig(self)
|
||||||
self.aimedb = AimedbConfig(self)
|
self.aimedb = AimedbConfig(self)
|
||||||
|
self.mucha = MuchaConfig(self)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def str_to_loglevel(cls, level_str: str):
|
def str_to_loglevel(cls, level_str: str):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import logging, coloredlogs
|
import logging, coloredlogs
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, List
|
||||||
from twisted.web import resource
|
from twisted.web import resource
|
||||||
from twisted.web.util import redirectTo
|
from twisted.web.util import redirectTo
|
||||||
from twisted.web.http import Request
|
from twisted.web.http import Request
|
||||||
@ -12,7 +12,6 @@ from core.data import Data
|
|||||||
from core.utils import Utils
|
from core.utils import Utils
|
||||||
|
|
||||||
class FrontendServlet(resource.Resource):
|
class FrontendServlet(resource.Resource):
|
||||||
children: Dict[str, Any] = {}
|
|
||||||
def getChild(self, name: bytes, request: Request):
|
def getChild(self, name: bytes, request: Request):
|
||||||
self.logger.debug(f"{request.getClientIP()} -> {name.decode()}")
|
self.logger.debug(f"{request.getClientIP()} -> {name.decode()}")
|
||||||
if name == b'':
|
if name == b'':
|
||||||
@ -24,7 +23,9 @@ class FrontendServlet(resource.Resource):
|
|||||||
log_fmt_str = "[%(asctime)s] Frontend | %(levelname)s | %(message)s"
|
log_fmt_str = "[%(asctime)s] Frontend | %(levelname)s | %(message)s"
|
||||||
log_fmt = logging.Formatter(log_fmt_str)
|
log_fmt = logging.Formatter(log_fmt_str)
|
||||||
self.logger = logging.getLogger("frontend")
|
self.logger = logging.getLogger("frontend")
|
||||||
self.environment = jinja2.Environment(loader=jinja2.FileSystemLoader("core/frontend"))
|
self.environment = jinja2.Environment(loader=jinja2.FileSystemLoader("."))
|
||||||
|
self.game_list: List[Dict[str, str]] = []
|
||||||
|
self.children: Dict[str, Any] = {}
|
||||||
|
|
||||||
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(self.config.server.log_dir, "frontend"), when="d", backupCount=10)
|
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(self.config.server.log_dir, "frontend"), when="d", backupCount=10)
|
||||||
fileHandler.setFormatter(log_fmt)
|
fileHandler.setFormatter(log_fmt)
|
||||||
@ -43,10 +44,13 @@ class FrontendServlet(resource.Resource):
|
|||||||
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:
|
||||||
fe_game.putChild(game_dir.encode(), 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})
|
||||||
|
fe_game.putChild(game_dir.encode(), game_fe)
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
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))
|
||||||
self.putChild(b"user", FE_User(cfg, self.environment))
|
self.putChild(b"user", FE_User(cfg, self.environment))
|
||||||
self.putChild(b"game", fe_game)
|
self.putChild(b"game", fe_game)
|
||||||
@ -55,8 +59,8 @@ class FrontendServlet(resource.Resource):
|
|||||||
|
|
||||||
def render_GET(self, request):
|
def render_GET(self, request):
|
||||||
self.logger.debug(f"{request.getClientIP()} -> {request.uri.decode()}")
|
self.logger.debug(f"{request.getClientIP()} -> {request.uri.decode()}")
|
||||||
template = self.environment.get_template("index.jinja")
|
template = self.environment.get_template("core/frontend/index.jinja")
|
||||||
return template.render(server_name=self.config.server.name, title=self.config.server.name).encode("utf-16")
|
return template.render(server_name=self.config.server.name, title=self.config.server.name, game_list=self.game_list).encode("utf-16")
|
||||||
|
|
||||||
class FE_Base(resource.Resource):
|
class FE_Base(resource.Resource):
|
||||||
"""
|
"""
|
||||||
@ -65,11 +69,12 @@ class FE_Base(resource.Resource):
|
|||||||
It is expected that game implementations of this class overwrite many of these
|
It is expected that game implementations of this class overwrite many of these
|
||||||
"""
|
"""
|
||||||
isLeaf = True
|
isLeaf = True
|
||||||
def __init__(self, cfg: CoreConfig, environment: jinja2.Environment, cfg_dir: str = None) -> None:
|
def __init__(self, cfg: CoreConfig, environment: jinja2.Environment) -> None:
|
||||||
self.core_config = cfg
|
self.core_config = cfg
|
||||||
self.data = Data(cfg)
|
self.data = Data(cfg)
|
||||||
self.logger = logging.getLogger('frontend')
|
self.logger = logging.getLogger('frontend')
|
||||||
self.environment = environment
|
self.environment = environment
|
||||||
|
self.nav_name = "nav_name"
|
||||||
|
|
||||||
class FE_Gate(FE_Base):
|
class FE_Gate(FE_Base):
|
||||||
def render_GET(self, request: Request):
|
def render_GET(self, request: Request):
|
||||||
@ -86,7 +91,7 @@ class FE_Gate(FE_Base):
|
|||||||
|
|
||||||
else: err = 0
|
else: err = 0
|
||||||
|
|
||||||
template = self.environment.get_template("gate/gate.jinja")
|
template = self.environment.get_template("core/frontend/gate/gate.jinja")
|
||||||
return template.render(title=f"{self.core_config.server.name} | Login Gate", error=err).encode("utf-16")
|
return template.render(title=f"{self.core_config.server.name} | Login Gate", error=err).encode("utf-16")
|
||||||
|
|
||||||
def render_POST(self, request: Request):
|
def render_POST(self, request: Request):
|
||||||
@ -153,12 +158,12 @@ class FE_Gate(FE_Base):
|
|||||||
|
|
||||||
ac = request.args[b'ac'][0].decode()
|
ac = request.args[b'ac'][0].decode()
|
||||||
|
|
||||||
template = self.environment.get_template("gate/create.jinja")
|
template = self.environment.get_template("core/frontend/gate/create.jinja")
|
||||||
return template.render(title=f"{self.core_config.server.name} | Create User", code=ac).encode("utf-16")
|
return template.render(title=f"{self.core_config.server.name} | Create User", code=ac).encode("utf-16")
|
||||||
|
|
||||||
class FE_User(FE_Base):
|
class FE_User(FE_Base):
|
||||||
def render_GET(self, request: Request):
|
def render_GET(self, request: Request):
|
||||||
template = self.environment.get_template("user/index.jinja")
|
template = self.environment.get_template("core/frontend/user/index.jinja")
|
||||||
return template.render().encode("utf-16")
|
return template.render().encode("utf-16")
|
||||||
if b'session' not in request.cookies:
|
if b'session' not in request.cookies:
|
||||||
return redirectTo(b"/gate", request)
|
return redirectTo(b"/gate", request)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "index.jinja" %}
|
{% extends "core/frontend/index.jinja" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Create User</h1>
|
<h1>Create User</h1>
|
||||||
<form id="create" style="max-width: 240px; min-width: 10%;" action="/gate/gate.create" method="post">
|
<form id="create" style="max-width: 240px; min-width: 10%;" action="/gate/gate.create" method="post">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% extends "index.jinja" %}
|
{% extends "core/frontend/index.jinja" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Gate</h1>
|
<h1>Gate</h1>
|
||||||
{% include "widgets/err_banner.jinja" %}
|
{% include "core/frontend/widgets/err_banner.jinja" %}
|
||||||
<form id="login" style="max-width: 240px; min-width: 10%;" action="/gate/gate.login" method="post">
|
<form id="login" style="max-width: 240px; min-width: 10%;" action="/gate/gate.login" method="post">
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="access_code">Card Access Code</label><br>
|
<label for="access_code">Card Access Code</label><br>
|
||||||
|
@ -80,7 +80,7 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% include "widgets/topbar.jinja" %}
|
{% include "core/frontend/widgets/topbar.jinja" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{ server_name }}</h1>
|
<h1>{{ server_name }}</h1>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "index.jinja" %}
|
{% extends "core/frontend/index.jinja" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>testing</h1>
|
<h1>testing</h1>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
@ -1,6 +1,13 @@
|
|||||||
<div style="background: #333; color: #f9f9f9; width: 10%; height: 50px; line-height: 50px; text-align: center; float: left;">
|
<div style="background: #333; color: #f9f9f9; width: 10%; height: 50px; line-height: 50px; text-align: center; float: left;">
|
||||||
Navigation
|
Navigation
|
||||||
</div>
|
</div>
|
||||||
<div style="background: #333; color: #f9f9f9; width: 90%; height: 50px; line-height: 50px; text-align: center; float: right;">
|
<div style="background: #333; color: #f9f9f9; width: 80%; height: 50px; line-height: 50px; padding-left: 10px; float: left;">
|
||||||
|
<a href=/><button class="btn btn-primary">Home</button></a>
|
||||||
|
{% for game in game_list %}
|
||||||
|
<a href=game/{{ game.url }}><button class="btn btn-success">{{ game.name }}</button></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="background: #333; color: #f9f9f9; width: 10%; height: 50px; line-height: 50px; text-align: center; float: left;">
|
||||||
<a href="/gate"><button class="btn btn-primary">Gate</button></a>
|
<a href="/gate"><button class="btn btn-primary">Gate</button></a>
|
||||||
</div>
|
</div>
|
@ -35,9 +35,14 @@ class MuchaServlet:
|
|||||||
return b""
|
return b""
|
||||||
|
|
||||||
req = MuchaAuthRequest(req_dict)
|
req = MuchaAuthRequest(req_dict)
|
||||||
self.logger.info(f"Mucha request {vars(req)}")
|
self.logger.debug(f"Mucha request {vars(req)}")
|
||||||
resp = MuchaAuthResponse(mucha_url=f"{self.config.mucha.hostname}:{self.config.mucha.port}")
|
|
||||||
self.logger.info(f"Mucha response {vars(resp)}")
|
if self.config.server.is_develop:
|
||||||
|
resp = MuchaAuthResponse(mucha_url=f"{self.config.mucha.hostname}:{self.config.mucha.port}")
|
||||||
|
else:
|
||||||
|
resp = MuchaAuthResponse(mucha_url=f"{self.config.mucha.hostname}")
|
||||||
|
|
||||||
|
self.logger.debug(f"Mucha response {vars(resp)}")
|
||||||
|
|
||||||
return self.mucha_postprocess(vars(resp))
|
return self.mucha_postprocess(vars(resp))
|
||||||
|
|
||||||
@ -48,9 +53,14 @@ class MuchaServlet:
|
|||||||
return b""
|
return b""
|
||||||
|
|
||||||
req = MuchaUpdateRequest(req_dict)
|
req = MuchaUpdateRequest(req_dict)
|
||||||
self.logger.info(f"Mucha request {vars(req)}")
|
self.logger.debug(f"Mucha request {vars(req)}")
|
||||||
resp = MuchaUpdateResponse(mucha_url=f"{self.config.mucha.hostname}:{self.config.mucha.port}")
|
|
||||||
self.logger.info(f"Mucha response {vars(resp)}")
|
if self.config.server.is_develop:
|
||||||
|
resp = MuchaUpdateResponse(mucha_url=f"{self.config.mucha.hostname}:{self.config.mucha.port}")
|
||||||
|
else:
|
||||||
|
resp = MuchaUpdateResponse(mucha_url=f"{self.config.mucha.hostname}")
|
||||||
|
|
||||||
|
self.logger.debug(f"Mucha response {vars(resp)}")
|
||||||
|
|
||||||
return self.mucha_postprocess(vars(resp))
|
return self.mucha_postprocess(vars(resp))
|
||||||
|
|
||||||
|
@ -71,4 +71,4 @@ class TitleServlet():
|
|||||||
self.logger.warn(f"{code} does not dispatch POST")
|
self.logger.warn(f"{code} does not dispatch POST")
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
return index.render_POST(request, endpoints["version"], endpoints["endpoint"])
|
return index.render_POST(request, int(endpoints["version"]), endpoints["endpoint"])
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from typing import Dict, List, Any, Optional
|
from typing import Dict, Any
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
import zlib, base64
|
import logging
|
||||||
import importlib
|
import importlib
|
||||||
from os import walk
|
from os import walk
|
||||||
|
|
||||||
@ -17,6 +17,6 @@ class Utils:
|
|||||||
ret[dir] = mod
|
ret[dir] = mod
|
||||||
|
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print(f"{dir} - {e}")
|
logging.getLogger("core").error(f"get_all_titles: {dir} - {e}")
|
||||||
raise
|
raise
|
||||||
return ret
|
return ret
|
||||||
|
@ -23,22 +23,22 @@ if __name__=='__main__':
|
|||||||
|
|
||||||
elif args.action == "upgrade" or args.action == "rollback":
|
elif args.action == "upgrade" or args.action == "rollback":
|
||||||
if args.version is None:
|
if args.version is None:
|
||||||
print("Must set game and version to migrate to")
|
data.logger.error("Must set game and version to migrate to")
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
if args.game is None:
|
if args.game is None:
|
||||||
print("No game set, upgrading core schema")
|
data.logger.info("No game set, upgrading core schema")
|
||||||
data.migrate_database("CORE", int(args.version))
|
data.migrate_database("CORE", int(args.version))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
data.migrate_database(args.game, int(args.version), args.action)
|
data.migrate_database(args.game, int(args.version), args.action)
|
||||||
|
|
||||||
elif args.action == "migrate":
|
elif args.action == "migrate":
|
||||||
print("Migrating from old schema to new schema")
|
data.logger.info("Migrating from old schema to new schema")
|
||||||
data.restore_from_old_schema()
|
data.restore_from_old_schema()
|
||||||
|
|
||||||
elif args.action == "dump":
|
elif args.action == "dump":
|
||||||
print("Dumping old schema to migrate to new schema")
|
data.logger.info("Dumping old schema to migrate to new schema")
|
||||||
data.dump_db()
|
data.dump_db()
|
||||||
|
|
||||||
elif args.action == "generate":
|
elif args.action == "generate":
|
||||||
|
129
docs/INSTALL_UBUNTU.md
Normal file
129
docs/INSTALL_UBUNTU.md
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
# ARTEMiS - Ubuntu 20.04 LTS Guide
|
||||||
|
This step-by-step guide assumes that you are using a fresh install of Ubuntu 20.04 LTS, some of the steps can be skipped if you already have an installation with MySQL 5.7 or even some of the modules already present on your environment
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
## Install memcached module
|
||||||
|
1. sudo apt-get install memcached
|
||||||
|
2. Under the file /etc/memcached.conf, please make sure the following parameters are set:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Start with a cap of 64 megs of memory. It's reasonable, and the daemon default
|
||||||
|
# Note that the daemon will grow to this size, but does not start out holding this much
|
||||||
|
# memory
|
||||||
|
|
||||||
|
-I 128m
|
||||||
|
-m 1024
|
||||||
|
```
|
||||||
|
|
||||||
|
** This is mandatory to avoid memcached overload caused by Crossbeats or by massive profiles
|
||||||
|
|
||||||
|
3. Restart memcached using: sudo systemctl restart memcached
|
||||||
|
|
||||||
|
## Install MySQL 5.7
|
||||||
|
```
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install wget -y
|
||||||
|
wget https://dev.mysql.com/get/mysql-apt-config_0.8.12-1_all.deb
|
||||||
|
sudo dpkg -i mysql-apt-config_0.8.12-1_all.deb
|
||||||
|
```
|
||||||
|
1. During the first prompt, select Ubuntu Bionic
|
||||||
|
2. Select the default option
|
||||||
|
3. Select MySQL 5.7
|
||||||
|
4. Select the last option
|
||||||
|
```
|
||||||
|
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-cache policy mysql-server
|
||||||
|
sudo apt install -f mysql-client=5.7* mysql-community-server=5.7* mysql-server=5.7*
|
||||||
|
```
|
||||||
|
|
||||||
|
## Default Configuration for MySQL Server
|
||||||
|
1. sudo mysql_secure_installation
|
||||||
|
> Make sure to follow the steps that will be prompted such as changing the mysql root password and such
|
||||||
|
|
||||||
|
2. Test your MySQL Server login by doing the following command :
|
||||||
|
> mysql -u root -p
|
||||||
|
|
||||||
|
## Create the default ARTEMiS database and user
|
||||||
|
1. mysql -u root -p
|
||||||
|
2. Please change the password indicated in the next line for a custom secure one and continue with the next commands
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATE USER 'aime'@'localhost' IDENTIFIED BY 'MyStrongPass.';
|
||||||
|
CREATE DATABASE aime;
|
||||||
|
GRANT Alter,Create,Delete,Drop,Insert,References,Select,Update ON aime.* TO 'aime'@'localhost';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
exit;
|
||||||
|
```
|
||||||
|
|
||||||
|
3. sudo systemctl restart mysql
|
||||||
|
|
||||||
|
## Install Python modules
|
||||||
|
```
|
||||||
|
sudo apt-get install python3-dev default-libmysqlclient-dev build-essential mysql-client libmysqlclient-dev libmemcached-dev
|
||||||
|
sudo apt install libpython3.8-dev
|
||||||
|
sudo apt-get install python3-software-properties
|
||||||
|
sudo apt install python3-pip
|
||||||
|
sudo pip3 install --upgrade pip testresources
|
||||||
|
sudo pip3 install --upgrade pip setuptools
|
||||||
|
sudo apt-get install python3-tk
|
||||||
|
```
|
||||||
|
7. Change your work path to the ARTEMiS root folder using 'cd' and install the requirements:
|
||||||
|
> sudo python3 -m pip install -r requirements.txt
|
||||||
|
|
||||||
|
## Copy/Rename the folder example_config to config
|
||||||
|
|
||||||
|
## Adjust /config/core.yaml
|
||||||
|
1. Make sure to change the server listen_address to be set to your local machine IP (ex.: 192.168.1.xxx)
|
||||||
|
2. Adjust the proper MySQL information you created earlier
|
||||||
|
3. Add the AimeDB key at the bottom of the file
|
||||||
|
|
||||||
|
## Create the database tables for ARTEMiS
|
||||||
|
1. sudo python3 dbutils.py create
|
||||||
|
|
||||||
|
2. If you get "No module named Crypto", run the following command:
|
||||||
|
```
|
||||||
|
sudo pip uninstall crypto
|
||||||
|
sudo pip uninstall pycrypto
|
||||||
|
sudo pip install pycrypto
|
||||||
|
```
|
||||||
|
|
||||||
|
## Firewall Adjustements
|
||||||
|
```
|
||||||
|
sudo ufw allow 80
|
||||||
|
sudo ufw allow 443
|
||||||
|
sudo ufw allow 8443
|
||||||
|
sudo ufw allow 22345
|
||||||
|
sudo ufw allow 8090
|
||||||
|
sudo ufw allow 8444
|
||||||
|
sudo ufw allow 9000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the ARTEMiS instance
|
||||||
|
1. sudo python3 index.py
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
## Game does not connect to ARTEMiS Allnet server
|
||||||
|
1. Double-check your core.yaml, the listen_address is most likely either not binded to the proper IP or the port is not opened
|
||||||
|
|
||||||
|
## Game does not connect to Title Server
|
||||||
|
1. Verify that your core.yaml is setup properly for both the server listen_address and title hostname
|
||||||
|
2. Boot your game and verify that an AllNet response does show and if it does, attempt to open the URI that is shown under a browser such as Edge, Chrome & Firefox.
|
||||||
|
3. If a page is shown, the server is working properly and if it doesn't, double check your port forwarding and also that you have entered the proper local IP under the Title hostname in core.yaml.
|
||||||
|
|
||||||
|
## Unhandled command under AimeDB
|
||||||
|
1. Double check your AimeDB key under core.yaml, it is incorrect.
|
||||||
|
|
||||||
|
## Memcache failed, error 3
|
||||||
|
1. Make sure memcached is properly installed and running. You can check the status of the service using the following command:
|
||||||
|
> sudo systemctl status memcached
|
||||||
|
2. If it is failing, double check the /etc/memcached.conf file, it may have duplicated arguments like the -I and -m
|
||||||
|
3. If it is still not working afterward, you can proceed with a workaround by manually editing the /core/data/cache.py file.
|
||||||
|
```
|
||||||
|
# Make memcache optional
|
||||||
|
try:
|
||||||
|
has_mc = False
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
has_mc = False
|
||||||
|
```
|
83
docs/INSTALL_WINDOWS.md
Normal file
83
docs/INSTALL_WINDOWS.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# ARTEMiS - Windows 10/11 Guide
|
||||||
|
This step-by-step guide assumes that you are using a fresh install of Windows 10/11 without MySQL installed, some of the steps can be skipped if you already have an installation with MySQL 8.0 or even some of the modules already present on your environment
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
## Install Python Python 3.9 (recommended) or 3.10
|
||||||
|
1. Download Python 3.9 : [Link](https://www.python.org/ftp/python/3.9.13/python-3.9.13-amd64.exe)
|
||||||
|
2. Install python-3.9.13-amd64.exe
|
||||||
|
1. Select Customize installation
|
||||||
|
2. Make sure that pip, tcl/tk, and the for all users are checked and hit Next
|
||||||
|
3. Make sure that you enable "Create shortcuts for installed applications" and "Add Python to environment variables" and hit Install
|
||||||
|
|
||||||
|
## Install MySQL 8.0
|
||||||
|
1. Download MySQL 8.0 Server : [Link](https://cdn.mysql.com//Downloads/MySQLInstaller/mysql-installer-web-community-8.0.31.0.msi)
|
||||||
|
2. Install mysql-installer-web-community-8.0.31.0.msi
|
||||||
|
1. Click on "Add ..." on the side
|
||||||
|
2. Click on the "+" next to MySQL Servers
|
||||||
|
3. Make sure MySQL Server 8.0.29 - X64 is under the products to be installed.
|
||||||
|
4. Hit Next and Next once installed
|
||||||
|
5. Select the configuration type "Development Computer"
|
||||||
|
6. Hit Next
|
||||||
|
7. Select "Use Legacy Authentication Method (Retain MySQL 5.x compatibility)" and hit Next
|
||||||
|
8. Enter a root password and then hit Next >
|
||||||
|
9. Leave everything under Windows Service as default and hit Next >
|
||||||
|
10. Click on Execute and for it to finish and hit Next> and then Finish
|
||||||
|
3. Open MySQL 8.0 Command Line Client and login as your root user
|
||||||
|
4. Type those commands to create your user and the database
|
||||||
|
```
|
||||||
|
CREATE USER 'aime'@'localhost' IDENTIFIED BY 'MyStrongPass.';
|
||||||
|
CREATE DATABASE aime;
|
||||||
|
GRANT Alter,Create,Delete,Drop,Insert,References,Select,Update ON aime.* TO 'aime'@'localhost';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
exit;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install Python modules
|
||||||
|
1. Change your work path to the artemis-master folder using 'cd' and install the requirements:
|
||||||
|
> pip install -r requirements.txt
|
||||||
|
|
||||||
|
## Copy/Rename the folder example_config to config
|
||||||
|
|
||||||
|
## Adjust /config/core.yaml
|
||||||
|
|
||||||
|
1. Make sure to change the server listen_address to be set to your local machine IP (ex.: 192.168.1.xxx)
|
||||||
|
- In case you want to run this only locally, set the following values:
|
||||||
|
```
|
||||||
|
server:
|
||||||
|
listen_address: 0.0.0.0
|
||||||
|
title:
|
||||||
|
hostname: localhost
|
||||||
|
```
|
||||||
|
2. Adjust the proper MySQL information you created earlier
|
||||||
|
3. Add the AimeDB key at the bottom of the file
|
||||||
|
4. If the webui is needed, change the flag from False to True
|
||||||
|
|
||||||
|
## Create the database tables for ARTEMiS
|
||||||
|
> python dbutils.py create
|
||||||
|
|
||||||
|
## Firewall Adjustements
|
||||||
|
Make sure the following ports are open both on your router and local Windows firewall in case you want to use this for public use (NOT recommended):
|
||||||
|
> Port 80 (TCP), 443 (TCP), 8443 (TCP), 22345 (TCP), 8090 (TCP) **webui, 8444 (TCP) **mucha, 9000 (TCP)
|
||||||
|
|
||||||
|
## Running the ARTEMiS instance
|
||||||
|
> python index.py
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
## Game does not connect to ARTEMiS Allnet server
|
||||||
|
1. Double-check your core.yaml, the listen_address is most likely either not binded to the proper IP or the port is not opened
|
||||||
|
|
||||||
|
## Game does not connect to Title Server
|
||||||
|
1. Verify that your core.yaml is setup properly for both the server listen_address and title hostname
|
||||||
|
2. Boot your game and verify that an AllNet response does show and if it does, attempt to open the URI that is shown under a browser such as Edge, Chrome & Firefox.
|
||||||
|
3. If a page is shown, the server is working properly and if it doesn't, double check your port forwarding and also that you have entered the proper local IP under the Title hostname in core.yaml.
|
||||||
|
|
||||||
|
## Unhandled command under AimeDB
|
||||||
|
1. Double check your AimeDB key under core.yaml, it is incorrect.
|
||||||
|
|
||||||
|
## AttributeError: module 'collections' has no attribute 'Hashable'
|
||||||
|
1. This means the pyYAML module is obsolete, simply rerun pip with the -U (force update) flag, as shown below.
|
||||||
|
- Change your work path to the artemis-master (or artemis-develop) folder using 'cd' and run the following commands:
|
||||||
|
```
|
||||||
|
pip install -r requirements.txt -U
|
||||||
|
```
|
49
index.py
49
index.py
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging, coloredlogs
|
||||||
|
from logging.handlers import TimedRotatingFileHandler
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
import yaml
|
import yaml
|
||||||
from os import path, mkdir, access, W_OK
|
from os import path, mkdir, access, W_OK
|
||||||
@ -17,11 +19,13 @@ class HttpDispatcher(resource.Resource):
|
|||||||
self.isLeaf = True
|
self.isLeaf = True
|
||||||
self.map_get = Mapper()
|
self.map_get = Mapper()
|
||||||
self.map_post = Mapper()
|
self.map_post = Mapper()
|
||||||
|
self.logger = logging.getLogger("core")
|
||||||
|
|
||||||
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)
|
self.mucha = MuchaServlet(cfg)
|
||||||
|
|
||||||
|
self.map_post.connect('allnet_ping', '/naomitest.html', controller="allnet", action='handle_naomitest', conditions=dict(method=['GET']))
|
||||||
self.map_post.connect('allnet_poweron', '/sys/servlet/PowerOn', controller="allnet", action='handle_poweron', conditions=dict(method=['POST']))
|
self.map_post.connect('allnet_poweron', '/sys/servlet/PowerOn', controller="allnet", action='handle_poweron', conditions=dict(method=['POST']))
|
||||||
self.map_post.connect('allnet_downloadorder', '/sys/servlet/DownloadOrder', controller="allnet", action='handle_dlorder', conditions=dict(method=['POST']))
|
self.map_post.connect('allnet_downloadorder', '/sys/servlet/DownloadOrder', controller="allnet", action='handle_dlorder', conditions=dict(method=['POST']))
|
||||||
self.map_post.connect('allnet_billing', '/request', controller="allnet", action='handle_billing_request', conditions=dict(method=['POST']))
|
self.map_post.connect('allnet_billing', '/request', controller="allnet", action='handle_billing_request', conditions=dict(method=['POST']))
|
||||||
@ -29,31 +33,39 @@ class HttpDispatcher(resource.Resource):
|
|||||||
self.map_post.connect('mucha_boardauth', '/mucha/boardauth.do', controller="mucha", action='handle_boardauth', conditions=dict(method=['POST']))
|
self.map_post.connect('mucha_boardauth', '/mucha/boardauth.do', controller="mucha", action='handle_boardauth', conditions=dict(method=['POST']))
|
||||||
self.map_post.connect('mucha_updatacheck', '/mucha/updatacheck.do', controller="mucha", action='handle_updatacheck', conditions=dict(method=['POST']))
|
self.map_post.connect('mucha_updatacheck', '/mucha/updatacheck.do', controller="mucha", action='handle_updatacheck', conditions=dict(method=['POST']))
|
||||||
|
|
||||||
self.map_get.connect("title_get", "/{game}/{version}/{endpoint:.*?}", controller="title", action="render_GET", requirements=dict(game=R"S..."))
|
self.map_get.connect("title_get", "/{game}/{version}/{endpoint:.*?}", controller="title", action="render_GET", conditions=dict(method=['GET']), requirements=dict(game=R"S..."))
|
||||||
self.map_post.connect("title_post", "/{game}/{version}/{endpoint:.*?}", controller="title", action="render_POST", requirements=dict(game=R"S..."))
|
self.map_post.connect("title_post", "/{game}/{version}/{endpoint:.*?}", controller="title", action="render_POST", conditions=dict(method=['POST']), requirements=dict(game=R"S..."))
|
||||||
|
|
||||||
def render_POST(self, request: Request) -> bytes:
|
def render_GET(self, request: Request) -> bytes:
|
||||||
test = self.map_get.match(request.uri.decode())
|
test = self.map_get.match(request.uri.decode())
|
||||||
if test is None:
|
if test is None:
|
||||||
return b""
|
self.logger.debug(f"Unknown GET endpoint {request.uri.decode()} from {request.getClientAddress().host} to port {request.getHost().port}")
|
||||||
|
request.setResponseCode(404)
|
||||||
|
return b"Endpoint not found."
|
||||||
|
|
||||||
return self.dispatch(test, request)
|
return self.dispatch(test, request)
|
||||||
|
|
||||||
def render_POST(self, request: Request) -> bytes:
|
def render_POST(self, request: Request) -> bytes:
|
||||||
test = self.map_post.match(request.uri.decode())
|
test = self.map_post.match(request.uri.decode())
|
||||||
if test is None:
|
if test is None:
|
||||||
return b""
|
self.logger.debug(f"Unknown POST endpoint {request.uri.decode()} from {request.getClientAddress().host} to port {request.getHost().port}")
|
||||||
|
request.setResponseCode(404)
|
||||||
|
return b"Endpoint not found."
|
||||||
|
|
||||||
return self.dispatch(test, request)
|
return self.dispatch(test, request)
|
||||||
|
|
||||||
def dispatch(self, matcher: Dict, request: Request) -> bytes:
|
def dispatch(self, matcher: Dict, request: Request) -> bytes:
|
||||||
controller = getattr(self, matcher["controller"], None)
|
controller = getattr(self, matcher["controller"], None)
|
||||||
if controller is None:
|
if controller is None:
|
||||||
return b""
|
self.logger.error(f"Controller {matcher['controller']} not found via endpoint {request.uri.decode()}")
|
||||||
|
request.setResponseCode(404)
|
||||||
|
return b"Endpoint not found."
|
||||||
|
|
||||||
handler = getattr(controller, matcher["action"], None)
|
handler = getattr(controller, matcher["action"], None)
|
||||||
if handler is None:
|
if handler is None:
|
||||||
return b""
|
self.logger.error(f"Action {matcher['action']} not found in controller {matcher['controller']} via endpoint {request.uri.decode()}")
|
||||||
|
request.setResponseCode(404)
|
||||||
|
return b"Endpoint not found."
|
||||||
|
|
||||||
url_vars = matcher
|
url_vars = matcher
|
||||||
url_vars.pop("controller")
|
url_vars.pop("controller")
|
||||||
@ -79,18 +91,35 @@ if __name__ == "__main__":
|
|||||||
cfg: CoreConfig = CoreConfig()
|
cfg: CoreConfig = CoreConfig()
|
||||||
cfg.update(yaml.safe_load(open(f"{args.config}/core.yaml")))
|
cfg.update(yaml.safe_load(open(f"{args.config}/core.yaml")))
|
||||||
|
|
||||||
|
logger = logging.getLogger("core")
|
||||||
|
log_fmt_str = "[%(asctime)s] Core | %(levelname)s | %(message)s"
|
||||||
|
log_fmt = logging.Formatter(log_fmt_str)
|
||||||
|
|
||||||
|
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(cfg.server.log_dir, "core"), when="d", backupCount=10)
|
||||||
|
fileHandler.setFormatter(log_fmt)
|
||||||
|
|
||||||
|
consoleHandler = logging.StreamHandler()
|
||||||
|
consoleHandler.setFormatter(log_fmt)
|
||||||
|
|
||||||
|
logger.addHandler(fileHandler)
|
||||||
|
logger.addHandler(consoleHandler)
|
||||||
|
|
||||||
|
log_lv = logging.DEBUG if cfg.server.is_develop else logging.INFO
|
||||||
|
logger.setLevel(log_lv)
|
||||||
|
coloredlogs.install(level=log_lv, logger=logger, fmt=log_fmt_str)
|
||||||
|
|
||||||
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(f"Log directory {cfg.server.log_dir} NOT writable, please check permissions")
|
logger.error(f"Log directory {cfg.server.log_dir} NOT writable, please check permissions")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if not cfg.aimedb.key:
|
if not cfg.aimedb.key:
|
||||||
print("!!AIMEDB KEY BLANK, SET KEY IN CORE.YAML!!")
|
logger.error("!!AIMEDB KEY BLANK, SET KEY IN CORE.YAML!!")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
print(f"ARTEMiS starting in {'develop' if cfg.server.is_develop else 'production'} mode")
|
logger.info(f"ARTEMiS starting in {'develop' if cfg.server.is_develop else 'production'} mode")
|
||||||
|
|
||||||
allnet_server_str = f"tcp:{cfg.allnet.port}:interface={cfg.server.listen_address}"
|
allnet_server_str = f"tcp:{cfg.allnet.port}:interface={cfg.server.listen_address}"
|
||||||
title_server_str = f"tcp:{cfg.title.port}:interface={cfg.server.listen_address}"
|
title_server_str = f"tcp:{cfg.title.port}:interface={cfg.server.listen_address}"
|
||||||
|
7
read.py
7
read.py
@ -85,7 +85,7 @@ if __name__ == "__main__":
|
|||||||
log_fmt = logging.Formatter(log_fmt_str)
|
log_fmt = logging.Formatter(log_fmt_str)
|
||||||
logger = logging.getLogger("reader")
|
logger = logging.getLogger("reader")
|
||||||
|
|
||||||
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(config.server.logs, "reader"), when="d", backupCount=10)
|
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(config.server.log_dir, "reader"), when="d", backupCount=10)
|
||||||
fileHandler.setFormatter(log_fmt)
|
fileHandler.setFormatter(log_fmt)
|
||||||
|
|
||||||
consoleHandler = logging.StreamHandler()
|
consoleHandler = logging.StreamHandler()
|
||||||
@ -94,8 +94,9 @@ if __name__ == "__main__":
|
|||||||
logger.addHandler(fileHandler)
|
logger.addHandler(fileHandler)
|
||||||
logger.addHandler(consoleHandler)
|
logger.addHandler(consoleHandler)
|
||||||
|
|
||||||
logger.setLevel(logging.INFO)
|
log_lv = logging.DEBUG if config.server.is_develop else logging.INFO
|
||||||
coloredlogs.install(level=logging.INFO, logger=logger, fmt=log_fmt_str)
|
logger.setLevel(log_lv)
|
||||||
|
coloredlogs.install(level=log_lv, logger=logger, fmt=log_fmt_str)
|
||||||
|
|
||||||
if args.series is None or args.version is None:
|
if args.series is None or args.version is None:
|
||||||
logger.error("Game or version not specified")
|
logger.error("Game or version not specified")
|
||||||
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Binary file not shown.
@ -161,6 +161,7 @@ course = Table(
|
|||||||
|
|
||||||
class Mai2ScoreData(BaseData):
|
class Mai2ScoreData(BaseData):
|
||||||
def put_best_score(self, user_id: int, score_data: Dict) -> Optional[int]:
|
def put_best_score(self, user_id: int, score_data: Dict) -> Optional[int]:
|
||||||
|
score_data["user"] = user_id
|
||||||
sql = insert(best_score).values(**score_data)
|
sql = insert(best_score).values(**score_data)
|
||||||
|
|
||||||
conflict = sql.on_duplicate_key_update(**score_data)
|
conflict = sql.on_duplicate_key_update(**score_data)
|
||||||
@ -197,6 +198,7 @@ class Mai2ScoreData(BaseData):
|
|||||||
return result.fetchone()
|
return result.fetchone()
|
||||||
|
|
||||||
def put_playlog(self, user_id: int, playlog_data: Dict) -> Optional[int]:
|
def put_playlog(self, user_id: int, playlog_data: Dict) -> Optional[int]:
|
||||||
|
playlog_data["user"] = user_id
|
||||||
sql = insert(playlog).values(**playlog_data)
|
sql = insert(playlog).values(**playlog_data)
|
||||||
|
|
||||||
conflict = sql.on_duplicate_key_update(**playlog_data)
|
conflict = sql.on_duplicate_key_update(**playlog_data)
|
||||||
@ -208,6 +210,7 @@ class Mai2ScoreData(BaseData):
|
|||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
def put_course(self, user_id: int, course_data: Dict) -> Optional[int]:
|
def put_course(self, user_id: int, course_data: Dict) -> Optional[int]:
|
||||||
|
course_data["user"] = user_id
|
||||||
sql = insert(course).values(**course_data)
|
sql = insert(course).values(**course_data)
|
||||||
|
|
||||||
conflict = sql.on_duplicate_key_update(**course_data)
|
conflict = sql.on_duplicate_key_update(**course_data)
|
||||||
|
@ -16,6 +16,10 @@ class PokkenServerConfig():
|
|||||||
def hostname(self) -> str:
|
def hostname(self) -> str:
|
||||||
return CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'hostname', default="localhost")
|
return CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'hostname', default="localhost")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ssl_enable(self) -> bool:
|
||||||
|
return CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'ssl_enable', default=False)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def port(self) -> int:
|
def port(self) -> int:
|
||||||
return CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'port', default=9000)
|
return CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'port', default=9000)
|
||||||
|
@ -42,7 +42,7 @@ class PokkenServlet(resource.Resource):
|
|||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
if self.game_cfg.server.enable:
|
if self.game_cfg.server.enable:
|
||||||
if self.core_cfg.server.is_develop:
|
if self.core_cfg.server.is_develop and self.game_cfg.server.ssl_enable:
|
||||||
endpoints.serverFromString(reactor, f"ssl:{self.game_cfg.server.port}"\
|
endpoints.serverFromString(reactor, f"ssl:{self.game_cfg.server.port}"\
|
||||||
f":interface={self.game_cfg.server.hostname}:privateKey={self.game_cfg.server.ssl_key}:"\
|
f":interface={self.game_cfg.server.hostname}:privateKey={self.game_cfg.server.ssl_key}:"\
|
||||||
f"certKey={self.game_cfg.server.ssl_cert}")\
|
f"certKey={self.game_cfg.server.ssl_cert}")\
|
||||||
|
@ -77,9 +77,13 @@ class WaccaBase():
|
|||||||
self.logger.info(f"{req.chipId} -> {housing_id}")
|
self.logger.info(f"{req.chipId} -> {housing_id}")
|
||||||
resp = HousingGetResponse(housing_id)
|
resp = HousingGetResponse(housing_id)
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
|
def handle_advertise_GetRanking_request(self, data: Dict) -> Dict:
|
||||||
|
req = AdvertiseGetRankingRequest(data)
|
||||||
|
return AdvertiseGetRankingResponse().make()
|
||||||
|
|
||||||
def handle_housing_start_request(self, data: Dict) -> Dict:
|
def handle_housing_start_request(self, data: Dict) -> Dict:
|
||||||
req = HousingStartRequest(data)
|
req = HousingStartRequestV1(data)
|
||||||
|
|
||||||
resp = HousingStartResponseV1(
|
resp = HousingStartResponseV1(
|
||||||
1,
|
1,
|
||||||
@ -103,7 +107,69 @@ class WaccaBase():
|
|||||||
self.logger.info(f"Log out user {req.userId} from {req.chipId}")
|
self.logger.info(f"Log out user {req.userId} from {req.chipId}")
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
def handle_user_status_login_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_get_request(self, data: Dict)-> Dict:
|
||||||
|
req = UserStatusGetRequest(data)
|
||||||
|
resp = UserStatusGetV1Response()
|
||||||
|
ver_split = req.appVersion.split(".")
|
||||||
|
|
||||||
|
profile = self.data.profile.get_profile(aime_id=req.aimeId)
|
||||||
|
if profile is None:
|
||||||
|
self.logger.info(f"No user exists for aime id {req.aimeId}")
|
||||||
|
resp.profileStatus = ProfileStatus.ProfileRegister
|
||||||
|
return resp.make()
|
||||||
|
|
||||||
|
|
||||||
|
self.logger.info(f"User preview for {req.aimeId} from {req.chipId}")
|
||||||
|
if profile["last_game_ver"] is None:
|
||||||
|
profile_ver_split = ver_split
|
||||||
|
resp.lastGameVersion = req.appVersion
|
||||||
|
else:
|
||||||
|
profile_ver_split = profile["last_game_ver"].split(".")
|
||||||
|
resp.lastGameVersion = profile["last_game_ver"]
|
||||||
|
|
||||||
|
resp.userStatus.userId = profile["id"]
|
||||||
|
resp.userStatus.username = profile["username"]
|
||||||
|
resp.userStatus.xp = profile["xp"]
|
||||||
|
resp.userStatus.danLevel = profile["dan_level"]
|
||||||
|
resp.userStatus.danType = profile["dan_type"]
|
||||||
|
resp.userStatus.wp = profile["wp"]
|
||||||
|
resp.userStatus.useCount = profile["login_count"]
|
||||||
|
|
||||||
|
set_title_id = self.data.profile.get_options(WaccaConstants.OPTIONS["set_title_id"], profile["user"])
|
||||||
|
if set_title_id is None:
|
||||||
|
set_title_id = self.OPTIONS_DEFAULTS["set_title_id"]
|
||||||
|
resp.setTitleId = set_title_id
|
||||||
|
|
||||||
|
set_icon_id = self.data.profile.get_options(WaccaConstants.OPTIONS["set_title_id"], profile["user"])
|
||||||
|
if set_icon_id is None:
|
||||||
|
set_icon_id = self.OPTIONS_DEFAULTS["set_icon_id"]
|
||||||
|
resp.setIconId = set_icon_id
|
||||||
|
|
||||||
|
|
||||||
|
if int(ver_split[0]) > int(profile_ver_split[0]):
|
||||||
|
resp.versionStatus = PlayVersionStatus.VersionUpgrade
|
||||||
|
|
||||||
|
elif int(ver_split[0]) < int(profile_ver_split[0]):
|
||||||
|
resp.versionStatus = PlayVersionStatus.VersionTooNew
|
||||||
|
|
||||||
|
else:
|
||||||
|
if int(ver_split[1]) > int(profile_ver_split[1]):
|
||||||
|
resp.versionStatus = PlayVersionStatus.VersionUpgrade
|
||||||
|
|
||||||
|
elif int(ver_split[1]) < int(profile_ver_split[1]):
|
||||||
|
resp.versionStatus = PlayVersionStatus.VersionTooNew
|
||||||
|
|
||||||
|
else:
|
||||||
|
if int(ver_split[2]) > int(profile_ver_split[2]):
|
||||||
|
resp.versionStatus = PlayVersionStatus.VersionUpgrade
|
||||||
|
|
||||||
|
|
||||||
|
elif int(ver_split[2]) < int(profile_ver_split[2]):
|
||||||
|
resp.versionStatus = PlayVersionStatus.VersionTooNew
|
||||||
|
|
||||||
|
return resp.make()
|
||||||
|
|
||||||
|
def handle_user_status_login_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusLoginRequest(data)
|
req = UserStatusLoginRequest(data)
|
||||||
resp = UserStatusLoginResponseV1()
|
resp = UserStatusLoginResponseV1()
|
||||||
is_new_day = False
|
is_new_day = False
|
||||||
@ -139,120 +205,8 @@ class WaccaBase():
|
|||||||
resp.firstLoginDaily = int(is_new_day)
|
resp.firstLoginDaily = int(is_new_day)
|
||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_status_get_request(self, data: Dict) -> List[Any]:
|
|
||||||
req = UserStatusGetRequest(data)
|
|
||||||
resp = UserStatusGetV1Response()
|
|
||||||
ver_split = req.appVersion.split(".")
|
|
||||||
|
|
||||||
profile = self.data.profile.get_profile(aime_id=req.aimeId)
|
|
||||||
if profile is None:
|
|
||||||
self.logger.info(f"No user exists for aime id {req.aimeId}")
|
|
||||||
return resp.make()
|
|
||||||
|
|
||||||
|
|
||||||
self.logger.info(f"User preview for {req.aimeId} from {req.chipId}")
|
|
||||||
if profile["last_game_ver"] is None:
|
|
||||||
profile_ver_split = ver_split
|
|
||||||
resp.lastGameVersion = req.appVersion
|
|
||||||
else:
|
|
||||||
profile_ver_split = profile["last_game_ver"].split(".")
|
|
||||||
resp.lastGameVersion = profile["last_game_ver"]
|
|
||||||
|
|
||||||
resp.userStatus.userId = profile["id"]
|
|
||||||
resp.userStatus.username = profile["username"]
|
|
||||||
resp.userStatus.xp = profile["xp"]
|
|
||||||
resp.userStatus.danLevel = profile["dan_level"]
|
|
||||||
resp.userStatus.danType = profile["dan_type"]
|
|
||||||
resp.userStatus.wp = profile["wp"]
|
|
||||||
resp.userStatus.useCount = profile["login_count"]
|
|
||||||
resp.userStatus.loginDays = profile["login_count_days"]
|
|
||||||
resp.userStatus.loginConsecutiveDays = profile["login_count_days_consec"]
|
|
||||||
|
|
||||||
set_title_id = self.data.profile.get_options(WaccaConstants.OPTIONS["set_title_id"], profile["user"])
|
|
||||||
if set_title_id is None:
|
|
||||||
set_title_id = self.OPTIONS_DEFAULTS["set_title_id"]
|
|
||||||
resp.setTitleId = set_title_id
|
|
||||||
|
|
||||||
set_icon_id = self.data.profile.get_options(WaccaConstants.OPTIONS["set_title_id"], profile["user"])
|
|
||||||
if set_icon_id is None:
|
|
||||||
set_icon_id = self.OPTIONS_DEFAULTS["set_icon_id"]
|
|
||||||
resp.setIconId = set_icon_id
|
|
||||||
|
|
||||||
if profile["last_login_date"].timestamp() < int((datetime.now().replace(hour=0,minute=0,second=0,microsecond=0) - timedelta(days=1)).timestamp()):
|
|
||||||
resp.userStatus.loginConsecutiveDays = 0
|
|
||||||
|
|
||||||
if int(ver_split[0]) > int(profile_ver_split[0]):
|
|
||||||
resp.versionStatus = PlayVersionStatus.VersionUpgrade
|
|
||||||
|
|
||||||
elif int(ver_split[0]) < int(profile_ver_split[0]):
|
|
||||||
resp.versionStatus = PlayVersionStatus.VersionTooNew
|
|
||||||
|
|
||||||
else:
|
|
||||||
if int(ver_split[1]) > int(profile_ver_split[1]):
|
|
||||||
resp.versionStatus = PlayVersionStatus.VersionUpgrade
|
|
||||||
|
|
||||||
elif int(ver_split[1]) < int(profile_ver_split[1]):
|
|
||||||
resp.versionStatus = PlayVersionStatus.VersionTooNew
|
|
||||||
|
|
||||||
else:
|
|
||||||
if int(ver_split[2]) > int(profile_ver_split[2]):
|
|
||||||
resp.versionStatus = PlayVersionStatus.VersionUpgrade
|
|
||||||
|
|
||||||
|
|
||||||
elif int(ver_split[2]) < int(profile_ver_split[2]):
|
|
||||||
resp.versionStatus = PlayVersionStatus.VersionTooNew
|
|
||||||
|
|
||||||
if profile["always_vip"]:
|
|
||||||
resp.userStatus.vipExpireTime = int((datetime.now() + timedelta(days=30)).timestamp())
|
|
||||||
|
|
||||||
elif profile["vip_expire_time"] is not None:
|
|
||||||
resp.userStatus.vipExpireTime = int(profile["vip_expire_time"].timestamp())
|
|
||||||
|
|
||||||
return resp.make()
|
|
||||||
|
|
||||||
def handle_user_status_login_request(self, data: Dict) -> List[Any]:
|
|
||||||
req = UserStatusLoginRequest(data)
|
|
||||||
resp = UserStatusLoginResponseV2()
|
|
||||||
is_new_day = False
|
|
||||||
is_consec_day = False
|
|
||||||
is_consec_day = True
|
|
||||||
|
|
||||||
if req.userId == 0:
|
|
||||||
self.logger.info(f"Guest login on {req.chipId}")
|
|
||||||
resp.lastLoginDate = 0
|
|
||||||
|
|
||||||
else:
|
|
||||||
profile = self.data.profile.get_profile(req.userId)
|
|
||||||
if profile is None:
|
|
||||||
self.logger.warn(f"Unknown user id {req.userId} attempted login from {req.chipId}")
|
|
||||||
return resp.make()
|
|
||||||
|
|
||||||
self.logger.info(f"User {req.userId} login on {req.chipId}")
|
|
||||||
last_login_time = int(profile["last_login_date"].timestamp())
|
|
||||||
resp.lastLoginDate = last_login_time
|
|
||||||
|
|
||||||
# If somebodies login timestamp < midnight of current day, then they are logging in for the first time today
|
|
||||||
if last_login_time < int(datetime.now().replace(hour=0,minute=0,second=0,microsecond=0).timestamp()):
|
|
||||||
is_new_day = True
|
|
||||||
is_consec_day = True
|
|
||||||
|
|
||||||
# If somebodies login timestamp > midnight of current day + 1 day, then they broke their daily login streak
|
|
||||||
elif last_login_time > int((datetime.now().replace(hour=0,minute=0,second=0,microsecond=0) + timedelta(days=1)).timestamp()):
|
|
||||||
is_consec_day = False
|
|
||||||
# else, they are simply logging in again on the same day, and we don't need to do anything for that
|
|
||||||
|
|
||||||
self.data.profile.session_login(req.userId, is_new_day, is_consec_day)
|
|
||||||
resp.vipInfo.pageYear = datetime.now().year
|
|
||||||
resp.vipInfo.pageMonth = datetime.now().month
|
|
||||||
resp.vipInfo.pageDay = datetime.now().day
|
|
||||||
resp.vipInfo.numItem = 1
|
|
||||||
|
|
||||||
resp.firstLoginDaily = int(is_new_day)
|
|
||||||
|
|
||||||
return resp.make()
|
|
||||||
|
|
||||||
def handle_user_status_create_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_create_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusCreateRequest(data)
|
req = UserStatusCreateRequest(data)
|
||||||
|
|
||||||
profileId = self.data.profile.create_profile(req.aimeId, req.username, self.version)
|
profileId = self.data.profile.create_profile(req.aimeId, req.username, self.version)
|
||||||
@ -284,7 +238,7 @@ class WaccaBase():
|
|||||||
|
|
||||||
return UserStatusCreateResponseV2(profileId, req.username).make()
|
return UserStatusCreateResponseV2(profileId, req.username).make()
|
||||||
|
|
||||||
def handle_user_status_getDetail_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_getDetail_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusGetDetailRequest(data)
|
req = UserStatusGetDetailRequest(data)
|
||||||
resp = UserStatusGetDetailResponseV1()
|
resp = UserStatusGetDetailResponseV1()
|
||||||
|
|
||||||
@ -301,16 +255,7 @@ class WaccaBase():
|
|||||||
profile_song_unlocks = self.data.item.get_song_unlocks(user_id)
|
profile_song_unlocks = self.data.item.get_song_unlocks(user_id)
|
||||||
profile_options = self.data.profile.get_options(user_id)
|
profile_options = self.data.profile.get_options(user_id)
|
||||||
profile_trophies = self.data.item.get_trophies(user_id)
|
profile_trophies = self.data.item.get_trophies(user_id)
|
||||||
profile_tickets = self.data.item.get_tickets(user_id)
|
profile_tickets = self.data.item.get_tickets(user_id)
|
||||||
|
|
||||||
if profile["vip_expire_time"] is None:
|
|
||||||
resp.userStatus.vipExpireTime = 0
|
|
||||||
|
|
||||||
else:
|
|
||||||
resp.userStatus.vipExpireTime = int(profile["vip_expire_time"].timestamp())
|
|
||||||
|
|
||||||
if profile["always_vip"] or self.game_config.mods.always_vip:
|
|
||||||
resp.userStatus.vipExpireTime = int((self.srvtime + timedelta(days=31)).timestamp())
|
|
||||||
|
|
||||||
resp.songUpdateTime = int(profile["last_login_date"].timestamp())
|
resp.songUpdateTime = int(profile["last_login_date"].timestamp())
|
||||||
resp.songPlayStatus = [profile["last_song_id"], 1]
|
resp.songPlayStatus = [profile["last_song_id"], 1]
|
||||||
@ -322,8 +267,6 @@ class WaccaBase():
|
|||||||
resp.userStatus.danType = profile["dan_type"]
|
resp.userStatus.danType = profile["dan_type"]
|
||||||
resp.userStatus.wp = profile["wp"]
|
resp.userStatus.wp = profile["wp"]
|
||||||
resp.userStatus.useCount = profile["login_count"]
|
resp.userStatus.useCount = profile["login_count"]
|
||||||
resp.userStatus.loginDays = profile["login_count_days"]
|
|
||||||
resp.userStatus.loginConsecutiveDays = profile["login_count_days_consec"]
|
|
||||||
|
|
||||||
if self.game_config.mods.infinite_wp:
|
if self.game_config.mods.infinite_wp:
|
||||||
resp.userStatus.wp = 999999
|
resp.userStatus.wp = 999999
|
||||||
@ -346,13 +289,9 @@ class WaccaBase():
|
|||||||
for unlock in profile_song_unlocks:
|
for unlock in profile_song_unlocks:
|
||||||
for x in range(1, unlock["highest_difficulty"] + 1):
|
for x in range(1, unlock["highest_difficulty"] + 1):
|
||||||
resp.userItems.songUnlocks.append(SongUnlock(unlock["song_id"], x, 0, int(unlock["acquire_date"].timestamp())))
|
resp.userItems.songUnlocks.append(SongUnlock(unlock["song_id"], x, 0, int(unlock["acquire_date"].timestamp())))
|
||||||
if x > 2:
|
|
||||||
resp.scores.append(BestScoreDetailV1(unlock["song_id"], x))
|
|
||||||
|
|
||||||
empty_scores = len(resp.scores)
|
|
||||||
for song in profile_scores:
|
for song in profile_scores:
|
||||||
resp.seasonInfo.cumulativeScore += song["score"]
|
resp.seasonInfo.cumulativeScore += song["score"]
|
||||||
empty_score_idx = resp.find_score_idx(song["song_id"], song["chart_id"], 0, empty_scores)
|
|
||||||
|
|
||||||
clear_cts = SongDetailClearCounts(
|
clear_cts = SongDetailClearCounts(
|
||||||
song["play_ct"],
|
song["play_ct"],
|
||||||
@ -368,24 +307,16 @@ class WaccaBase():
|
|||||||
song["grade_master_ct"]
|
song["grade_master_ct"]
|
||||||
)
|
)
|
||||||
|
|
||||||
if empty_score_idx is not None:
|
deets = BestScoreDetailV1(song["song_id"], song["chart_id"])
|
||||||
resp.scores[empty_score_idx].clearCounts = clear_cts
|
deets.clearCounts = clear_cts
|
||||||
resp.scores[empty_score_idx].clearCountsSeason = clear_cts
|
deets.clearCountsSeason = clear_cts
|
||||||
resp.scores[empty_score_idx].gradeCounts = grade_cts
|
deets.gradeCounts = grade_cts
|
||||||
resp.scores[empty_score_idx].score = song["score"]
|
deets.score = song["score"]
|
||||||
resp.scores[empty_score_idx].bestCombo = song["best_combo"]
|
deets.bestCombo = song["best_combo"]
|
||||||
resp.scores[empty_score_idx].lowestMissCtMaybe = song["lowest_miss_ct"]
|
deets.lowestMissCtMaybe = song["lowest_miss_ct"]
|
||||||
resp.scores[empty_score_idx].rating = song["rating"]
|
deets.rating = song["rating"]
|
||||||
|
|
||||||
else:
|
resp.scores.append(deets)
|
||||||
deets = BestScoreDetailV1(song["song_id"], song["chart_id"])
|
|
||||||
deets.clearCounts = clear_cts
|
|
||||||
deets.clearCountsSeason = clear_cts
|
|
||||||
deets.gradeCounts = grade_cts
|
|
||||||
deets.score = song["score"]
|
|
||||||
deets.bestCombo = song["best_combo"]
|
|
||||||
deets.lowestMissCtMaybe = song["lowest_miss_ct"]
|
|
||||||
deets.rating = song["rating"]
|
|
||||||
|
|
||||||
for trophy in profile_trophies:
|
for trophy in profile_trophies:
|
||||||
resp.userItems.trophies.append(TrophyItem(trophy["trophy_id"], trophy["season"], trophy["progress"], trophy["badge_type"]))
|
resp.userItems.trophies.append(TrophyItem(trophy["trophy_id"], trophy["season"], trophy["progress"], trophy["badge_type"]))
|
||||||
@ -434,7 +365,7 @@ class WaccaBase():
|
|||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_trial_get_request(self, data: Dict) -> List[Any]:
|
def handle_user_trial_get_request(self, data: Dict)-> Dict:
|
||||||
req = UserTrialGetRequest(data)
|
req = UserTrialGetRequest(data)
|
||||||
resp = UserTrialGetResponse()
|
resp = UserTrialGetResponse()
|
||||||
|
|
||||||
@ -444,10 +375,6 @@ class WaccaBase():
|
|||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
self.logger.info(f"Get trial info for user {req.profileId}")
|
self.logger.info(f"Get trial info for user {req.profileId}")
|
||||||
|
|
||||||
for d in self.allowed_stages:
|
|
||||||
if d[1] > 0 and d[1] < 10:
|
|
||||||
resp.stageList.append(StageInfo(d[0], d[1]))
|
|
||||||
|
|
||||||
stages = self.data.score.get_stageup(user_id, self.version)
|
stages = self.data.score.get_stageup(user_id, self.version)
|
||||||
if stages is None:
|
if stages is None:
|
||||||
@ -474,7 +401,7 @@ class WaccaBase():
|
|||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_trial_update_request(self, data: Dict) -> List[Any]:
|
def handle_user_trial_update_request(self, data: Dict)-> Dict:
|
||||||
req = UserTrialUpdateRequest(data)
|
req = UserTrialUpdateRequest(data)
|
||||||
|
|
||||||
total_score = 0
|
total_score = 0
|
||||||
@ -496,8 +423,8 @@ class WaccaBase():
|
|||||||
# We only care about total score for best of, even if one score happens to be lower (I think)
|
# We only care about total score for best of, even if one score happens to be lower (I think)
|
||||||
if total_score > (old_stage["song1_score"] + old_stage["song2_score"] + old_stage["song3_score"]):
|
if total_score > (old_stage["song1_score"] + old_stage["song2_score"] + old_stage["song3_score"]):
|
||||||
best_score1 = req.songScores[0]
|
best_score1 = req.songScores[0]
|
||||||
best_score2 = req.songScores[2]
|
best_score2 = req.songScores[1]
|
||||||
best_score3 = req.songScores[3]
|
best_score3 = req.songScores[2]
|
||||||
else:
|
else:
|
||||||
best_score1 = old_stage["song1_score"]
|
best_score1 = old_stage["song1_score"]
|
||||||
best_score2 = old_stage["song2_score"]
|
best_score2 = old_stage["song2_score"]
|
||||||
@ -528,9 +455,9 @@ class WaccaBase():
|
|||||||
self.data.item.put_item(user_id, WaccaConstants.ITEM_TYPES["icon"], current_icon)
|
self.data.item.put_item(user_id, WaccaConstants.ITEM_TYPES["icon"], current_icon)
|
||||||
self.data.item.put_item(user_id, WaccaConstants.ITEM_TYPES["navigator"], current_nav)
|
self.data.item.put_item(user_id, WaccaConstants.ITEM_TYPES["navigator"], current_nav)
|
||||||
self.data.profile.update_profile_playtype(req.profileId, 4, data["appVersion"][:7])
|
self.data.profile.update_profile_playtype(req.profileId, 4, data["appVersion"][:7])
|
||||||
return BaseResponse.make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
def handle_user_sugoroku_update_request(self, data: Dict) -> List[Any]:
|
def handle_user_sugoroku_update_request(self, data: Dict)-> Dict:
|
||||||
ver_split = data["appVersion"].split(".")
|
ver_split = data["appVersion"].split(".")
|
||||||
resp = BaseResponse()
|
resp = BaseResponse()
|
||||||
|
|
||||||
@ -552,10 +479,10 @@ class WaccaBase():
|
|||||||
self.data.profile.update_gate(user_id, req.gateId, req.page, req.progress, req.loops, mission_flg, req.totalPts)
|
self.data.profile.update_gate(user_id, req.gateId, req.page, req.progress, req.loops, mission_flg, req.totalPts)
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_info_getMyroom_request(self, data: Dict) -> List[Any]:
|
def handle_user_info_getMyroom_request(self, data: Dict)-> Dict:
|
||||||
return UserInfogetMyroomResponse().make()
|
return UserInfogetMyroomResponseV1().make()
|
||||||
|
|
||||||
def handle_user_music_unlock_request(self, data: Dict) -> List[Any]:
|
def handle_user_music_unlock_request(self, data: Dict)-> Dict:
|
||||||
req = UserMusicUnlockRequest(data)
|
req = UserMusicUnlockRequest(data)
|
||||||
|
|
||||||
profile = self.data.profile.get_profile(req.profileId)
|
profile = self.data.profile.get_profile(req.profileId)
|
||||||
@ -605,29 +532,35 @@ class WaccaBase():
|
|||||||
|
|
||||||
return UserMusicUnlockResponse(current_wp, new_tickets).make()
|
return UserMusicUnlockResponse(current_wp, new_tickets).make()
|
||||||
|
|
||||||
def handle_user_info_getRanking_request(self, data: Dict) -> List[Any]:
|
def handle_user_info_getRanking_request(self, data: Dict)-> Dict:
|
||||||
# total score, high score by song, cumulative socre, stage up score, other score, WP ranking
|
# total score, high score by song, cumulative socre, stage up score, other score, WP ranking
|
||||||
# This likely requies calculating standings at regular intervals and caching the results
|
# This likely requies calculating standings at regular intervals and caching the results
|
||||||
return UserInfogetRankingResponse().make()
|
return UserInfogetRankingResponse().make()
|
||||||
|
|
||||||
def handle_user_music_update_request(self, data: Dict) -> List[Any]:
|
def handle_user_music_update_request(self, data: Dict)-> Dict:
|
||||||
req = UserMusicUpdateRequest(data)
|
ver_split = data["appVersion"].split(".")
|
||||||
ver_split = req.appVersion.split(".")
|
|
||||||
if int(ver_split[0]) >= 3:
|
if int(ver_split[0]) >= 3:
|
||||||
resp = UserMusicUpdateResponseV3()
|
resp = UserMusicUpdateResponseV3()
|
||||||
|
req = UserMusicUpdateRequestV2(data)
|
||||||
elif int(ver_split[0]) >= 2:
|
elif int(ver_split[0]) >= 2:
|
||||||
resp = UserMusicUpdateResponseV2()
|
resp = UserMusicUpdateResponseV2()
|
||||||
|
req = UserMusicUpdateRequestV2(data)
|
||||||
else:
|
else:
|
||||||
resp = UserMusicUpdateResponseV1()
|
resp = UserMusicUpdateResponseV1()
|
||||||
|
req = UserMusicUpdateRequestV1(data)
|
||||||
|
|
||||||
resp.songDetail.songId = req.songDetail.songId
|
resp.songDetail.songId = req.songDetail.songId
|
||||||
resp.songDetail.difficulty = req.songDetail.difficulty
|
resp.songDetail.difficulty = req.songDetail.difficulty
|
||||||
|
|
||||||
|
if req.profileId == 0:
|
||||||
|
self.logger.info(f"Guest score for song {req.songDetail.songId} difficulty {req.songDetail.difficulty}")
|
||||||
|
return resp.make()
|
||||||
|
|
||||||
profile = self.data.profile.get_profile(req.profileId)
|
profile = self.data.profile.get_profile(req.profileId)
|
||||||
|
|
||||||
if profile is None:
|
if profile is None:
|
||||||
self.logger.warn(f"handle_user_music_update_request: No profile for game_id {req.profileId}")
|
self.logger.warn(f"handle_user_music_update_request: No profile for game_id {req.profileId}")
|
||||||
return BaseResponse().make()
|
return resp.make()
|
||||||
|
|
||||||
user_id = profile["user"]
|
user_id = profile["user"]
|
||||||
self.util_put_items(req.profileId, user_id, req.itemsObtained)
|
self.util_put_items(req.profileId, user_id, req.itemsObtained)
|
||||||
@ -715,18 +648,18 @@ class WaccaBase():
|
|||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
#TODO: Coop and vs data
|
#TODO: Coop and vs data
|
||||||
def handle_user_music_updateCoop_request(self, data: Dict) -> List[Any]:
|
def handle_user_music_updateCoop_request(self, data: Dict)-> Dict:
|
||||||
coop_info = data["params"][4]
|
coop_info = data["params"][4]
|
||||||
return self.handle_user_music_update_request(data)
|
return self.handle_user_music_update_request(data)
|
||||||
|
|
||||||
def handle_user_music_updateVersus_request(self, data: Dict) -> List[Any]:
|
def handle_user_music_updateVersus_request(self, data: Dict)-> Dict:
|
||||||
vs_info = data["params"][4]
|
vs_info = data["params"][4]
|
||||||
return self.handle_user_music_update_request(data)
|
return self.handle_user_music_update_request(data)
|
||||||
|
|
||||||
def handle_user_music_updateTrial_request(self, data: Dict) -> List[Any]:
|
def handle_user_music_updateTrial_request(self, data: Dict)-> Dict:
|
||||||
return self.handle_user_music_update_request(data)
|
return self.handle_user_music_update_request(data)
|
||||||
|
|
||||||
def handle_user_mission_update_request(self, data: Dict) -> List[Any]:
|
def handle_user_mission_update_request(self, data: Dict)-> Dict:
|
||||||
req = UserMissionUpdateRequest(data)
|
req = UserMissionUpdateRequest(data)
|
||||||
page_status = req.params[1][1]
|
page_status = req.params[1][1]
|
||||||
|
|
||||||
@ -742,7 +675,7 @@ class WaccaBase():
|
|||||||
|
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
def handle_user_goods_purchase_request(self, data: Dict) -> List[Any]:
|
def handle_user_goods_purchase_request(self, data: Dict)-> Dict:
|
||||||
req = UserGoodsPurchaseRequest(data)
|
req = UserGoodsPurchaseRequest(data)
|
||||||
resp = UserGoodsPurchaseResponse()
|
resp = UserGoodsPurchaseResponse()
|
||||||
|
|
||||||
@ -775,13 +708,13 @@ class WaccaBase():
|
|||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_competition_status_login_request(self, data: Dict) -> List[Any]:
|
def handle_competition_status_login_request(self, data: Dict)-> Dict:
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
def handle_competition_status_update_request(self, data: Dict) -> List[Any]:
|
def handle_competition_status_update_request(self, data: Dict)-> Dict:
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
def handle_user_rating_update_request(self, data: Dict) -> List[Any]:
|
def handle_user_rating_update_request(self, data: Dict)-> Dict:
|
||||||
req = UserRatingUpdateRequest(data)
|
req = UserRatingUpdateRequest(data)
|
||||||
|
|
||||||
user_id = self.data.profile.profile_to_aime_user(req.profileId)
|
user_id = self.data.profile.profile_to_aime_user(req.profileId)
|
||||||
@ -797,8 +730,8 @@ class WaccaBase():
|
|||||||
|
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
def handle_user_status_update_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_update_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusUpdateRequestV2(data)
|
req = UserStatusUpdateRequestV1(data)
|
||||||
|
|
||||||
user_id = self.data.profile.profile_to_aime_user(req.profileId)
|
user_id = self.data.profile.profile_to_aime_user(req.profileId)
|
||||||
if user_id is None:
|
if user_id is None:
|
||||||
@ -807,8 +740,6 @@ class WaccaBase():
|
|||||||
|
|
||||||
self.util_put_items(req.profileId, user_id, req.itemsRecieved)
|
self.util_put_items(req.profileId, user_id, req.itemsRecieved)
|
||||||
self.data.profile.update_profile_playtype(req.profileId, req.playType.value, data["appVersion"][:7])
|
self.data.profile.update_profile_playtype(req.profileId, req.playType.value, data["appVersion"][:7])
|
||||||
self.data.profile.update_profile_lastplayed(req.profileId, req.lastSongInfo.lastSongId, req.lastSongInfo.lastSongDiff,
|
|
||||||
req.lastSongInfo.lastFolderOrd, req.lastSongInfo.lastFolderId, req.lastSongInfo.lastSongOrd)
|
|
||||||
|
|
||||||
current_icon = self.data.profile.get_options(user_id, WaccaConstants.OPTIONS["set_icon_id"])
|
current_icon = self.data.profile.get_options(user_id, WaccaConstants.OPTIONS["set_icon_id"])
|
||||||
current_nav = self.data.profile.get_options(user_id, WaccaConstants.OPTIONS["set_nav_id"])
|
current_nav = self.data.profile.get_options(user_id, WaccaConstants.OPTIONS["set_nav_id"])
|
||||||
@ -826,7 +757,7 @@ class WaccaBase():
|
|||||||
self.data.item.put_item(user_id, WaccaConstants.ITEM_TYPES["navigator"], current_nav)
|
self.data.item.put_item(user_id, WaccaConstants.ITEM_TYPES["navigator"], current_nav)
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
def handle_user_info_update_request(self, data: Dict) -> List[Any]:
|
def handle_user_info_update_request(self, data: Dict)-> Dict:
|
||||||
req = UserInfoUpdateRequest(data)
|
req = UserInfoUpdateRequest(data)
|
||||||
|
|
||||||
user_id = self.data.profile.profile_to_aime_user(req.profileId)
|
user_id = self.data.profile.profile_to_aime_user(req.profileId)
|
||||||
@ -845,7 +776,7 @@ class WaccaBase():
|
|||||||
|
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
|
||||||
def handle_user_vip_get_request(self, data: Dict) -> List[Any]:
|
def handle_user_vip_get_request(self, data: Dict)-> Dict:
|
||||||
req = UserVipGetRequest(data)
|
req = UserVipGetRequest(data)
|
||||||
resp = UserVipGetResponse()
|
resp = UserVipGetResponse()
|
||||||
|
|
||||||
@ -868,7 +799,7 @@ class WaccaBase():
|
|||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_vip_start_request(self, data: Dict) -> List[Any]:
|
def handle_user_vip_start_request(self, data: Dict)-> Dict:
|
||||||
req = UserVipStartRequest(data)
|
req = UserVipStartRequest(data)
|
||||||
|
|
||||||
profile = self.data.profile.get_profile(req.profileId)
|
profile = self.data.profile.get_profile(req.profileId)
|
||||||
|
@ -6,6 +6,7 @@ from core.frontend import FE_Base
|
|||||||
from core.config import CoreConfig
|
from core.config import CoreConfig
|
||||||
from titles.wacca.database import WaccaData
|
from titles.wacca.database import WaccaData
|
||||||
from titles.wacca.config import WaccaConfig
|
from titles.wacca.config import WaccaConfig
|
||||||
|
from titles.wacca.const import WaccaConstants
|
||||||
|
|
||||||
class WaccaFrontend(FE_Base):
|
class WaccaFrontend(FE_Base):
|
||||||
def __init__(self, cfg: CoreConfig, environment: jinja2.Environment, cfg_dir: str) -> None:
|
def __init__(self, cfg: CoreConfig, environment: jinja2.Environment, cfg_dir: str) -> None:
|
||||||
@ -13,6 +14,11 @@ class WaccaFrontend(FE_Base):
|
|||||||
self.data = WaccaData(cfg)
|
self.data = WaccaData(cfg)
|
||||||
self.game_cfg = WaccaConfig()
|
self.game_cfg = WaccaConfig()
|
||||||
self.game_cfg.update(yaml.safe_load(open(f"{cfg_dir}/wacca.yaml")))
|
self.game_cfg.update(yaml.safe_load(open(f"{cfg_dir}/wacca.yaml")))
|
||||||
|
self.nav_name = "Wacca"
|
||||||
|
|
||||||
def render_GET(self, request: Request) -> bytes:
|
def render_GET(self, request: Request) -> bytes:
|
||||||
return b""
|
template = self.environment.get_template("titles/wacca/frontend/wacca_index.jinja")
|
||||||
|
return template.render(
|
||||||
|
title=f"{self.core_config.server.name} | {self.nav_name}",
|
||||||
|
game_list=self.environment.globals["game_list"]
|
||||||
|
).encode("utf-16")
|
||||||
|
4
titles/wacca/frontend/wacca_index.jinja
Normal file
4
titles/wacca/frontend/wacca_index.jinja
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{% extends "core/frontend/index.jinja" %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>Wacca</h1>
|
||||||
|
{% endblock content %}
|
@ -1,6 +1,6 @@
|
|||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
|
|
||||||
from titles.wacca.handlers.base import BaseResponse
|
from titles.wacca.handlers.base import BaseResponse, BaseRequest
|
||||||
from titles.wacca.handlers.helpers import Notice
|
from titles.wacca.handlers.helpers import Notice
|
||||||
|
|
||||||
# ---advertise/GetNews---
|
# ---advertise/GetNews---
|
||||||
@ -33,13 +33,33 @@ class GetNewsResponseV1(BaseResponse):
|
|||||||
|
|
||||||
class GetNewsResponseV2(GetNewsResponseV1):
|
class GetNewsResponseV2(GetNewsResponseV1):
|
||||||
stoppedProducts: list[int] = []
|
stoppedProducts: list[int] = []
|
||||||
|
|
||||||
|
def make(self) -> Dict:
|
||||||
|
super().make()
|
||||||
|
self.params.append(self.stoppedProducts)
|
||||||
|
|
||||||
|
return super(GetNewsResponseV1, self).make()
|
||||||
|
|
||||||
|
class GetNewsResponseV3(GetNewsResponseV2):
|
||||||
stoppedNavs: list[int] = []
|
stoppedNavs: list[int] = []
|
||||||
stoppedNavVoices: list[int] = []
|
stoppedNavVoices: list[int] = []
|
||||||
|
|
||||||
def make(self) -> Dict:
|
def make(self) -> Dict:
|
||||||
super().make()
|
super().make()
|
||||||
self.params.append(self.stoppedProducts)
|
|
||||||
self.params.append(self.stoppedNavs)
|
self.params.append(self.stoppedNavs)
|
||||||
self.params.append(self.stoppedNavVoices)
|
self.params.append(self.stoppedNavVoices)
|
||||||
|
|
||||||
return super(GetNewsResponseV1, self).make()
|
return super(GetNewsResponseV1, self).make()
|
||||||
|
|
||||||
|
# ---advertise/GetRanking---
|
||||||
|
class AdvertiseGetRankingRequest(BaseRequest):
|
||||||
|
def __init__(self, data: Dict) -> None:
|
||||||
|
super().__init__(data)
|
||||||
|
self.resourceVer: int = self.params[0]
|
||||||
|
|
||||||
|
class AdvertiseGetRankingResponse(BaseResponse):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def make(self) -> Dict:
|
||||||
|
return super().make()
|
@ -1,4 +1,4 @@
|
|||||||
from typing import List, Dict, Any
|
from typing import List, Optional, Any
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from titles.wacca.const import WaccaConstants
|
from titles.wacca.const import WaccaConstants
|
||||||
@ -41,9 +41,6 @@ class Notice():
|
|||||||
int(self.showWelcomeScreen), self.startTime, self.endTime, self.voiceline]
|
int(self.showWelcomeScreen), self.startTime, self.endTime, self.voiceline]
|
||||||
|
|
||||||
class UserOption():
|
class UserOption():
|
||||||
opt_id: int
|
|
||||||
opt_val: Any
|
|
||||||
|
|
||||||
def __init__(self, opt_id: int = 0, opt_val: Any = 0) -> None:
|
def __init__(self, opt_id: int = 0, opt_val: Any = 0) -> None:
|
||||||
self.opt_id = opt_id
|
self.opt_id = opt_id
|
||||||
self.opt_val = opt_val
|
self.opt_val = opt_val
|
||||||
@ -53,7 +50,7 @@ class UserOption():
|
|||||||
|
|
||||||
class UserStatusV1():
|
class UserStatusV1():
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.userId: int = -1
|
self.userId: int = 0
|
||||||
self.username: str = ""
|
self.username: str = ""
|
||||||
self.userType: int = 1
|
self.userType: int = 1
|
||||||
self.xp: int = 0
|
self.xp: int = 0
|
||||||
@ -62,10 +59,6 @@ class UserStatusV1():
|
|||||||
self.wp: int = 0
|
self.wp: int = 0
|
||||||
self.titlePartIds: List[int] = [0, 0, 0]
|
self.titlePartIds: List[int] = [0, 0, 0]
|
||||||
self.useCount: int = 0
|
self.useCount: int = 0
|
||||||
self.loginDays: int = 0
|
|
||||||
self.loginConsecutive: int = 0
|
|
||||||
self.loginConsecutiveDays: int = 0
|
|
||||||
self.vipExpireTime: int = 0
|
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self) -> List:
|
||||||
return [
|
return [
|
||||||
@ -78,21 +71,25 @@ class UserStatusV1():
|
|||||||
self.wp,
|
self.wp,
|
||||||
self.titlePartIds,
|
self.titlePartIds,
|
||||||
self.useCount,
|
self.useCount,
|
||||||
self.loginDays,
|
|
||||||
self.loginConsecutive,
|
|
||||||
self.loginConsecutiveDays,
|
|
||||||
self.vipExpireTime
|
|
||||||
]
|
]
|
||||||
|
|
||||||
class UserStatusV2(UserStatusV1):
|
class UserStatusV2(UserStatusV1):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.loginDays: int = 0
|
||||||
|
self.loginConsecutive: int = 0
|
||||||
|
self.loginConsecutiveDays: int = 0
|
||||||
self.loginsToday: int = 0
|
self.loginsToday: int = 0
|
||||||
self.rating: int = 0
|
self.rating: int = 0
|
||||||
|
self.vipExpireTime: int = 0
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self) -> List:
|
||||||
ret = super().make()
|
ret = super().make()
|
||||||
|
|
||||||
|
ret.append(self.loginDays)
|
||||||
|
ret.append(self.loginConsecutive)
|
||||||
|
ret.append(self.loginConsecutiveDays)
|
||||||
|
ret.append(self.vipExpireTime)
|
||||||
ret.append(self.loginsToday)
|
ret.append(self.loginsToday)
|
||||||
ret.append(self.rating)
|
ret.append(self.rating)
|
||||||
|
|
||||||
@ -336,7 +333,7 @@ class UserItemInfoV3(UserItemInfoV2):
|
|||||||
|
|
||||||
class SongDetailClearCounts():
|
class SongDetailClearCounts():
|
||||||
def __init__(self, play_ct: int = 0, clear_ct: int = 0, ml_ct: int = 0, fc_ct: int = 0,
|
def __init__(self, play_ct: int = 0, clear_ct: int = 0, ml_ct: int = 0, fc_ct: int = 0,
|
||||||
am_ct: int = 0, counts: List[int] = None) -> None:
|
am_ct: int = 0, counts: Optional[List[int]] = None) -> None:
|
||||||
if counts is None:
|
if counts is None:
|
||||||
self.playCt = play_ct
|
self.playCt = play_ct
|
||||||
self.clearCt = clear_ct
|
self.clearCt = clear_ct
|
||||||
@ -367,7 +364,7 @@ class SongDetailGradeCountsV1():
|
|||||||
masterCt: int
|
masterCt: int
|
||||||
|
|
||||||
def __init__(self, d: int = 0, c: int = 0, b: int = 0, a: int = 0, aa: int = 0, aaa: int = 0, s: int = 0,
|
def __init__(self, d: int = 0, c: int = 0, b: int = 0, a: int = 0, aa: int = 0, aaa: int = 0, s: int = 0,
|
||||||
ss: int = 0, sss: int = 0, master: int = 0, counts: List[int] = None) -> None:
|
ss: int = 0, sss: int = 0, master: int = 0, counts: Optional[List[int]] = None) -> None:
|
||||||
if counts is None:
|
if counts is None:
|
||||||
self.dCt = d
|
self.dCt = d
|
||||||
self.cCt = c
|
self.cCt = c
|
||||||
@ -401,7 +398,7 @@ class SongDetailGradeCountsV2(SongDetailGradeCountsV1):
|
|||||||
ssspCt: int
|
ssspCt: int
|
||||||
|
|
||||||
def __init__(self, d: int = 0, c: int = 0, b: int = 0, a: int = 0, aa: int = 0, aaa: int = 0, s: int = 0,
|
def __init__(self, d: int = 0, c: int = 0, b: int = 0, a: int = 0, aa: int = 0, aaa: int = 0, s: int = 0,
|
||||||
ss: int = 0, sss: int = 0, master: int = 0, sp: int = 0, ssp: int = 0, sssp: int = 0, counts: List[int] = None, ) -> None:
|
ss: int = 0, sss: int = 0, master: int = 0, sp: int = 0, ssp: int = 0, sssp: int = 0, counts: Optional[List[int]] = None) -> None:
|
||||||
super().__init__(d, c, b, a, aa, aaa, s, ss, sss, master, counts)
|
super().__init__(d, c, b, a, aa, aaa, s, ss, sss, master, counts)
|
||||||
if counts is None:
|
if counts is None:
|
||||||
self.spCt = sp
|
self.spCt = sp
|
||||||
@ -464,25 +461,8 @@ class SongUpdateJudgementCounts():
|
|||||||
def make(self) -> List:
|
def make(self) -> List:
|
||||||
return [self.marvCt, self.greatCt, self.goodCt, self.missCt]
|
return [self.marvCt, self.greatCt, self.goodCt, self.missCt]
|
||||||
|
|
||||||
class SongUpdateDetail():
|
class SongUpdateDetailV1():
|
||||||
songId: int
|
def __init__(self, data: List) -> None:
|
||||||
difficulty: int
|
|
||||||
level: float
|
|
||||||
score: int
|
|
||||||
judgements: SongUpdateJudgementCounts
|
|
||||||
maxCombo: int
|
|
||||||
grade: WaccaConstants.GRADES
|
|
||||||
flagCleared: bool
|
|
||||||
flagMissless: bool
|
|
||||||
flagFullcombo: bool
|
|
||||||
flagAllMarvelous: bool
|
|
||||||
flagGiveUp: bool
|
|
||||||
skillPt: int
|
|
||||||
fastCt: int
|
|
||||||
slowCt: int
|
|
||||||
flagNewRecord: bool
|
|
||||||
|
|
||||||
def __init__(self, data: List = None) -> None:
|
|
||||||
if data is not None:
|
if data is not None:
|
||||||
self.songId = data[0]
|
self.songId = data[0]
|
||||||
self.difficulty = data[1]
|
self.difficulty = data[1]
|
||||||
@ -498,8 +478,15 @@ class SongUpdateDetail():
|
|||||||
self.flagFullcombo = False if data[9] == 0 else True
|
self.flagFullcombo = False if data[9] == 0 else True
|
||||||
self.flagAllMarvelous = False if data[10] == 0 else True
|
self.flagAllMarvelous = False if data[10] == 0 else True
|
||||||
self.flagGiveUp = False if data[11] == 0 else True
|
self.flagGiveUp = False if data[11] == 0 else True
|
||||||
|
self.skillPt = data[12]
|
||||||
|
self.fastCt = 0
|
||||||
|
self.slowCt = 0
|
||||||
|
self.flagNewRecord = False
|
||||||
|
|
||||||
self.skillPt = data[12]
|
class SongUpdateDetailV2(SongUpdateDetailV1):
|
||||||
|
def __init__(self, data: List) -> None:
|
||||||
|
super().__init__(data)
|
||||||
|
if data is not None:
|
||||||
self.fastCt = data[13]
|
self.fastCt = data[13]
|
||||||
self.slowCt = data[14]
|
self.slowCt = data[14]
|
||||||
self.flagNewRecord = False if data[15] == 0 else True
|
self.flagNewRecord = False if data[15] == 0 else True
|
||||||
@ -583,7 +570,7 @@ class GateDetailV2(GateDetailV1):
|
|||||||
return super().make() + [self.missionFlg]
|
return super().make() + [self.missionFlg]
|
||||||
|
|
||||||
class GachaInfo():
|
class GachaInfo():
|
||||||
def make() -> List:
|
def make(self) -> List:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
class LastSongDetail():
|
class LastSongDetail():
|
||||||
@ -609,17 +596,6 @@ class FriendDetail():
|
|||||||
def make(self) -> List:
|
def make(self) -> List:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
class UserOption():
|
|
||||||
id = 1
|
|
||||||
val = 1
|
|
||||||
|
|
||||||
def __init__(self, id: int = 1, val: int = val) -> None:
|
|
||||||
self.id = id
|
|
||||||
self.val = val
|
|
||||||
|
|
||||||
def make(self) -> List:
|
|
||||||
return [self.id, self.val]
|
|
||||||
|
|
||||||
class LoginBonusInfo():
|
class LoginBonusInfo():
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.tickets: List[TicketItem] = []
|
self.tickets: List[TicketItem] = []
|
||||||
@ -682,19 +658,6 @@ class PlayType(Enum):
|
|||||||
PlayTypeCoop = 3
|
PlayTypeCoop = 3
|
||||||
PlayTypeStageup = 4
|
PlayTypeStageup = 4
|
||||||
|
|
||||||
class SongRatingUpdate():
|
|
||||||
song_id = 0
|
|
||||||
difficulty = 0
|
|
||||||
rating = 0
|
|
||||||
|
|
||||||
def __init__(self, song: int = 0, difficulty: int = 0, rating: int = 0) -> None:
|
|
||||||
self.song_id = song
|
|
||||||
self.difficulty = difficulty
|
|
||||||
self.rating = rating
|
|
||||||
|
|
||||||
def make(self) -> List:
|
|
||||||
return [self.song_id, self.difficulty, self.rating]
|
|
||||||
|
|
||||||
class StageInfo():
|
class StageInfo():
|
||||||
danId: int = 0
|
danId: int = 0
|
||||||
danLevel: int = 0
|
danLevel: int = 0
|
||||||
@ -740,7 +703,6 @@ class MusicUpdateDetailV1():
|
|||||||
self.lowestMissCount = 0
|
self.lowestMissCount = 0
|
||||||
self.maxSkillPts = 0
|
self.maxSkillPts = 0
|
||||||
self.locked = 0
|
self.locked = 0
|
||||||
self.rating = 0
|
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self) -> List:
|
||||||
return [
|
return [
|
||||||
@ -753,10 +715,17 @@ class MusicUpdateDetailV1():
|
|||||||
self.lowestMissCount,
|
self.lowestMissCount,
|
||||||
self.maxSkillPts,
|
self.maxSkillPts,
|
||||||
self.locked,
|
self.locked,
|
||||||
self.rating
|
|
||||||
]
|
]
|
||||||
|
|
||||||
class MusicUpdateDetailV2(MusicUpdateDetailV1):
|
class MusicUpdateDetailV2(MusicUpdateDetailV1):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.rating = 0
|
||||||
|
|
||||||
|
def make(self) -> List:
|
||||||
|
return super().make() + [self.rating]
|
||||||
|
|
||||||
|
class MusicUpdateDetailV3(MusicUpdateDetailV2):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.grades = SongDetailGradeCountsV2()
|
self.grades = SongDetailGradeCountsV2()
|
||||||
|
@ -15,12 +15,22 @@ class HousingGetResponse(BaseResponse):
|
|||||||
return super().make()
|
return super().make()
|
||||||
|
|
||||||
# ---housing/start----
|
# ---housing/start----
|
||||||
class HousingStartRequest(BaseRequest):
|
class HousingStartRequestV1(BaseRequest):
|
||||||
def __init__(self, data: Dict) -> None:
|
def __init__(self, data: Dict) -> None:
|
||||||
super().__init__(data)
|
super().__init__(data)
|
||||||
self.unknown0: str = self.params[0]
|
self.unknown0: str = self.params[0]
|
||||||
self.errorLog: str = self.params[1]
|
self.errorLog: str = self.params[1]
|
||||||
self.unknown2: str = self.params[2]
|
self.info: List[HousingInfo] = []
|
||||||
|
|
||||||
|
for info in self.params[2]:
|
||||||
|
self.info.append(HousingInfo(info[0], info[1]))
|
||||||
|
|
||||||
|
class HousingStartRequestV2(HousingStartRequestV1):
|
||||||
|
def __init__(self, data: Dict) -> None:
|
||||||
|
super(HousingStartRequestV1, self).__init__(data)
|
||||||
|
self.unknown0: str = self.params[0]
|
||||||
|
self.errorLog: str = self.params[1]
|
||||||
|
self.creditLog: str = self.params[2]
|
||||||
self.info: List[HousingInfo] = []
|
self.info: List[HousingInfo] = []
|
||||||
|
|
||||||
for info in self.params[3]:
|
for info in self.params[3]:
|
||||||
|
@ -23,14 +23,37 @@ class UserInfogetMyroomRequest(BaseRequest):
|
|||||||
super().__init__(data)
|
super().__init__(data)
|
||||||
self.game_id = int(self.params[0])
|
self.game_id = int(self.params[0])
|
||||||
|
|
||||||
class UserInfogetMyroomResponse(BaseResponse):
|
class UserInfogetMyroomResponseV1(BaseResponse):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.titleViewBadge = 0
|
||||||
|
self.iconViewBadge = 0
|
||||||
|
self.trophyViewBadge = 0
|
||||||
|
self.noteColorViewBadge = 0
|
||||||
|
self.noteSoundViewBadge = 0
|
||||||
|
self.userViewingInfo = []
|
||||||
|
|
||||||
def make(self) -> Dict:
|
def make(self) -> Dict:
|
||||||
self.params = [
|
self.params = [
|
||||||
0,0,0,0,0,[],0,0,0
|
self.titleViewBadge,
|
||||||
|
self.iconViewBadge,
|
||||||
|
self.trophyViewBadge,
|
||||||
|
self.noteColorViewBadge,
|
||||||
|
self.noteSoundViewBadge,
|
||||||
|
self.userViewingInfo,
|
||||||
]
|
]
|
||||||
|
|
||||||
return super().make()
|
return super().make()
|
||||||
|
|
||||||
|
class UserInfogetMyroomResponseV2(UserInfogetMyroomResponseV1):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def make(self) -> Dict:
|
||||||
|
super().make()
|
||||||
|
self.params += [0, 0, 0]
|
||||||
|
return super(UserInfogetMyroomResponseV1, self).make()
|
||||||
|
|
||||||
# ---user/info/getRanking---
|
# ---user/info/getRanking---
|
||||||
class UserInfogetRankingRequest(BaseRequest):
|
class UserInfogetRankingRequest(BaseRequest):
|
||||||
game_id = 0
|
game_id = 0
|
||||||
|
@ -25,7 +25,7 @@ class UserGoodsPurchaseResponse(BaseResponse):
|
|||||||
for ticket in tickets:
|
for ticket in tickets:
|
||||||
self.tickets.append(TicketItem(ticket[0], ticket[1], ticket[2]))
|
self.tickets.append(TicketItem(ticket[0], ticket[1], ticket[2]))
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self) -> Dict:
|
||||||
tix = []
|
tix = []
|
||||||
for ticket in self.tickets:
|
for ticket in self.tickets:
|
||||||
tix.append(ticket.make())
|
tix.append(ticket.make())
|
||||||
|
@ -1,22 +1,28 @@
|
|||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
|
|
||||||
from titles.wacca.handlers.base import BaseRequest, BaseResponse
|
from titles.wacca.handlers.base import BaseRequest, BaseResponse
|
||||||
from titles.wacca.handlers.helpers import GenericItemRecv, SongUpdateDetail, TicketItem
|
from titles.wacca.handlers.helpers import GenericItemRecv, SongUpdateDetailV2, TicketItem
|
||||||
from titles.wacca.handlers.helpers import MusicUpdateDetailV1, MusicUpdateDetailV2
|
from titles.wacca.handlers.helpers import MusicUpdateDetailV2, MusicUpdateDetailV3
|
||||||
from titles.wacca.handlers.helpers import SeasonalInfoV2, SeasonalInfoV1
|
from titles.wacca.handlers.helpers import SeasonalInfoV2, SeasonalInfoV1, SongUpdateDetailV1
|
||||||
|
from titles.wacca.handlers.helpers import MusicUpdateDetailV1
|
||||||
|
|
||||||
# ---user/music/update---
|
# ---user/music/update---
|
||||||
class UserMusicUpdateRequest(BaseRequest):
|
class UserMusicUpdateRequestV1(BaseRequest):
|
||||||
def __init__(self, data: Dict) -> None:
|
def __init__(self, data: Dict) -> None:
|
||||||
super().__init__(data)
|
super().__init__(data)
|
||||||
self.profileId: int = self.params[0]
|
self.profileId: int = self.params[0]
|
||||||
self.songNumber: int = self.params[1]
|
self.songNumber: int = self.params[1]
|
||||||
self.songDetail = SongUpdateDetail(self.params[2])
|
self.songDetail = SongUpdateDetailV1(self.params[2])
|
||||||
self.itemsObtained: List[GenericItemRecv] = []
|
self.itemsObtained: List[GenericItemRecv] = []
|
||||||
|
|
||||||
for itm in data["params"][3]:
|
for itm in data["params"][3]:
|
||||||
self.itemsObtained.append(GenericItemRecv(itm[0], itm[1], itm[2]))
|
self.itemsObtained.append(GenericItemRecv(itm[0], itm[1], itm[2]))
|
||||||
|
|
||||||
|
class UserMusicUpdateRequestV2(UserMusicUpdateRequestV1):
|
||||||
|
def __init__(self, data: Dict) -> None:
|
||||||
|
super().__init__(data)
|
||||||
|
self.songDetail = SongUpdateDetailV2(self.params[2])
|
||||||
|
|
||||||
class UserMusicUpdateResponseV1(BaseResponse):
|
class UserMusicUpdateResponseV1(BaseResponse):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -37,21 +43,22 @@ class UserMusicUpdateResponseV1(BaseResponse):
|
|||||||
class UserMusicUpdateResponseV2(UserMusicUpdateResponseV1):
|
class UserMusicUpdateResponseV2(UserMusicUpdateResponseV1):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.songDetail = MusicUpdateDetailV2()
|
||||||
self.seasonInfo = SeasonalInfoV2()
|
self.seasonInfo = SeasonalInfoV2()
|
||||||
|
|
||||||
class UserMusicUpdateResponseV3(UserMusicUpdateResponseV2):
|
class UserMusicUpdateResponseV3(UserMusicUpdateResponseV2):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.songDetail = MusicUpdateDetailV2()
|
self.songDetail = MusicUpdateDetailV3()
|
||||||
|
|
||||||
# ---user/music/updateCoop---
|
# ---user/music/updateCoop---
|
||||||
class UserMusicUpdateCoopRequest(UserMusicUpdateRequest):
|
class UserMusicUpdateCoopRequest(UserMusicUpdateRequestV2):
|
||||||
def __init__(self, data: Dict) -> None:
|
def __init__(self, data: Dict) -> None:
|
||||||
super().__init__(data)
|
super().__init__(data)
|
||||||
self.coopData = self.params[4]
|
self.coopData = self.params[4]
|
||||||
|
|
||||||
# ---user/music/updateVs---
|
# ---user/music/updateVs---
|
||||||
class UserMusicUpdateVsRequest(UserMusicUpdateRequest):
|
class UserMusicUpdateVsRequest(UserMusicUpdateRequestV2):
|
||||||
def __init__(self, data: Dict) -> None:
|
def __init__(self, data: Dict) -> None:
|
||||||
super().__init__(data)
|
super().__init__(data)
|
||||||
self.vsData = self.params[4]
|
self.vsData = self.params[4]
|
||||||
@ -77,7 +84,7 @@ class UserMusicUnlockResponse(BaseResponse):
|
|||||||
for ticket in tickets_remaining:
|
for ticket in tickets_remaining:
|
||||||
self.tickets.append(TicketItem(ticket[0], ticket[1], ticket[2]))
|
self.tickets.append(TicketItem(ticket[0], ticket[1], ticket[2]))
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self)-> Dict:
|
||||||
tickets = []
|
tickets = []
|
||||||
|
|
||||||
for ticket in self.tickets:
|
for ticket in self.tickets:
|
||||||
|
@ -65,11 +65,11 @@ class UserStatusGetDetailResponseV1(BaseResponse):
|
|||||||
self.userItems: UserItemInfoV1 = UserItemInfoV1()
|
self.userItems: UserItemInfoV1 = UserItemInfoV1()
|
||||||
self.scores: List[BestScoreDetailV1] = []
|
self.scores: List[BestScoreDetailV1] = []
|
||||||
self.songPlayStatus: List[int] = [0,0]
|
self.songPlayStatus: List[int] = [0,0]
|
||||||
self.seasonInfo: SeasonalInfoV1 = []
|
self.seasonInfo: SeasonalInfoV1 = SeasonalInfoV1()
|
||||||
self.playAreaList: List = [ [0],[0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0],[0,0,0,0],[0,0,0,0,0,0,0],[0] ]
|
self.playAreaList: List = [ [0],[0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0],[0,0,0,0],[0,0,0,0,0,0,0],[0] ]
|
||||||
self.songUpdateTime: int = 0
|
self.songUpdateTime: int = 0
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self)-> Dict:
|
||||||
opts = []
|
opts = []
|
||||||
play_modes = []
|
play_modes = []
|
||||||
scores = []
|
scores = []
|
||||||
@ -97,7 +97,7 @@ class UserStatusGetDetailResponseV1(BaseResponse):
|
|||||||
|
|
||||||
return super().make()
|
return super().make()
|
||||||
|
|
||||||
def find_score_idx(self, song_id: int, difficulty: int = 1, start_idx: int = 0, stop_idx: int = None) -> Optional[int]:
|
def find_score_idx(self, song_id: int, difficulty: int = 1, start_idx: int = 0, stop_idx: Optional[int] = None) -> Optional[int]:
|
||||||
if stop_idx is None or stop_idx > len(self.scores):
|
if stop_idx is None or stop_idx > len(self.scores):
|
||||||
stop_idx = len(self.scores)
|
stop_idx = len(self.scores)
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ class UserStatusGetDetailResponseV2(UserStatusGetDetailResponseV1):
|
|||||||
self.gatchaInfo: List[GachaInfo] = []
|
self.gatchaInfo: List[GachaInfo] = []
|
||||||
self.friendList: List[FriendDetail] = []
|
self.friendList: List[FriendDetail] = []
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self)-> Dict:
|
||||||
super().make()
|
super().make()
|
||||||
gates = []
|
gates = []
|
||||||
friends = []
|
friends = []
|
||||||
@ -164,7 +164,7 @@ class UserStatusGetDetailResponseV4(UserStatusGetDetailResponseV3):
|
|||||||
self.bingoStatus: BingoDetail = BingoDetail(0)
|
self.bingoStatus: BingoDetail = BingoDetail(0)
|
||||||
self.scores: List[BestScoreDetailV2] = []
|
self.scores: List[BestScoreDetailV2] = []
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self)-> Dict:
|
||||||
super().make()
|
super().make()
|
||||||
self.params.append(self.bingoStatus.make())
|
self.params.append(self.bingoStatus.make())
|
||||||
|
|
||||||
@ -187,7 +187,8 @@ class UserStatusLoginResponseV1(BaseResponse):
|
|||||||
self.firstLoginDaily = is_first_login_daily
|
self.firstLoginDaily = is_first_login_daily
|
||||||
self.lastLoginDate = last_login_date
|
self.lastLoginDate = last_login_date
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self)-> Dict:
|
||||||
|
super().make()
|
||||||
daily = []
|
daily = []
|
||||||
consec = []
|
consec = []
|
||||||
other = []
|
other = []
|
||||||
@ -205,25 +206,24 @@ class UserStatusLoginResponseV1(BaseResponse):
|
|||||||
return super().make()
|
return super().make()
|
||||||
|
|
||||||
class UserStatusLoginResponseV2(UserStatusLoginResponseV1):
|
class UserStatusLoginResponseV2(UserStatusLoginResponseV1):
|
||||||
vipInfo: VipInfo
|
|
||||||
lastLoginDate: int = 0
|
|
||||||
|
|
||||||
def __init__(self, is_first_login_daily: bool = False, last_login_date: int = 0) -> None:
|
def __init__(self, is_first_login_daily: bool = False, last_login_date: int = 0) -> None:
|
||||||
super().__init__(is_first_login_daily)
|
super().__init__(is_first_login_daily)
|
||||||
self.lastLoginDate = last_login_date
|
self.lastLoginDate = last_login_date
|
||||||
|
|
||||||
self.vipInfo = VipInfo()
|
self.vipInfo = VipInfo()
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self)-> Dict:
|
||||||
super().make()
|
super().make()
|
||||||
self.params.append(self.vipInfo.make())
|
self.params.append(self.vipInfo.make())
|
||||||
self.params.append(self.lastLoginDate)
|
self.params.append(self.lastLoginDate)
|
||||||
return super(UserStatusLoginResponseV1, self).make()
|
return super(UserStatusLoginResponseV1, self).make()
|
||||||
|
|
||||||
class UserStatusLoginResponseV3(UserStatusLoginResponseV2):
|
class UserStatusLoginResponseV3(UserStatusLoginResponseV2):
|
||||||
unk: List = []
|
def __init__(self, is_first_login_daily: bool = False, last_login_date: int = 0) -> None:
|
||||||
|
super().__init__(is_first_login_daily, last_login_date)
|
||||||
|
self.unk: List = []
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self)-> Dict:
|
||||||
super().make()
|
super().make()
|
||||||
self.params.append(self.unk)
|
self.params.append(self.unk)
|
||||||
return super(UserStatusLoginResponseV1, self).make()
|
return super(UserStatusLoginResponseV1, self).make()
|
||||||
@ -242,7 +242,7 @@ class UserStatusCreateResponseV1(BaseResponse):
|
|||||||
self.userStatus.userId = userId
|
self.userStatus.userId = userId
|
||||||
self.userStatus.username = username
|
self.userStatus.username = username
|
||||||
|
|
||||||
def make(self) -> List:
|
def make(self)-> Dict:
|
||||||
self.params = [
|
self.params = [
|
||||||
self.userStatus.make()
|
self.userStatus.make()
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
from titles.wacca.handlers.base import BaseRequest, BaseResponse
|
from titles.wacca.handlers.base import BaseRequest, BaseResponse
|
||||||
from titles.wacca.handlers.helpers import StageInfo, StageupClearType
|
from titles.wacca.handlers.helpers import StageInfo, StageupClearType, GenericItemRecv
|
||||||
|
|
||||||
# --user/trial/get--
|
# --user/trial/get--
|
||||||
class UserTrialGetRequest(BaseRequest):
|
class UserTrialGetRequest(BaseRequest):
|
||||||
@ -28,15 +28,18 @@ class UserTrialGetResponse(BaseResponse):
|
|||||||
class UserTrialUpdateRequest(BaseRequest):
|
class UserTrialUpdateRequest(BaseRequest):
|
||||||
def __init__(self, data: Dict) -> None:
|
def __init__(self, data: Dict) -> None:
|
||||||
super().__init__(data)
|
super().__init__(data)
|
||||||
self.profileId = self.params[0]
|
self.profileId: int = self.params[0]
|
||||||
self.stageId = self.params[1]
|
self.stageId: int = self.params[1]
|
||||||
self.stageLevel = self.params[2]
|
self.stageLevel: int = self.params[2]
|
||||||
self.clearType = StageupClearType(self.params[3])
|
self.clearType = StageupClearType(self.params[3])
|
||||||
self.songScores = self.params[4]
|
self.songScores: List[int] = self.params[4]
|
||||||
self.numSongsCleared = self.params[5]
|
self.numSongsCleared: int = self.params[5]
|
||||||
self.itemsObtained = self.params[6]
|
self.itemsObtained: List[GenericItemRecv] = []
|
||||||
self.unk7: List = []
|
self.unk7: List = []
|
||||||
|
|
||||||
|
for x in self.params[6]:
|
||||||
|
self.itemsObtained.append(GenericItemRecv(x[0], x[1], x[2]))
|
||||||
|
|
||||||
if len(self.params) == 8:
|
if len(self.params) == 8:
|
||||||
self.unk7 = self.params[7]
|
self.unk7 = self.params[7]
|
||||||
|
|
||||||
|
@ -35,8 +35,28 @@ class WaccaLily(WaccaS):
|
|||||||
(210002, 0),
|
(210002, 0),
|
||||||
(210003, 0),
|
(210003, 0),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def handle_advertise_GetNews_request(self, data: Dict)-> Dict:
|
||||||
|
resp = GetNewsResponseV3()
|
||||||
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_status_get_request(self, data: Dict) -> List[Any]:
|
def handle_housing_start_request(self, data: Dict) -> Dict:
|
||||||
|
req = HousingStartRequestV2(data)
|
||||||
|
|
||||||
|
resp = HousingStartResponseV1(
|
||||||
|
1,
|
||||||
|
[ # Recomended songs
|
||||||
|
1269,1007,1270,1002,1020,1003,1008,1211,1018,1092,1056,32,
|
||||||
|
1260,1230,1258,1251,2212,1264,1125,1037,2001,1272,1126,1119,
|
||||||
|
1104,1070,1047,1044,1027,1004,1001,24,2068,2062,2021,1275,
|
||||||
|
1249,1207,1203,1107,1021,1009,9,4,3,23,22,2014,13,1276,1247,
|
||||||
|
1240,1237,1128,1114,1110,1109,1102,1045,1043,1036,1035,1030,
|
||||||
|
1023,1015
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return resp.make()
|
||||||
|
|
||||||
|
def handle_user_status_get_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusGetRequest(data)
|
req = UserStatusGetRequest(data)
|
||||||
resp = UserStatusGetV2Response()
|
resp = UserStatusGetV2Response()
|
||||||
ver_split = req.appVersion.split(".")
|
ver_split = req.appVersion.split(".")
|
||||||
@ -115,7 +135,7 @@ class WaccaLily(WaccaS):
|
|||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_status_login_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_login_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusLoginRequest(data)
|
req = UserStatusLoginRequest(data)
|
||||||
resp = UserStatusLoginResponseV2()
|
resp = UserStatusLoginResponseV2()
|
||||||
is_new_day = False
|
is_new_day = False
|
||||||
@ -156,7 +176,7 @@ class WaccaLily(WaccaS):
|
|||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_status_getDetail_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_getDetail_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusGetDetailRequest(data)
|
req = UserStatusGetDetailRequest(data)
|
||||||
ver_split = req.appVersion.split(".")
|
ver_split = req.appVersion.split(".")
|
||||||
if int(ver_split[1]) >= 53:
|
if int(ver_split[1]) >= 53:
|
||||||
@ -255,13 +275,9 @@ class WaccaLily(WaccaS):
|
|||||||
for unlock in profile_song_unlocks:
|
for unlock in profile_song_unlocks:
|
||||||
for x in range(1, unlock["highest_difficulty"] + 1):
|
for x in range(1, unlock["highest_difficulty"] + 1):
|
||||||
resp.userItems.songUnlocks.append(SongUnlock(unlock["song_id"], x, 0, int(unlock["acquire_date"].timestamp())))
|
resp.userItems.songUnlocks.append(SongUnlock(unlock["song_id"], x, 0, int(unlock["acquire_date"].timestamp())))
|
||||||
if x > 2:
|
|
||||||
resp.scores.append(BestScoreDetailV1(unlock["song_id"], x))
|
|
||||||
|
|
||||||
empty_scores = len(resp.scores)
|
|
||||||
for song in profile_scores:
|
for song in profile_scores:
|
||||||
resp.seasonInfo.cumulativeScore += song["score"]
|
resp.seasonInfo.cumulativeScore += song["score"]
|
||||||
empty_score_idx = resp.find_score_idx(song["song_id"], song["chart_id"], 0, empty_scores)
|
|
||||||
|
|
||||||
clear_cts = SongDetailClearCounts(
|
clear_cts = SongDetailClearCounts(
|
||||||
song["play_ct"],
|
song["play_ct"],
|
||||||
@ -277,24 +293,16 @@ class WaccaLily(WaccaS):
|
|||||||
song["grade_master_ct"]
|
song["grade_master_ct"]
|
||||||
)
|
)
|
||||||
|
|
||||||
if empty_score_idx is not None:
|
deets = BestScoreDetailV1(song["song_id"], song["chart_id"])
|
||||||
resp.scores[empty_score_idx].clearCounts = clear_cts
|
deets.clearCounts = clear_cts
|
||||||
resp.scores[empty_score_idx].clearCountsSeason = clear_cts
|
deets.clearCountsSeason = clear_cts
|
||||||
resp.scores[empty_score_idx].gradeCounts = grade_cts
|
deets.gradeCounts = grade_cts
|
||||||
resp.scores[empty_score_idx].score = song["score"]
|
deets.score = song["score"]
|
||||||
resp.scores[empty_score_idx].bestCombo = song["best_combo"]
|
deets.bestCombo = song["best_combo"]
|
||||||
resp.scores[empty_score_idx].lowestMissCtMaybe = song["lowest_miss_ct"]
|
deets.lowestMissCtMaybe = song["lowest_miss_ct"]
|
||||||
resp.scores[empty_score_idx].rating = song["rating"]
|
deets.rating = song["rating"]
|
||||||
|
|
||||||
else:
|
resp.scores.append(deets)
|
||||||
deets = BestScoreDetailV1(song["song_id"], song["chart_id"])
|
|
||||||
deets.clearCounts = clear_cts
|
|
||||||
deets.clearCountsSeason = clear_cts
|
|
||||||
deets.gradeCounts = grade_cts
|
|
||||||
deets.score = song["score"]
|
|
||||||
deets.bestCombo = song["best_combo"]
|
|
||||||
deets.lowestMissCtMaybe = song["lowest_miss_ct"]
|
|
||||||
deets.rating = song["rating"]
|
|
||||||
|
|
||||||
for trophy in profile_trophies:
|
for trophy in profile_trophies:
|
||||||
resp.userItems.trophies.append(TrophyItem(trophy["trophy_id"], trophy["season"], trophy["progress"], trophy["badge_type"]))
|
resp.userItems.trophies.append(TrophyItem(trophy["trophy_id"], trophy["season"], trophy["progress"], trophy["badge_type"]))
|
||||||
@ -348,4 +356,14 @@ class WaccaLily(WaccaS):
|
|||||||
resp.seasonInfo.noteSoundsObtained = len(resp.userItems.noteSounds)
|
resp.seasonInfo.noteSoundsObtained = len(resp.userItems.noteSounds)
|
||||||
resp.seasonInfo.platesObtained = len(resp.userItems.plates)
|
resp.seasonInfo.platesObtained = len(resp.userItems.plates)
|
||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
|
def handle_user_info_getMyroom_request(self, data: Dict)-> Dict:
|
||||||
|
return UserInfogetMyroomResponseV2().make()
|
||||||
|
|
||||||
|
def handle_user_status_update_request(self, data: Dict)-> Dict:
|
||||||
|
super().handle_user_status_update_request(data)
|
||||||
|
req = UserStatusUpdateRequestV2(data)
|
||||||
|
self.data.profile.update_profile_lastplayed(req.profileId, req.lastSongInfo.lastSongId, req.lastSongInfo.lastSongDiff,
|
||||||
|
req.lastSongInfo.lastFolderOrd, req.lastSongInfo.lastFolderId, req.lastSongInfo.lastSongOrd)
|
||||||
|
return BaseResponse().make()
|
@ -35,7 +35,7 @@ class WaccaLilyR(WaccaLily):
|
|||||||
(210003, 0),
|
(210003, 0),
|
||||||
]
|
]
|
||||||
|
|
||||||
def handle_user_status_create_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_create_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusCreateRequest(data)
|
req = UserStatusCreateRequest(data)
|
||||||
resp = super().handle_user_status_create_request(data)
|
resp = super().handle_user_status_create_request(data)
|
||||||
|
|
||||||
@ -50,5 +50,5 @@ class WaccaLilyR(WaccaLily):
|
|||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def handle_user_status_logout_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_logout_request(self, data: Dict)-> Dict:
|
||||||
return BaseResponse().make()
|
return BaseResponse().make()
|
||||||
|
@ -46,12 +46,12 @@ class WaccaReverse(WaccaLilyR):
|
|||||||
(310006, 0),
|
(310006, 0),
|
||||||
]
|
]
|
||||||
|
|
||||||
def handle_user_status_login_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_login_request(self, data: Dict)-> Dict:
|
||||||
resp = super().handle_user_status_login_request(data)
|
resp = super().handle_user_status_login_request(data)
|
||||||
resp["params"].append([])
|
resp["params"].append([])
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def handle_user_status_getDetail_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_getDetail_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusGetDetailRequest(data)
|
req = UserStatusGetDetailRequest(data)
|
||||||
resp = UserStatusGetDetailResponseV4()
|
resp = UserStatusGetDetailResponseV4()
|
||||||
|
|
||||||
@ -148,13 +148,9 @@ class WaccaReverse(WaccaLilyR):
|
|||||||
for unlock in profile_song_unlocks:
|
for unlock in profile_song_unlocks:
|
||||||
for x in range(1, unlock["highest_difficulty"] + 1):
|
for x in range(1, unlock["highest_difficulty"] + 1):
|
||||||
resp.userItems.songUnlocks.append(SongUnlock(unlock["song_id"], x, 0, int(unlock["acquire_date"].timestamp())))
|
resp.userItems.songUnlocks.append(SongUnlock(unlock["song_id"], x, 0, int(unlock["acquire_date"].timestamp())))
|
||||||
if x > 2:
|
|
||||||
resp.scores.append(BestScoreDetailV2(unlock["song_id"], x))
|
|
||||||
|
|
||||||
empty_scores = len(resp.scores)
|
|
||||||
for song in profile_scores:
|
for song in profile_scores:
|
||||||
resp.seasonInfo.cumulativeScore += song["score"]
|
resp.seasonInfo.cumulativeScore += song["score"]
|
||||||
empty_score_idx = resp.find_score_idx(song["song_id"], song["chart_id"], 0, empty_scores)
|
|
||||||
|
|
||||||
clear_cts = SongDetailClearCounts(
|
clear_cts = SongDetailClearCounts(
|
||||||
song["play_ct"],
|
song["play_ct"],
|
||||||
@ -167,28 +163,19 @@ class WaccaReverse(WaccaLilyR):
|
|||||||
grade_cts = SongDetailGradeCountsV2(
|
grade_cts = SongDetailGradeCountsV2(
|
||||||
song["grade_d_ct"], song["grade_c_ct"], song["grade_b_ct"], song["grade_a_ct"], song["grade_aa_ct"],
|
song["grade_d_ct"], song["grade_c_ct"], song["grade_b_ct"], song["grade_a_ct"], song["grade_aa_ct"],
|
||||||
song["grade_aaa_ct"], song["grade_s_ct"], song["grade_ss_ct"], song["grade_sss_ct"],
|
song["grade_aaa_ct"], song["grade_s_ct"], song["grade_ss_ct"], song["grade_sss_ct"],
|
||||||
song["grade_master_ct"], song["grade_sp_ct"], song["grade_ssp_ct"], song["grade_sssp_ct"]
|
song["grade_master_ct"], song["grade_sp_ct"], song["grade_ssp_ct"], song["grade_sssp_ct"]
|
||||||
)
|
)
|
||||||
|
|
||||||
if empty_score_idx is not None:
|
deets = BestScoreDetailV2(song["song_id"], song["chart_id"])
|
||||||
resp.scores[empty_score_idx].clearCounts = clear_cts
|
deets.clearCounts = clear_cts
|
||||||
resp.scores[empty_score_idx].clearCountsSeason = clear_cts
|
deets.clearCountsSeason = clear_cts
|
||||||
resp.scores[empty_score_idx].gradeCounts = grade_cts
|
deets.gradeCounts = grade_cts
|
||||||
resp.scores[empty_score_idx].score = song["score"]
|
deets.score = song["score"]
|
||||||
resp.scores[empty_score_idx].bestCombo = song["best_combo"]
|
deets.bestCombo = song["best_combo"]
|
||||||
resp.scores[empty_score_idx].lowestMissCtMaybe = song["lowest_miss_ct"]
|
deets.lowestMissCtMaybe = song["lowest_miss_ct"]
|
||||||
resp.scores[empty_score_idx].rating = song["rating"]
|
deets.rating = song["rating"]
|
||||||
|
|
||||||
else:
|
resp.scores.append(deets)
|
||||||
deets = BestScoreDetailV2(song["song_id"], song["chart_id"])
|
|
||||||
deets.clearCounts = clear_cts
|
|
||||||
deets.clearCountsSeason = clear_cts
|
|
||||||
deets.gradeCounts = grade_cts
|
|
||||||
deets.score = song["score"]
|
|
||||||
deets.bestCombo = song["best_combo"]
|
|
||||||
deets.lowestMissCtMaybe = song["lowest_miss_ct"]
|
|
||||||
deets.rating = song["rating"]
|
|
||||||
resp.scores.append(deets)
|
|
||||||
|
|
||||||
for trophy in profile_trophies:
|
for trophy in profile_trophies:
|
||||||
resp.userItems.trophies.append(TrophyItem(trophy["trophy_id"], trophy["season"], trophy["progress"], trophy["badge_type"]))
|
resp.userItems.trophies.append(TrophyItem(trophy["trophy_id"], trophy["season"], trophy["progress"], trophy["badge_type"]))
|
||||||
@ -247,7 +234,7 @@ class WaccaReverse(WaccaLilyR):
|
|||||||
|
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
|
||||||
def handle_user_status_create_request(self, data: Dict) -> List[Any]:
|
def handle_user_status_create_request(self, data: Dict)-> Dict:
|
||||||
req = UserStatusCreateRequest(data)
|
req = UserStatusCreateRequest(data)
|
||||||
resp = super().handle_user_status_create_request(data)
|
resp = super().handle_user_status_create_request(data)
|
||||||
|
|
||||||
|
@ -30,6 +30,6 @@ class WaccaS(WaccaBase):
|
|||||||
super().__init__(cfg, game_cfg)
|
super().__init__(cfg, game_cfg)
|
||||||
self.version = WaccaConstants.VER_WACCA_S
|
self.version = WaccaConstants.VER_WACCA_S
|
||||||
|
|
||||||
def handle_advertise_GetNews_request(self, data: Dict) -> List[Any]:
|
def handle_advertise_GetNews_request(self, data: Dict) -> Dict:
|
||||||
resp = GetNewsResponseV2()
|
resp = GetNewsResponseV2()
|
||||||
return resp.make()
|
return resp.make()
|
||||||
|
Loading…
Reference in New Issue
Block a user