Merge branch 'develop' into fork_develop

This commit is contained in:
Dniel97 2023-05-10 12:49:01 +02:00
commit 0ab539173a
Signed by untrusted user: Dniel97
GPG Key ID: 6180B3C768FB2E08
13 changed files with 228 additions and 29 deletions

21
Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM python:3.9.15-slim-bullseye
RUN apt update && apt install default-libmysqlclient-dev build-essential libtk nodejs npm -y
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
RUN npm i -g nodemon
COPY entrypoint.sh entrypoint.sh
RUN chmod +x entrypoint.sh
COPY index.py index.py
COPY dbutils.py dbutils.py
ADD core core
ADD titles titles
ADD config config
ADD log log
ADD cert cert
ENTRYPOINT [ "/app/entrypoint.sh" ]

View File

@ -249,14 +249,18 @@ class AllnetServlet:
signer = PKCS1_v1_5.new(rsa) signer = PKCS1_v1_5.new(rsa)
digest = SHA.new() digest = SHA.new()
kc_playlimit = int(req_dict[0]["playlimit"]) try:
kc_nearfull = int(req_dict[0]["nearfull"]) kc_playlimit = int(req_dict[0]["playlimit"])
kc_billigtype = int(req_dict[0]["billingtype"]) kc_nearfull = int(req_dict[0]["nearfull"])
kc_playcount = int(req_dict[0]["playcnt"]) kc_billigtype = int(req_dict[0]["billingtype"])
kc_serial: str = req_dict[0]["keychipid"] kc_playcount = int(req_dict[0]["playcnt"])
kc_game: str = req_dict[0]["gameid"] kc_serial: str = req_dict[0]["keychipid"]
kc_date = strptime(req_dict[0]["date"], "%Y%m%d%H%M%S") kc_game: str = req_dict[0]["gameid"]
kc_serial_bytes = kc_serial.encode() kc_date = strptime(req_dict[0]["date"], "%Y%m%d%H%M%S")
kc_serial_bytes = kc_serial.encode()
except KeyError as e:
return f"result=5&linelimit=&message={e} field is missing".encode()
machine = self.data.arcade.get_machine(kc_serial) machine = self.data.arcade.get_machine(kc_serial)
if machine is None and not self.config.server.allow_unregistered_serials: if machine is None and not self.config.server.allow_unregistered_serials:

View File

@ -0,0 +1,9 @@
ALTER TABLE diva_profile
DROP cnp_cid,
DROP cnp_val,
DROP cnp_rr,
DROP cnp_sp,
DROP btn_se_eqp,
DROP sld_se_eqp,
DROP chn_sld_se_eqp,
DROP sldr_tch_se_eqp;

View File

@ -0,0 +1,9 @@
ALTER TABLE diva_profile
ADD cnp_cid INT NOT NULL DEFAULT -1,
ADD cnp_val INT NOT NULL DEFAULT -1,
ADD cnp_rr INT NOT NULL DEFAULT -1,
ADD cnp_sp VARCHAR(255) NOT NULL DEFAULT "",
ADD btn_se_eqp INT NOT NULL DEFAULT -1,
ADD sld_se_eqp INT NOT NULL DEFAULT -1,
ADD chn_sld_se_eqp INT NOT NULL DEFAULT -1,
ADD sldr_tch_se_eqp INT NOT NULL DEFAULT -1;

57
docker-compose.yml Normal file
View File

