mai2: add present support
This commit is contained in:
parent
fef527d61f
commit
4446ff1f21
41
core/data/alembic/versions/5ea363686347_mai2_presents.py
Normal file
41
core/data/alembic/versions/5ea363686347_mai2_presents.py
Normal file
@ -0,0 +1,41 @@
|
||||
"""mai2_presents
|
||||
|
||||
Revision ID: 5ea363686347
|
||||
Revises: 680789dabab3
|
||||
Create Date: 2024-06-28 14:49:07.666879
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '5ea363686347'
|
||||
down_revision = '680789dabab3'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('mai2_item_present',
|
||||
sa.Column('id', sa.BIGINT(), nullable=False),
|
||||
sa.Column('version', sa.INTEGER(), nullable=True),
|
||||
sa.Column('user', sa.Integer(), nullable=True),
|
||||
sa.Column('itemKind', sa.INTEGER(), nullable=False),
|
||||
sa.Column('itemId', sa.INTEGER(), nullable=False),
|
||||
sa.Column('stock', sa.INTEGER(), server_default='1', nullable=False),
|
||||
sa.Column('startDate', sa.TIMESTAMP(), nullable=True),
|
||||
sa.Column('endDate', sa.TIMESTAMP(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['user'], ['aime_user.id'], onupdate='cascade', ondelete='cascade'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('version', 'user', 'itemKind', 'itemId', name='mai2_item_present_uk'),
|
||||
mysql_charset='utf8mb4'
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('mai2_item_present')
|
||||
# ### end Alembic commands ###
|
@ -182,6 +182,14 @@ Config file is located in `config/cxb.yaml`.
|
||||
|
||||
## maimai DX
|
||||
|
||||
### Presents
|
||||
Presents are items given to the user when they login, with a little animation (for example, the KOP song was given to the finalists as a present). To add a present, you must insert it into the `mai2_item_present` table. In that table, a NULL version means any version, a NULL user means any user, a NULL start date means always open, and a NULL end date means it never expires. Below is a list of presents one might wish to add:
|
||||
|
||||
| Game Version | Item ID | Item Kind | Item Description | Present Description |
|
||||
|--------------|---------|-----------|-------------------------------------------------|------------------------------------------------|
|
||||
| BUDDiES (21) | 409505 | Icon (3) | 旅行スタンプ(月面基地) (Travel Stamp - Moon Base) | Officially obtained on the webui with a serial |
|
||||
| | | | | number, for project raputa |
|
||||
|
||||
### Versions
|
||||
|
||||
| Game Code | Version ID | Version Name |
|
||||
|
@ -471,7 +471,25 @@ class Mai2Base:
|
||||
}
|
||||
|
||||
async def handle_get_user_present_api_request(self, data: Dict) -> Dict:
|
||||
return { "userId": data.get("userId", 0), "length": 0, "userPresentList": []}
|
||||
items: List[Dict[str, Any]] = []
|
||||
user_pres_list = await self.data.item.get_presents_by_version_user(self.version, data["userId"])
|
||||
if user_pres_list:
|
||||
for present in user_pres_list:
|
||||
if (present['startDate'] and present['startDate'].timestamp() > datetime.now().timestamp()):
|
||||
self.logger.debug(f"Present {present['id']} distribution hasn't started yet (begins {present['startDate']})")
|
||||
continue # present period hasn't started yet, move onto the next one
|
||||
|
||||
if (present['endDate'] and present['endDate'].timestamp() < datetime.now().timestamp()):
|
||||
self.logger.warn(f"Present {present['id']} ended on {present['endDate']} and should be removed")
|
||||
continue # present period ended, move onto the next one
|
||||
|
||||
test = await self.data.item.get_item(data["userId"], present['itemKind'], present['itemId'])
|
||||
if not test: # Don't send presents for items the user already has
|
||||
items.append({"itemId": present['itemId'], "itemKind": present['itemKind'], "stock": present['stock'], "isValid": True})
|
||||
self.logger.info(f"Give user {data['userId']} {present['stock']}x item {present['itemId']} (kind {present['itemKind']}) as present")
|
||||
await self.data.item.put_item(data["userId"], present['itemKind'], present['itemId'], present['stock'], True)
|
||||
|
||||
return { "userId": data.get("userId", 0), "length": len(items), "userPresentList": items}
|
||||
|
||||
async def handle_get_transfer_friend_api_request(self, data: Dict) -> Dict:
|
||||
return {}
|
||||
|
@ -327,9 +327,28 @@ class Mai2DX(Mai2Base):
|
||||
async def handle_get_user_item_api_request(self, data: Dict) -> Dict:
|
||||
kind = int(data["nextIndex"] / 10000000000)
|
||||
next_idx = int(data["nextIndex"] % 10000000000)
|
||||
user_item_list = await self.data.item.get_items(data["userId"], kind)
|
||||
|
||||
items: List[Dict[str, Any]] = []
|
||||
|
||||
if kind == 4: # presents
|
||||
user_pres_list = await self.data.item.get_presents_by_version_user(self.version, data["userId"])
|
||||
if user_pres_list:
|
||||
for present in user_pres_list:
|
||||
if (present['startDate'] and present['startDate'].timestamp() > datetime.now().timestamp()):
|
||||
self.logger.debug(f"Present {present['id']} distribution hasn't started yet (begins {present['startDate']})")
|
||||
continue # present period hasn't started yet, move onto the next one
|
||||
|
||||
if (present['endDate'] and present['endDate'].timestamp() < datetime.now().timestamp()):
|
||||
self.logger.warn(f"Present {present['id']} ended on {present['endDate']} and should be removed")
|
||||
continue # present period ended, move onto the next one
|
||||
|
||||
test = await self.data.item.get_item(data["userId"], present['itemKind'], present['itemId'])
|
||||
if not test: # Don't send presents for items the user already has
|
||||
items.append({"itemId": present['itemId'], "itemKind": present['itemKind'], "stock": present['stock'], "isValid": True})
|
||||
self.logger.info(f"Give user {data['userId']} {present['stock']}x item {present['itemId']} (kind {present['itemKind']}) as present")
|
||||
await self.data.item.put_item(data["userId"], present['itemKind'], present['itemId'], present['stock'], True)
|
||||
|
||||
else:
|
||||
user_item_list = await self.data.item.get_items(data["userId"], kind)
|
||||
for i in range(next_idx, len(user_item_list)):
|
||||
tmp = user_item_list[i]._asdict()
|
||||
tmp.pop("user")
|
||||
|
@ -2,8 +2,8 @@ from core.data.schema import BaseData, metadata
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional, Dict, List
|
||||
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_
|
||||
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON
|
||||
from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_, or_
|
||||
from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON, BIGINT, INTEGER
|
||||
from sqlalchemy.schema import ForeignKey
|
||||
from sqlalchemy.sql import func, select
|
||||
from sqlalchemy.dialects.mysql import insert
|
||||
@ -198,6 +198,20 @@ print_detail = Table(
|
||||
mysql_charset="utf8mb4",
|
||||
)
|
||||
|
||||
present = Table(
|
||||
"mai2_item_present",
|
||||
metadata,
|
||||
Column('id', BIGINT, primary_key=True, nullable=False),
|
||||
Column('version', INTEGER),
|
||||
Column("user", Integer, ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade")),
|
||||
Column("itemKind", INTEGER, nullable=False),
|
||||
Column("itemId", INTEGER, nullable=False),
|
||||
Column("stock", INTEGER, nullable=False, server_default="1"),
|
||||
Column("startDate", TIMESTAMP),
|
||||
Column("endDate", TIMESTAMP),
|
||||
UniqueConstraint("version", "user", "itemKind", "itemId", name="mai2_item_present_uk"),
|
||||
mysql_charset="utf8mb4",
|
||||
)
|
||||
|
||||
class Mai2ItemData(BaseData):
|
||||
async def put_item(
|
||||
@ -476,7 +490,7 @@ class Mai2ItemData(BaseData):
|
||||
musicId = music_id
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_do_nothing()
|
||||
conflict = sql.on_duplicate_key_update(musicId = music_id)
|
||||
|
||||
result = await self.execute(conflict)
|
||||
if result:
|
||||
@ -586,3 +600,49 @@ class Mai2ItemData(BaseData):
|
||||
)
|
||||
return None
|
||||
return result.lastrowid
|
||||
|
||||
async def put_present(self, item_kind: int, item_id: int, version: int = None, user_id: int = None, start_date: datetime = None, end_date: datetime = None) -> Optional[int]:
|
||||
sql = insert(present).values(
|
||||
version = version,
|
||||
user = user_id,
|
||||
itemKind = item_kind,
|
||||
itemId = item_id,
|
||||
startDate = start_date,
|
||||
endDate = end_date
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_update(
|
||||
startDate = start_date,
|
||||
endDate = end_date
|
||||
)
|
||||
|
||||
result = await self.execute(conflict)
|
||||
if result:
|
||||
return result.lastrowid
|
||||
|
||||
self.logger.error(f"Failed to add present item {item_id}!")
|
||||
|
||||
async def get_presents_by_user(self, user_id: int = None) -> Optional[List[Row]]:
|
||||
result = await self.execute(present.select(or_(present.c.user == user_id, present.c.user is None)))
|
||||
if result:
|
||||
return result.fetchall()
|
||||
|
||||
async def get_presents_by_version(self, ver: int = None) -> Optional[List[Row]]:
|
||||
result = await self.execute(present.select(or_(present.c.version == ver, present.c.version is None)))
|
||||
if result:
|
||||
return result.fetchall()
|
||||
|
||||
async def get_presents_by_version_user(self, ver: int = None, user_id: int = None) -> Optional[List[Row]]:
|
||||
result = await self.execute(present.select(
|
||||
and_(
|
||||
or_(present.c.user == user_id, present.c.user is None)),
|
||||
or_(present.c.version == ver, present.c.version is None)
|
||||
)
|
||||
)
|
||||
if result:
|
||||
return result.fetchall()
|
||||
|
||||
async def get_present_by_id(self, present_id: int) -> Optional[Row]:
|
||||
result = await self.execute(present.select(present.c.id == present_id))
|
||||
if result:
|
||||
return result.fetchone()
|
||||
|
@ -892,7 +892,7 @@ class Mai2ProfileData(BaseData):
|
||||
rival = rival_id
|
||||
)
|
||||
|
||||
conflict = sql.on_duplicate_key_do_nothing()
|
||||
conflict = sql.on_duplicate_key_update(rival = rival_id)
|
||||
|
||||
result = await self.execute(conflict)
|
||||
if result:
|
||||
|
Loading…
Reference in New Issue
Block a user