forked from Hay1tsme/artemis
1
0
Fork 0

Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop

This commit is contained in:
Hay1tsme 2024-04-02 16:43:16 -04:00
commit 926713431d
16 changed files with 407 additions and 22 deletions

View File

@ -0,0 +1,68 @@
"""mai2_buddies_support
Revision ID: 81e44dd6047a
Revises: d8950c7ce2fc
Create Date: 2024-03-12 19:10:37.063907
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = "81e44dd6047a"
down_revision = "6a7e8277763b"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"mai2_playlog_2p",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("user", sa.Integer(), nullable=False),
sa.Column("userId1", sa.Integer(), nullable=True),
sa.Column("userId2", sa.Integer(), nullable=True),
sa.Column("userName1", sa.String(length=25), nullable=True),
sa.Column("userName2", sa.String(length=25), nullable=True),
sa.Column("regionId", sa.Integer(), nullable=True),
sa.Column("placeId", sa.Integer(), nullable=True),
sa.Column("user2pPlaylogDetailList", sa.JSON(), nullable=True),
sa.ForeignKeyConstraint(
["user"], ["aime_user.id"], onupdate="cascade", ondelete="cascade"
),
sa.PrimaryKeyConstraint("id"),
mysql_charset="utf8mb4",
)
op.add_column(
"mai2_playlog",
sa.Column(
"extBool1", sa.Boolean(), nullable=True, server_default=sa.text("NULL")
),
)
op.add_column(
"mai2_profile_detail",
sa.Column(
"renameCredit", sa.Integer(), nullable=True, server_default=sa.text("NULL")
),
)
op.add_column(
"mai2_profile_detail",
sa.Column(
"currentPlayCount",
sa.Integer(),
nullable=True,
server_default=sa.text("NULL"),
),
)
def downgrade():
op.drop_table("mai2_playlog_2p")
op.drop_column("mai2_playlog", "extBool1")
op.drop_column("mai2_profile_detail", "renameCredit")
op.drop_column("mai2_profile_detail", "currentPlayCount")

View File

@ -94,7 +94,7 @@ class ArcadeData(BaseData):
return None return None
return result.fetchone() return result.fetchone()
async def put_machine( async def create_machine(
self, self,
arcade_id: int, arcade_id: int,
serial: str = "", serial: str = "",
@ -102,12 +102,12 @@ class ArcadeData(BaseData):
game: str = None, game: str = None,
is_cab: bool = False, is_cab: bool = False,
) -> Optional[int]: ) -> Optional[int]:
if arcade_id: if not arcade_id:
self.logger.error(f"{__name__ }: Need arcade id!") self.logger.error(f"{__name__ }: Need arcade id!")
return None return None
sql = machine.insert().values( sql = machine.insert().values(
arcade=arcade_id, keychip=serial, board=board, game=game, is_cab=is_cab arcade=arcade_id, serial=serial, board=board, game=game, is_cab=is_cab
) )
result = await self.execute(sql) result = await self.execute(sql)
@ -148,15 +148,15 @@ class ArcadeData(BaseData):
return None return None
return result.fetchall() return result.fetchall()
async def put_arcade( async def create_arcade(
self, self,
name: str, name: str = None,
nickname: str = None, nickname: str = None,
country: str = "JPN", country: str = "JPN",
country_id: int = 1, country_id: int = 1,
state: str = "", state: str = "",
city: str = "", city: str = "",
regional_id: int = 1, region_id: int = 1,
) -> Optional[int]: ) -> Optional[int]:
if nickname is None: if nickname is None:
nickname = name nickname = name
@ -168,7 +168,7 @@ class ArcadeData(BaseData):
country_id=country_id, country_id=country_id,
state=state, state=state,
city=city, city=city,
regional_id=regional_id, region_id=region_id,
) )
result = await self.execute(sql) result = await self.execute(sql)
@ -206,8 +206,8 @@ class ArcadeData(BaseData):
return None return None
return result.lastrowid return result.lastrowid
async def format_serial( def format_serial( # TODO: Actual serial stuff
self, platform_code: str, platform_rev: int, serial_num: int, append: int = 4152 self, platform_code: str, platform_rev: int, serial_num: int, append: int = 8888
) -> str: ) -> str:
return f"{platform_code}{platform_rev:02d}A{serial_num:04d}{append:04d}" # 0x41 = A, 0x52 = R return f"{platform_code}{platform_rev:02d}A{serial_num:04d}{append:04d}" # 0x41 = A, 0x52 = R

View File

@ -10,6 +10,9 @@ import bcrypt
import re import re
import jwt import jwt
import yaml import yaml
import secrets
import string
import random
from base64 import b64decode from base64 import b64decode
from enum import Enum from enum import Enum
from datetime import datetime, timezone from datetime import datetime, timezone
@ -131,6 +134,10 @@ class FrontendServlet():
Route("/", self.system.render_GET, methods=['GET']), Route("/", self.system.render_GET, methods=['GET']),
Route("/lookup.user", self.system.lookup_user, methods=['GET']), Route("/lookup.user", self.system.lookup_user, methods=['GET']),
Route("/lookup.shop", self.system.lookup_shop, methods=['GET']), Route("/lookup.shop", self.system.lookup_shop, methods=['GET']),
Route("/add.user", self.system.add_user, methods=['POST']),
Route("/add.card", self.system.add_card, methods=['POST']),
Route("/add.shop", self.system.add_shop, methods=['POST']),
Route("/add.cab", self.system.add_cab, methods=['POST']),
]), ]),
Mount("/shop", routes=[ Mount("/shop", routes=[
Route("/", self.arcade.render_GET, methods=['GET']), Route("/", self.arcade.render_GET, methods=['GET']),
@ -551,10 +558,16 @@ class FE_System(FE_Base):
if not usr_sesh or not self.test_perm_minimum(usr_sesh.permissions, PermissionOffset.USERMOD): if not usr_sesh or not self.test_perm_minimum(usr_sesh.permissions, PermissionOffset.USERMOD):
return RedirectResponse("/gate/", 303) return RedirectResponse("/gate/", 303)
if request.query_params.get("e", None):
err = int(request.query_params.get("e"))
else:
err = 0
return Response(template.render( return Response(template.render(
title=f"{self.core_config.server.name} | System", title=f"{self.core_config.server.name} | System",
sesh=vars(usr_sesh), sesh=vars(usr_sesh),
usrlist=[], usrlist=[],
error = err
), media_type="text/html; charset=utf-8") ), media_type="text/html; charset=utf-8")
async def lookup_user(self, request: Request): async def lookup_user(self, request: Request):
@ -661,6 +674,113 @@ class FE_System(FE_Base):
shoplist=shoplist, shoplist=shoplist,
), media_type="text/html; charset=utf-8") ), media_type="text/html; charset=utf-8")
async def add_user(self, request: Request):
template = self.environment.get_template("core/templates/sys/index.jinja")
usr_sesh = self.validate_session(request)
if not usr_sesh or not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
return RedirectResponse("/gate/", 303)
frm = await request.form()
username = frm.get("userName", None)
email = frm.get("userEmail", None)
perm = frm.get("usrPerm", "1")
passwd = "".join(
secrets.choice(string.ascii_letters + string.digits) for i in range(20)
)
hash = bcrypt.hashpw(passwd.encode(), bcrypt.gensalt())
if not email:
return RedirectResponse("/sys/?e=4", 303)
uid = await self.data.user.create_user(username=username if username else None, email=email, password=hash.decode(), permission=int(perm))
return Response(template.render(
title=f"{self.core_config.server.name} | System",
sesh=vars(usr_sesh),
usradd={"id": uid, "username": username, "password": passwd},
), media_type="text/html; charset=utf-8")
async def add_card(self, request: Request):
template = self.environment.get_template("core/templates/sys/index.jinja")
usr_sesh = self.validate_session(request)
if not usr_sesh or not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
return RedirectResponse("/gate/", 303)
frm = await request.form()
userid = frm.get("cardUsr", None)
access_code = frm.get("cardAc", None)
idm = frm.get("cardIdm", None)
if userid is None or access_code is None or not userid.isdigit() or not len(access_code) == 20 or not access_code.isdigit:
return RedirectResponse("/sys/?e=4", 303)
cardid = await self.data.card.create_card(int(userid), access_code)
if not cardid:
return RedirectResponse("/sys/?e=99", 303)
if idm is not None:
# TODO: save IDM
pass
return Response(template.render(
title=f"{self.core_config.server.name} | System",
sesh=vars(usr_sesh),
cardadd={"id": cardid, "user": userid, "access_code": access_code},
), media_type="text/html; charset=utf-8")
async def add_shop(self, request: Request):
template = self.environment.get_template("core/templates/sys/index.jinja")
usr_sesh = self.validate_session(request)
if not usr_sesh or not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
return RedirectResponse("/gate/", 303)
frm = await request.form()
name = frm.get("shopName", None)
country = frm.get("shopCountry", "JPN")
ip = frm.get("shopIp", None)
acid = await self.data.arcade.create_arcade(name if name else None, name if name else None, country)
if not acid:
return RedirectResponse("/sys/?e=99", 303)
if ip:
# TODO: set IP
pass
return Response(template.render(
title=f"{self.core_config.server.name} | System",
sesh=vars(usr_sesh),
shopadd={"id": acid},
), media_type="text/html; charset=utf-8")
async def add_cab(self, request: Request):
template = self.environment.get_template("core/templates/sys/index.jinja")
usr_sesh = self.validate_session(request)
if not usr_sesh or not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
return RedirectResponse("/gate/", 303)
frm = await request.form()
shopid = frm.get("cabShop", None)
serial = frm.get("cabSerial", None)
game_code = frm.get("cabGame", None)
if not shopid or not shopid.isdigit():
return RedirectResponse("/sys/?e=4", 303)
if not serial:
serial = self.data.arcade.format_serial("A69E", 1, random.randint(1, 9999))
cab_id = await self.data.arcade.create_machine(int(shopid), serial, None, game_code if game_code else None)
return Response(template.render(
title=f"{self.core_config.server.name} | System",
sesh=vars(usr_sesh),
cabadd={"id": cab_id, "serial": serial},
), media_type="text/html; charset=utf-8")
class FE_Arcade(FE_Base): class FE_Arcade(FE_Base):
async def render_GET(self, request: Request): async def render_GET(self, request: Request):
template = self.environment.get_template("core/templates/arcade/index.jinja") template = self.environment.get_template("core/templates/arcade/index.jinja")

View File

@ -10,7 +10,7 @@ Cab added successfully
{% endif %} {% endif %}
<ul style="font-size: 20px;"> <ul style="font-size: 20px;">
{% for c in arcade.cabs %} {% for c in arcade.cabs %}
<li><a href="/cab/{{ c.id }}">{{ c.serial }} ({{ c.game }})</a>&nbsp;<button class="btn btn-secondary" onclick="prep_edit_form()">Edit</button>&nbsp;<button class="btn-danger btn">Delete</button></li> <li><a href="/cab/{{ c.id }}">{{ c.serial }}</a> ({{ c.game if c.game else "Any" }})&nbsp;<button class="btn btn-secondary" onclick="prep_edit_form()">Edit</button>&nbsp;<button class="btn-danger btn">Delete</button></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}

View File

@ -4,6 +4,7 @@
{% if error is defined %} {% if error is defined %}
{% include "core/templates/widgets/err_banner.jinja" %} {% include "core/templates/widgets/err_banner.jinja" %}
{% endif %} {% endif %}
<h2>Search</h2>
<div class="row" id="rowForm"> <div class="row" id="rowForm">
{% if "{:08b}".format(sesh.permissions)[6] == "1" %} {% if "{:08b}".format(sesh.permissions)[6] == "1" %}
<div class="col-sm-6" style="max-width: 25%;"> <div class="col-sm-6" style="max-width: 25%;">
@ -21,7 +22,12 @@
OR OR
<div class="form-group"> <div class="form-group">
<label for="usrEmail">Email address</label> <label for="usrEmail">Email address</label>
<input type="email" class="form-control" id="usrEmail" name="usrEmail" aria-describedby="emailHelp"> <input type="email" class="form-control" id="usrEmail" name="usrEmail">
</div>
OR
<div class="form-group">
<label for="usrAc">Access Code</label>
<input type="text" class="form-control" id="usrAc" name="usrAc" maxlength="20" placeholder="00000000000000000000">
</div> </div>
<br /> <br />
<button type="submit" class="btn btn-primary">Search</button> <button type="submit" class="btn btn-primary">Search</button>
@ -63,7 +69,121 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<h2>Add</h2>
<div class="row" id="rowAdd"> <div class="row" id="rowAdd">
{% if "{:08b}".format(sesh.permissions)[6] == "1" %}
<div class="col-sm-6" style="max-width: 25%;">
<form id="usrAdd" name="usrAdd" action="/sys/add.user" class="form-inline" method="POST">
<h3>Add User</h3>
<div class="form-group">
<label for="usrName">Username</label>
<input type="text" class="form-control" id="usrName" name="usrName">
</div>
<br>
<div class="form-group">
<label for="usrEmail">Email address</label>
<input type="email" class="form-control" id="usrEmail" name="usrEmail" required>
</div>
<br>
<div class="form-group">
<label for="usrPerm">Permission Level</label>
<input type="number" class="form-control" id="usrPerm" name="usrPerm" value="1">
</div>
<br />
<button type="submit" class="btn btn-primary">Add</button>
</form>
</div>
<div class="col-sm-6" style="max-width: 25%;">
<form id="cardAdd" name="cardAdd" action="/sys/add.card" class="form-inline" method="POST">
<h3>Add Card</h3>
<div class="form-group">
<label for="cardUsr">User ID</label>
<input type="number" class="form-control" id="cardUsr" name="cardUsr" required>
</div>
<br>
<div class="form-group">
<label for="cardAc">Access Code</label>
<input type="text" class="form-control" id="cardAc" name="cardAc" maxlength="20" placeholder="00000000000000000000" required>
</div>
<br>
<div class="form-group">
<label for="cardIdm">IDm/Chip ID</label>
<input type="text" class="form-control" id="cardIdm" name="cardIdm" disabled>
</div>
<br />
<button type="submit" class="btn btn-primary">Add</button>
</form>
</div>
{% endif %}
{% if "{:08b}".format(sesh.permissions)[5] == "1" %}
<div class="col-sm-6" style="max-width: 25%;">
<form id="shopAdd" name="shopAdd" action="/sys/add.shop" class="form-inline" method="POST">
<h3>Add Shop</h3>
<div class="form-group">
<label for="shopName">Name</label>
<input type="text" class="form-control" id="shopName" name="shopName">
</div>
<br>
<div class="form-group">
<label for="shopCountry">Country Code</label>
<input type="text" class="form-control" id="shopCountry" name="shopCountry" maxlength="3" placeholder="JPN">
</div>
<br />
<div class="form-group">
<label for="shopIp">VPN IP</label>
<input type="text" class="form-control" id="shopIp" name="shopIp">
</div>
<br />
<button type="submit" class="btn btn-primary">Add</button>
</form>
</div>
<div class="col-sm-6" style="max-width: 25%;">
<form id="cabAdd" name="cabAdd" action="/sys/add.cab" class="form-inline" method="POST">
<h3>Add Machine</h3>
<div class="form-group">
<label for="cabShop">Shop ID</label>
<input type="number" class="form-control" id="cabShop" name="cabShop" required>
</div>
<br>
<div class="form-group">
<label for="cabSerial">Serial</label>
<input type="text" class="form-control" id="cabSerial" name="cabSerial">
</div>
<br />
<div class="form-group">
<label for="cabGame">Game Code</label>
<input type="text" class="form-control" id="cabGame" name="cabGame" maxlength="4" placeholder="SXXX">
</div>
<br />
<button type="submit" class="btn btn-primary">Add</button>
</form>
</div>
{% endif %}
</div>
<div class="row" id="rowAddResult" style="margin: 10px;">
{% if "{:08b}".format(sesh.permissions)[6] == "1" %}
<div id="userAddResult" class="col-sm-6" style="max-width: 25%;">
{% if usradd is defined %}
<pre>Added user {{ usradd.username if usradd.username is not none else "with no name"}} with id {{usradd.id}} and password {{ usradd.password }}</pre>
{% endif %}
</div>
<div id="cardAddResult" class="col-sm-6" style="max-width: 25%;">
{% if cardadd is defined %}
<pre>Added {{ cardadd.access_code }} with id {{cardadd.id}} to user {{ cardadd.user }}</pre>
{% endif %}
</div>
{% endif %}
{% if "{:08b}".format(sesh.permissions)[5] == "1" %}
<div id="shopAddResult" class="col-sm-6" style="max-width: 25%;">
{% if shopadd is defined %}
<pre>Added Shop {{ shopadd.id }}</pre></a>
{% endif %}
</div>
<div id="cabAddResult" class="col-sm-6" style="max-width: 25%;">
{% if cabadd is defined %}
<pre>Added Machine {{ cabadd.id }} with serial {{ cabadd.serial }}</pre></a>
{% endif %}
</div>
{% endif %}
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -34,7 +34,8 @@ class Utils:
@classmethod @classmethod
def get_ip_addr(cls, req: Request) -> str: def get_ip_addr(cls, req: Request) -> str:
return req.headers.get("x-forwarded-for", req.client.host) ip = req.headers.get("x-forwarded-for", req.client.host)
return ip.split(", ")[0]
@classmethod @classmethod
def get_title_port(cls, cfg: CoreConfig): def get_title_port(cls, cfg: CoreConfig):

View File

@ -192,6 +192,7 @@ Config file is located in `config/cxb.yaml`.
| SDEZ | 18 | maimai DX UNiVERSE PLUS | | SDEZ | 18 | maimai DX UNiVERSE PLUS |
| SDEZ | 19 | maimai DX FESTiVAL | | SDEZ | 19 | maimai DX FESTiVAL |
| SDEZ | 20 | maimai DX FESTiVAL PLUS | | SDEZ | 20 | maimai DX FESTiVAL PLUS |
| SDEZ | 21 | maimai DX BUDDiES |
### Importer ### Importer
@ -406,6 +407,7 @@ After that, on next login the present should be received (or whenever it suppose
* UNiVERSE PLUS: Yes * UNiVERSE PLUS: Yes
* FESTiVAL: Yes (added in A031) * FESTiVAL: Yes (added in A031)
* FESTiVAL PLUS: Yes (added in A035) * FESTiVAL PLUS: Yes (added in A035)
* BUDDiES: Yes (added in A039)
* O.N.G.E.K.I. bright MEMORY: Yes * O.N.G.E.K.I. bright MEMORY: Yes

View File

@ -47,6 +47,7 @@ Games listed below have been tested and confirmed working. Only game versions ol
+ UNiVERSE PLUS + UNiVERSE PLUS
+ FESTiVAL + FESTiVAL
+ FESTiVAL PLUS + FESTiVAL PLUS
+ BUDDiES
+ O.N.G.E.K.I. + O.N.G.E.K.I.
+ SUMMER + SUMMER

View File

@ -206,6 +206,7 @@ class CardMakerReader(BaseReader):
"1.25": Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS, "1.25": Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS,
"1.30": Mai2Constants.VER_MAIMAI_DX_FESTIVAL, "1.30": Mai2Constants.VER_MAIMAI_DX_FESTIVAL,
"1.35": Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS, "1.35": Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS,
"1.40": Mai2Constants.VER_MAIMAI_DX_BUDDIES,
} }
for root, dirs, files in os.walk(base_dir): for root, dirs, files in os.walk(base_dir):
@ -225,12 +226,6 @@ class CardMakerReader(BaseReader):
True if troot.find("disable").text == "false" else False True if troot.find("disable").text == "false" else False
) )
# check if a date is part of the name and disable the
# card if it is
enabled = (
False if re.search(r"\d{2}/\d{2}/\d{2}", name) else enabled
)
await self.mai2_data.static.put_card( await self.mai2_data.static.put_card(
version, card_id, name, enabled=enabled version, card_id, name, enabled=enabled
) )

32
titles/mai2/buddies.py Normal file
View File

@ -0,0 +1,32 @@
from typing import Dict
from core.config import CoreConfig
from titles.mai2.festivalplus import Mai2FestivalPlus
from titles.mai2.const import Mai2Constants
from titles.mai2.config import Mai2Config
class Mai2Buddies(Mai2FestivalPlus):
def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None:
super().__init__(cfg, game_cfg)
self.version = Mai2Constants.VER_MAIMAI_DX_BUDDIES
async def handle_cm_get_user_preview_api_request(self, data: Dict) -> Dict:
user_data = await super().handle_cm_get_user_preview_api_request(data)
# hardcode lastDataVersion for CardMaker
user_data["lastDataVersion"] = "1.40.00"
return user_data
async def handle_get_user_new_item_api_request(self, data: Dict) -> Dict:
# TODO: Added in 1.41, implement this?
user_id = data["userId"]
version = data.get("version", 1041000)
user_playlog_list = data.get("userPlaylogList", [])
return {
"userId": user_id,
"itemKind": -1,
"itemId": -1,
}

View File

@ -53,6 +53,7 @@ class Mai2Constants:
VER_MAIMAI_DX_UNIVERSE_PLUS = 18 VER_MAIMAI_DX_UNIVERSE_PLUS = 18
VER_MAIMAI_DX_FESTIVAL = 19 VER_MAIMAI_DX_FESTIVAL = 19
VER_MAIMAI_DX_FESTIVAL_PLUS = 20 VER_MAIMAI_DX_FESTIVAL_PLUS = 20
VER_MAIMAI_DX_BUDDIES = 21
VERSION_STRING = ( VERSION_STRING = (
"maimai", "maimai",
@ -76,6 +77,7 @@ class Mai2Constants:
"maimai DX UNiVERSE PLUS", "maimai DX UNiVERSE PLUS",
"maimai DX FESTiVAL", "maimai DX FESTiVAL",
"maimai DX FESTiVAL PLUS", "maimai DX FESTiVAL PLUS",
"maimai DX BUDDiES"
) )
@classmethod @classmethod

View File

@ -212,6 +212,9 @@ class Mai2DX(Mai2Base):
), ),
) )
await self.data.item.put_friend_season_ranking(user_id, fsr) await self.data.item.put_friend_season_ranking(user_id, fsr)
if "user2pPlaylog" in upsert:
await self.data.score.put_playlog_2p(user_id, upsert["user2pPlaylog"])
return {"returnCode": 1, "apiName": "UpsertUserAllApi"} return {"returnCode": 1, "apiName": "UpsertUserAllApi"}

View File

@ -25,6 +25,7 @@ from .universe import Mai2Universe
from .universeplus import Mai2UniversePlus from .universeplus import Mai2UniversePlus
from .festival import Mai2Festival from .festival import Mai2Festival
from .festivalplus import Mai2FestivalPlus from .festivalplus import Mai2FestivalPlus
from .buddies import Mai2Buddies
class Mai2Servlet(BaseServlet): class Mai2Servlet(BaseServlet):
@ -58,6 +59,7 @@ class Mai2Servlet(BaseServlet):
Mai2UniversePlus, Mai2UniversePlus,
Mai2Festival, Mai2Festival,
Mai2FestivalPlus, Mai2FestivalPlus,
Mai2Buddies
] ]
self.logger = logging.getLogger("mai2") self.logger = logging.getLogger("mai2")
@ -257,8 +259,10 @@ class Mai2Servlet(BaseServlet):
internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS
elif version >= 130 and version < 135: # FESTiVAL elif version >= 130 and version < 135: # FESTiVAL
internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL
elif version >= 135: # FESTiVAL PLUS elif version >= 135 and version < 140: # FESTiVAL PLUS
internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS
elif version >= 140: # BUDDiES
internal_ver = Mai2Constants.VER_MAIMAI_DX_BUDDIES
if ( if (
request.headers.get("Mai-Encoding") is not None request.headers.get("Mai-Encoding") is not None

View File

@ -40,6 +40,8 @@ detail = Table(
Column("charaLockSlot", JSON), Column("charaLockSlot", JSON),
Column("contentBit", BigInteger), Column("contentBit", BigInteger),
Column("playCount", Integer), Column("playCount", Integer),
Column("currentPlayCount", Integer), # new with buddies
Column("renameCredit", Integer), # new with buddies
Column("mapStock", Integer), # new with fes+ Column("mapStock", Integer), # new with fes+
Column("eventWatchedDate", String(25)), Column("eventWatchedDate", String(25)),
Column("lastGameId", String(25)), Column("lastGameId", String(25)),

View File

@ -145,11 +145,34 @@ playlog = Table(
Column("isNewFree", Boolean), Column("isNewFree", Boolean),
Column("extNum1", Integer), Column("extNum1", Integer),
Column("extNum2", Integer), Column("extNum2", Integer),
Column("extNum4", Integer, server_default="0"), Column("extNum4", Integer),
Column("extBool1", Boolean), # new with buddies
Column("trialPlayAchievement", Integer), Column("trialPlayAchievement", Integer),
mysql_charset="utf8mb4", mysql_charset="utf8mb4",
) )
# new with buddies
playlog_2p = Table(
"mai2_playlog_2p",
metadata,
Column("id", Integer, primary_key=True, nullable=False),
Column(
"user",
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
nullable=False,
),
# TODO: ForeignKey to aime_user?
Column("userId1", Integer),
Column("userId2", Integer),
# TODO: ForeignKey to mai2_profile_detail?
Column("userName1", String(25)),
Column("userName2", String(25)),
Column("regionId", Integer),
Column("placeId", Integer),
Column("user2pPlaylogDetailList", JSON),
mysql_charset="utf8mb4",
)
course = Table( course = Table(
"mai2_score_course", "mai2_score_course",
metadata, metadata,
@ -343,6 +366,18 @@ class Mai2ScoreData(BaseData):
self.logger.error(f"put_playlog: Failed to insert! user_id {user_id} is_dx {is_dx}") self.logger.error(f"put_playlog: Failed to insert! user_id {user_id} is_dx {is_dx}")
return None return None
return result.lastrowid return result.lastrowid
async def put_playlog_2p(self, user_id: int, playlog_2p_data: Dict) -> Optional[int]:
playlog_2p_data["user"] = user_id
sql = insert(playlog_2p).values(**playlog_2p_data)
conflict = sql.on_duplicate_key_update(**playlog_2p_data)
result = await self.execute(conflict)
if result is None:
self.logger.error(f"put_playlog_2p: Failed to insert! user_id {user_id}")
return None
return result.lastrowid
async def put_course(self, user_id: int, course_data: Dict) -> Optional[int]: async def put_course(self, user_id: int, course_data: Dict) -> Optional[int]:
course_data["user"] = user_id course_data["user"] = user_id

View File

@ -44,7 +44,7 @@ class OngekiFrontend(FE_Base):
self.version = usr_sesh.ongeki_version self.version = usr_sesh.ongeki_version
if usr_sesh.user_id > 0: if usr_sesh.user_id > 0:
profile_data =self.data.profile.get_profile_data(usr_sesh.user_id, self.version) profile_data =await self.data.profile.get_profile_data(usr_sesh.user_id, self.version)
rival_list = await self.data.profile.get_rivals(usr_sesh.user_id) rival_list = await self.data.profile.get_rivals(usr_sesh.user_id)
rival_data = { rival_data = {
"userRivalList": rival_list, "userRivalList": rival_list,