@ -0,0 +1,57 @@
version: "3.9"
services:
app:
hostname: ma.app
build: .
volumes:
- ./aime:/app/aime
environment:
CFG_DEV: 1
CFG_CORE_SERVER_HOSTNAME: 0.0.0.0
CFG_CORE_DATABASE_HOST: ma.db
CFG_CORE_MEMCACHED_HOSTNAME: ma.memcached
CFG_CORE_AIMEDB_KEY: keyhere
CFG_CHUNI_SERVER_LOGLEVEL: debug
ports:
- "80:80"
- "8443:8443"
- "22345:22345"
- "8080:8080"
- "8090:8090"
depends_on:
db:
condition: service_healthy
db:
hostname: ma.db
image: mysql:8.0.31-debian
environment:
MYSQL_DATABASE: aime
MYSQL_USER: aime
MYSQL_PASSWORD: aime
MYSQL_ROOT_PASSWORD: AimeRootPassword
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 5s
retries: 5
memcached:
hostname: ma.memcached
image: memcached:1.6.17-bullseye
phpmyadmin:
hostname: ma.phpmyadmin
image: phpmyadmin:latest
environment:
PMA_HOSTS: ma.db
PMA_USER: root
PMA_PASSWORD: AimeRootPassword
APACHE_PORT: 8080
ports:
- "8080:8080"

11
entrypoint.sh Normal file
View File

@ -0,0 +1,11 @@
#!/bin/bash
if [[ -z "${CFG_DEV}" ]]; then
echo Production mode
python3 index.py
else
echo Development mode
python3 dbutils.py create
nodemon -w aime --legacy-watch index.py
fi

View File

@ -42,7 +42,7 @@ class HttpDispatcher(resource.Resource):
conditions=dict(method=["POST"]), conditions=dict(method=["POST"]),
) )
self.map_post.connect( self.map_get.connect(
"allnet_ping", "allnet_ping",
"/naomitest.html", "/naomitest.html",
controller="allnet", controller="allnet",

View File

@ -7,4 +7,4 @@ index = DivaServlet
database = DivaData database = DivaData
reader = DivaReader reader = DivaReader
game_codes = [DivaConstants.GAME_CODE] game_codes = [DivaConstants.GAME_CODE]
current_schema_version = 4 current_schema_version = 5

View File

@ -266,16 +266,17 @@ class DivaBase:
def handle_festa_info_request(self, data: Dict) -> Dict: def handle_festa_info_request(self, data: Dict) -> Dict:
encoded = "&" encoded = "&"
params = { params = {
"fi_id": "1,-1", "fi_id": "1,2",
"fi_name": f"{self.core_cfg.server.name} Opening,xxx", "fi_name": f"{self.core_cfg.server.name} Opening,Project DIVA Festa",
"fi_kind": "0,0", # 0=PINK, 1=GREEN
"fi_kind": "1,0",
"fi_difficulty": "-1,-1", "fi_difficulty": "-1,-1",
"fi_pv_id_lst": "ALL,ALL", "fi_pv_id_lst": "ALL,ALL",
"fi_attr": "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "fi_attr": "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
"fi_add_vp": "20,0", "fi_add_vp": "20,5",
"fi_mul_vp": "1,1", "fi_mul_vp": "1,2",
"fi_st": "2022-06-17 17:00:00.0,2014-07-08 18:10:11.0", "fi_st": "2019-01-01 00:00:00.0,2019-01-01 00:00:00.0",
"fi_et": "2029-01-01 10:00:00.0,2014-07-08 18:10:11.0", "fi_et": "2029-01-01 00:00:00.0,2029-01-01 00:00:00.0",
"fi_lut": "{self.time_lut}", "fi_lut": "{self.time_lut}",
} }
@ -401,10 +402,10 @@ class DivaBase:
response += f"&lv_pnt={profile['lv_pnt']}" response += f"&lv_pnt={profile['lv_pnt']}"
response += f"&vcld_pts={profile['vcld_pts']}" response += f"&vcld_pts={profile['vcld_pts']}"
response += f"&skn_eqp={profile['use_pv_skn_eqp']}" response += f"&skn_eqp={profile['use_pv_skn_eqp']}"
response += f"&btn_se_eqp={profile['use_pv_btn_se_eqp']}" response += f"&btn_se_eqp={profile['btn_se_eqp']}"
response += f"&sld_se_eqp={profile['use_pv_sld_se_eqp']}" response += f"&sld_se_eqp={profile['sld_se_eqp']}"
response += f"&chn_sld_se_eqp={profile['use_pv_chn_sld_se_eqp']}" response += f"&chn_sld_se_eqp={profile['chn_sld_se_eqp']}"
response += f"&sldr_tch_se_eqp={profile['use_pv_sldr_tch_se_eqp']}" response += f"&sldr_tch_se_eqp={profile['sldr_tch_se_eqp']}"
response += f"&passwd_stat={profile['passwd_stat']}" response += f"&passwd_stat={profile['passwd_stat']}"
# Store stuff to add to rework # Store stuff to add to rework
@ -478,6 +479,21 @@ class DivaBase:
response += f"&dsp_clr_sts={profile['dsp_clr_sts']}" response += f"&dsp_clr_sts={profile['dsp_clr_sts']}"
response += f"&rgo_sts={profile['rgo_sts']}" response += f"&rgo_sts={profile['rgo_sts']}"
# Contest progress
response += f"&cv_cid=-1,-1,-1,-1"
response += f"&cv_sc=-1,-1,-1,-1"
response += f"&cv_bv=-1,-1,-1,-1"
response += f"&cv_bv=-1,-1,-1,-1"
response += f"&cv_bf=-1,-1,-1,-1"
# Contest now playing id, return -1 if no current playing contest
response += f"&cnp_cid={profile['cnp_cid']}"
response += f"&cnp_val={profile['cnp_val']}"
# border can be 0=bronzem 1=silver, 2=gold
response += f"&cnp_rr={profile['cnp_rr']}"
# only show contest specifier if it is not empty
response += f"&cnp_sp={profile['cnp_sp']}" if profile["cnp_sp"] != "" else ""
# To be fully fixed # To be fully fixed
if "my_qst_id" not in profile: if "my_qst_id" not in profile:
response += f"&my_qst_id=-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" response += f"&my_qst_id=-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
@ -488,7 +504,63 @@ class DivaBase:
response += f"&my_qst_prgrs=0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" response += f"&my_qst_prgrs=0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
response += f"&my_qst_et=2022-06-19%2010%3A28%3A52.0,2022-06-19%2010%3A28%3A52.0,2022-06-19%2010%3A28%3A52.0,2100-01-01%2008%3A59%3A59.0,2100-01-01%2008%3A59%3A59.0,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx" response += f"&my_qst_et=2022-06-19%2010%3A28%3A52.0,2022-06-19%2010%3A28%3A52.0,2022-06-19%2010%3A28%3A52.0,2100-01-01%2008%3A59%3A59.0,2100-01-01%2008%3A59%3A59.0,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx,xxx"
response += f"&clr_sts=0,0,0,0,0,0,0,0,56,52,35,6,6,3,1,0,0,0,0,0"
# define a helper class to store all counts for clear, great,
# excellent and perfect
class ClearSet:
def __init__(self):
self.clear = 0
self.great = 0
self.excellent = 0
self.perfect = 0
# create a dict to store the ClearSets per difficulty
clear_set_dict = {
0: ClearSet(), # easy
1: ClearSet(), # normal
2: ClearSet(), # hard
3: ClearSet(), # extreme
4: ClearSet(), # exExtreme
}
# get clear status from user scores
pv_records = self.data.score.get_best_scores(data["pd_id"])
clear_status = "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
if pv_records is not None:
for score in pv_records:
if score["edition"] == 0:
# cheap and standard both count to "clear"
if score["clr_kind"] in {1, 2}:
clear_set_dict[score["difficulty"]].clear += 1
elif score["clr_kind"] == 3:
clear_set_dict[score["difficulty"]].great += 1
elif score["clr_kind"] == 4:
clear_set_dict[score["difficulty"]].excellent += 1
elif score["clr_kind"] == 5:
clear_set_dict[score["difficulty"]].perfect += 1
else:
# 4=ExExtreme
if score["clr_kind"] in {1, 2}:
clear_set_dict[4].clear += 1
elif score["clr_kind"] == 3:
clear_set_dict[4].great += 1
elif score["clr_kind"] == 4:
clear_set_dict[4].excellent += 1
elif score["clr_kind"] == 5:
clear_set_dict[4].perfect += 1
# now add all values to a list
clear_list = []
for clear_set in clear_set_dict.values():
clear_list.append(clear_set.clear)
clear_list.append(clear_set.great)
clear_list.append(clear_set.excellent)
clear_list.append(clear_set.perfect)
clear_status = ",".join(map(str, clear_list))
response += f"&clr_sts={clear_status}"
# Store stuff to add to rework # Store stuff to add to rework
response += f"&mdl_eqp_tm={self.time_lut}" response += f"&mdl_eqp_tm={self.time_lut}"

View File

@ -34,9 +34,17 @@ profile = Table(
Column("use_pv_sld_se_eqp", Boolean, nullable=False, server_default="0"), Column("use_pv_sld_se_eqp", Boolean, nullable=False, server_default="0"),
Column("use_pv_chn_sld_se_eqp", Boolean, nullable=False, server_default="0"), Column("use_pv_chn_sld_se_eqp", Boolean, nullable=False, server_default="0"),
Column("use_pv_sldr_tch_se_eqp", Boolean, nullable=False, server_default="0"), Column("use_pv_sldr_tch_se_eqp", Boolean, nullable=False, server_default="0"),
Column("btn_se_eqp", Integer, nullable=False, server_default="-1"),
Column("sld_se_eqp", Integer, nullable=False, server_default="-1"),
Column("chn_sld_se_eqp", Integer, nullable=False, server_default="-1"),
Column("sldr_tch_se_eqp", Integer, nullable=False, server_default="-1"),
Column("nxt_pv_id", Integer, nullable=False, server_default="708"), Column("nxt_pv_id", Integer, nullable=False, server_default="708"),
Column("nxt_dffclty", Integer, nullable=False, server_default="2"), Column("nxt_dffclty", Integer, nullable=False, server_default="2"),
Column("nxt_edtn", Integer, nullable=False, server_default="0"), Column("nxt_edtn", Integer, nullable=False, server_default="0"),
Column("cnp_cid", Integer, nullable=False, server_default="-1"),
Column("cnp_val", Integer, nullable=False, server_default="-1"),
Column("cnp_rr", Integer, nullable=False, server_default="-1"),
Column("cnp_sp", String(255), nullable=False, server_default=""),
Column("dsp_clr_brdr", Integer, nullable=False, server_default="7"), Column("dsp_clr_brdr", Integer, nullable=False, server_default="7"),
Column("dsp_intrm_rnk", Integer, nullable=False, server_default="1"), Column("dsp_intrm_rnk", Integer, nullable=False, server_default="1"),
Column("dsp_clr_sts", Integer, nullable=False, server_default="1"), Column("dsp_clr_sts", Integer, nullable=False, server_default="1"),

View File

@ -3,6 +3,7 @@ from sqlalchemy.types import Integer, String, TIMESTAMP, JSON, Boolean
from sqlalchemy.schema import ForeignKey from sqlalchemy.schema import ForeignKey
from sqlalchemy.sql import func, select from sqlalchemy.sql import func, select
from sqlalchemy.dialects.mysql import insert from sqlalchemy.dialects.mysql import insert
from sqlalchemy.engine import Row
from typing import Optional, List, Dict, Any from typing import Optional, List, Dict, Any
from core.data.schema import BaseData, metadata from core.data.schema import BaseData, metadata
@ -167,7 +168,7 @@ class DivaScoreData(BaseData):
def get_best_user_score( def get_best_user_score(
self, user_id: int, pv_id: int, difficulty: int, edition: int self, user_id: int, pv_id: int, difficulty: int, edition: int
) -> Optional[Dict]: ) -> Optional[Row]:
sql = score.select( sql = score.select(
and_( and_(
score.c.user == user_id, score.c.user == user_id,
@ -184,7 +185,7 @@ class DivaScoreData(BaseData):
def get_top3_scores( def get_top3_scores(
self, pv_id: int, difficulty: int, edition: int self, pv_id: int, difficulty: int, edition: int
) -> Optional[List[Dict]]: ) -> Optional[List[Row]]:
sql = ( sql = (
score.select( score.select(
and_( and_(
@ -204,7 +205,7 @@ class DivaScoreData(BaseData):
def get_global_ranking( def get_global_ranking(
self, user_id: int, pv_id: int, difficulty: int, edition: int self, user_id: int, pv_id: int, difficulty: int, edition: int
) -> Optional[List]: ) -> Optional[List[Row]]:
# get the subquery max score of a user with pv_id, difficulty and # get the subquery max score of a user with pv_id, difficulty and
# edition # edition
sql_sub = ( sql_sub = (
@ -231,7 +232,7 @@ class DivaScoreData(BaseData):
return None return None
return result.fetchone() return result.fetchone()
def get_best_scores(self, user_id: int) -> Optional[List]: def get_best_scores(self, user_id: int) -> Optional[List[Row]]:
sql = score.select(score.c.user == user_id) sql = score.select(score.c.user == user_id)
result = self.execute(sql) result = self.execute(sql)

View File

@ -16,8 +16,15 @@ class Mai2Base:
self.version = Mai2Constants.VER_MAIMAI_DX self.version = Mai2Constants.VER_MAIMAI_DX
self.data = Mai2Data(cfg) self.data = Mai2Data(cfg)
self.logger = logging.getLogger("mai2") self.logger = logging.getLogger("mai2")
if self.core_config.server.is_develop and self.core_config.title.port > 0:
self.old_server = f"http://{self.core_config.title.hostname}:{self.core_config.title.port}/SDEY/100/"
else:
self.old_server = f"http://{self.core_config.title.hostname}/SDEY/100/"
def handle_get_game_setting_api_request(self, data: Dict): def handle_get_game_setting_api_request(self, data: Dict):
# TODO: See if making this epoch 0 breaks things
reboot_start = date.strftime( reboot_start = date.strftime(
datetime.now() + timedelta(hours=3), Mai2Constants.DATE_TIME_FORMAT datetime.now() + timedelta(hours=3), Mai2Constants.DATE_TIME_FORMAT
) )
@ -34,7 +41,7 @@ class Mai2Base:
"movieStatus": 0, "movieStatus": 0,
"movieServerUri": "", "movieServerUri": "",
"deliverServerUri": "", "deliverServerUri": "",
"oldServerUri": "", "oldServerUri": self.old_server,
"usbDlServerUri": "", "usbDlServerUri": "",
"rebootInterval": 0, "rebootInterval": 0,
}, },

View File

@ -82,13 +82,13 @@ class Mai2Servlet:
return ( return (
True, True,
f"http://{core_cfg.title.hostname}:{core_cfg.title.port}/{game_code}/$v/", f"http://{core_cfg.title.hostname}:{core_cfg.title.port}/{game_code}/$v/",
f"{core_cfg.title.hostname}:{core_cfg.title.port}/", f"{core_cfg.title.hostname}:{core_cfg.title.port}",
) )
return ( return (
True, True,
f"http://{core_cfg.title.hostname}/{game_code}/$v/", f"http://{core_cfg.title.hostname}/{game_code}/$v/",
f"{core_cfg.title.hostname}/", f"{core_cfg.title.hostname}",
) )
def render_POST(self, request: Request, version: int, url_path: str) -> bytes: def render_POST(self, request: Request, version: int, url_path: str) -> bytes: