From f71591e622c7c397768207793d89dd15b577c8b7 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Tue, 12 Mar 2024 14:17:26 -0400 Subject: [PATCH 1/5] wacca: fix S stage up stages --- titles/wacca/s.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/titles/wacca/s.py b/titles/wacca/s.py index aab2659..2633110 100644 --- a/titles/wacca/s.py +++ b/titles/wacca/s.py @@ -21,10 +21,10 @@ class WaccaS(WaccaBase): (1507, 7), (1506, 6), (1505, 5), - (1514, 4), - (1513, 3), - (1512, 2), - (1511, 1), + (1504, 4), + (1503, 3), + (1502, 2), + (1501, 1), ] def __init__(self, cfg: CoreConfig, game_cfg: WaccaConfig) -> None: From 346f82a32ad101a23d4c244dc212750ef6b8c309 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Tue, 12 Mar 2024 14:20:36 -0400 Subject: [PATCH 2/5] wacca: move allowed_stages into __init__ for s --- titles/wacca/s.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/titles/wacca/s.py b/titles/wacca/s.py index 2633110..4e43237 100644 --- a/titles/wacca/s.py +++ b/titles/wacca/s.py @@ -11,25 +11,24 @@ from titles.wacca.handlers import * class WaccaS(WaccaBase): - allowed_stages = [ - (1513, 13), - (1512, 12), - (1511, 11), - (1510, 10), - (1509, 9), - (1508, 8), - (1507, 7), - (1506, 6), - (1505, 5), - (1504, 4), - (1503, 3), - (1502, 2), - (1501, 1), - ] - def __init__(self, cfg: CoreConfig, game_cfg: WaccaConfig) -> None: super().__init__(cfg, game_cfg) self.version = WaccaConstants.VER_WACCA_S + self.allowed_stages = [ + (1513, 13), + (1512, 12), + (1511, 11), + (1510, 10), + (1509, 9), + (1508, 8), + (1507, 7), + (1506, 6), + (1505, 5), + (1504, 4), + (1503, 3), + (1502, 2), + (1501, 1), + ] async def handle_advertise_GetNews_request(self, data: Dict) -> Dict: resp = GetNewsResponseV2() From 40a0817009104f6bd48010830ae69dcc54569c2d Mon Sep 17 00:00:00 2001 From: beerpsi Date: Thu, 14 Mar 2024 14:44:32 +0000 Subject: [PATCH 3/5] CHUNITHM & O.N.G.E.K.I.: Handle userRatingBase*List (#113) These tables are not used by the game, but are useful for anyone wanting to develop a web UI showing what the player's rating consists of. As such, instead of storing them in JSON columns, I've split them out, one row per each entry. Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/113 Co-authored-by: beerpsi Co-committed-by: beerpsi --- .../6a7e8277763b_gekichu_rating_tables.py | 56 +++++++++++++++++++ titles/chuni/base.py | 11 ++++ titles/chuni/schema/profile.py | 51 +++++++++++++++-- titles/ongeki/base.py | 18 ++++++ titles/ongeki/schema/profile.py | 47 +++++++++++++++- 5 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 core/data/alembic/versions/6a7e8277763b_gekichu_rating_tables.py diff --git a/core/data/alembic/versions/6a7e8277763b_gekichu_rating_tables.py b/core/data/alembic/versions/6a7e8277763b_gekichu_rating_tables.py new file mode 100644 index 0000000..2d4074a --- /dev/null +++ b/core/data/alembic/versions/6a7e8277763b_gekichu_rating_tables.py @@ -0,0 +1,56 @@ +"""GekiChu rating tables + +Revision ID: 6a7e8277763b +Revises: d8950c7ce2fc +Create Date: 2024-03-13 12:18:53.210018 + +""" +from alembic import op +from sqlalchemy import Column, Integer, String + + +# revision identifiers, used by Alembic. +revision = '6a7e8277763b' +down_revision = 'd8950c7ce2fc' +branch_labels = None +depends_on = None + +GEKICHU_RATING_TABLE_NAMES = [ + "chuni_profile_rating", + "ongeki_profile_rating", +] + +def upgrade(): + for table_name in GEKICHU_RATING_TABLE_NAMES: + op.create_table( + table_name, + Column("id", Integer, primary_key=True, nullable=False), + Column("user", Integer, nullable=False), + Column("version", Integer, nullable=False), + Column("type", String(255), nullable=False), + Column("index", Integer, nullable=False), + Column("musicId", Integer), + Column("difficultId", Integer), + Column("romVersionCode", Integer), + Column("score", Integer), + mysql_charset="utf8mb4", + ) + op.create_foreign_key( + None, + table_name, + "aime_user", + ["user"], + ["id"], + ondelete="cascade", + onupdate="cascade", + ) + op.create_unique_constraint( + f"{table_name}_uk", + table_name, + ["user", "version", "type", "index"], + ) + + +def downgrade(): + for table_name in GEKICHU_RATING_TABLE_NAMES: + op.drop_table(table_name) diff --git a/titles/chuni/base.py b/titles/chuni/base.py index 72d665e..c3b9ca2 100644 --- a/titles/chuni/base.py +++ b/titles/chuni/base.py @@ -925,6 +925,17 @@ class ChuniBase: for rp in upsert["userRecentPlayerList"]: pass + for rating_type in {"userRatingBaseList", "userRatingBaseHotList", "userRatingBaseNextList"}: + if rating_type not in upsert: + continue + + await self.data.profile.put_profile_rating( + user_id, + self.version, + rating_type, + upsert[rating_type], + ) + return {"returnCode": "1"} async def handle_upsert_user_chargelog_api_request(self, data: Dict) -> Dict: diff --git a/titles/chuni/schema/profile.py b/titles/chuni/schema/profile.py index 849a5b3..9864928 100644 --- a/titles/chuni/schema/profile.py +++ b/titles/chuni/schema/profile.py @@ -1,10 +1,9 @@ from typing import Dict, List, Optional -from sqlalchemy import Table, Column, UniqueConstraint, PrimaryKeyConstraint, and_ -from sqlalchemy.types import Integer, String, TIMESTAMP, Boolean, JSON, BigInteger -from sqlalchemy.engine.base import Connection +from sqlalchemy import Table, Column, UniqueConstraint, and_ +from sqlalchemy.types import Integer, String, Boolean, JSON, BigInteger from sqlalchemy.schema import ForeignKey from sqlalchemy.engine import Row -from sqlalchemy.sql import func, select +from sqlalchemy.sql import select, delete from sqlalchemy.dialects.mysql import insert from core.data.schema import BaseData, metadata @@ -393,6 +392,26 @@ team = Table( mysql_charset="utf8mb4", ) +rating = Table( + "chuni_profile_rating", + metadata, + Column("id", Integer, primary_key=True, nullable=False), + Column( + "user", + ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), + nullable=False, + ), + Column("version", Integer, nullable=False), + Column("type", String(255), nullable=False), + Column("index", Integer, nullable=False), + Column("musicId", Integer), + Column("difficultId", Integer), + Column("romVersionCode", Integer), + Column("score", Integer), + UniqueConstraint("user", "version", "type", "index", name="chuni_profile_rating_best_uk"), + mysql_charset="utf8mb4", +) + class ChuniProfileData(BaseData): async def update_name(self, user_id: int, new_name: str) -> bool: @@ -714,3 +733,27 @@ class ChuniProfileData(BaseData): return { "total_play_count": total_play_count } + + async def put_profile_rating( + self, + aime_id: int, + version: int, + rating_type: str, + rating_data: List[Dict], + ): + inserted_values = [ + {"user": aime_id, "version": version, "type": rating_type, "index": i, **x} + for (i, x) in enumerate(rating_data) + ] + sql = insert(rating).values(inserted_values) + update_dict = {x.name: x for x in sql.inserted if x.name != "id"} + sql = sql.on_duplicate_key_update(**update_dict) + result = await self.execute(sql) + + if result is None: + self.logger.warn( + f"put_profile_rating: Could not insert {rating_type}, aime_id: {aime_id}", + ) + return + + return result.lastrowid diff --git a/titles/ongeki/base.py b/titles/ongeki/base.py index d40ece8..ca5a38c 100644 --- a/titles/ongeki/base.py +++ b/titles/ongeki/base.py @@ -1067,6 +1067,24 @@ class OngekiBase: if "userKopList" in upsert: for x in upsert["userKopList"]: await self.data.profile.put_kop(user_id, x) + + for rating_type in { + "userRatingBaseBestList", + "userRatingBaseBestNewList", + "userRatingBaseHotList", + "userRatingBaseNextList", + "userRatingBaseNextNewList", + "userRatingBaseHotNextList", + }: + if rating_type not in upsert: + continue + + await self.data.profile.put_profile_rating( + user_id, + self.version, + rating_type, + upsert[rating_type], + ) return {"returnCode": 1, "apiName": "upsertUserAll"} diff --git a/titles/ongeki/schema/profile.py b/titles/ongeki/schema/profile.py index 1f6bcab..b42a0a3 100644 --- a/titles/ongeki/schema/profile.py +++ b/titles/ongeki/schema/profile.py @@ -246,6 +246,26 @@ rival = Table( mysql_charset="utf8mb4", ) +rating = Table( + "ongeki_profile_rating", + metadata, + Column("id", Integer, primary_key=True, nullable=False), + Column( + "user", + ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), + nullable=False, + ), + Column("version", Integer, nullable=False), + Column("type", String(255), nullable=False), + Column("index", Integer, nullable=False), + Column("musicId", Integer), + Column("difficultId", Integer), + Column("romVersionCode", Integer), + Column("score", Integer), + UniqueConstraint("user", "version", "type", "index", name="ongeki_profile_rating_best_uk"), + mysql_charset="utf8mb4", +) + class OngekiProfileData(BaseData): def __init__(self, cfg: CoreConfig, conn: Connection) -> None: @@ -508,10 +528,35 @@ class OngekiProfileData(BaseData): ) return None return result.lastrowid + async def delete_rival(self, aime_id: int, rival_id: int) -> Optional[int]: sql = delete(rival).where(rival.c.user==aime_id, rival.c.rivalUserId==rival_id) result = await self.execute(sql) if result is None: self.logger.error(f"delete_rival: failed to delete! aime_id: {aime_id}, rival_id: {rival_id}") else: - return result.rowcount \ No newline at end of file + return result.rowcount + + async def put_profile_rating( + self, + aime_id: int, + version: int, + rating_type: str, + rating_data: List[Dict], + ): + inserted_values = [ + {"user": aime_id, "version": version, "type": rating_type, "index": i, **x} + for (i, x) in enumerate(rating_data) + ] + sql = insert(rating).values(inserted_values) + update_dict = {x.name: x for x in sql.inserted if x.name != "id"} + sql = sql.on_duplicate_key_update(**update_dict) + result = await self.execute(sql) + + if result is None: + self.logger.warn( + f"put_profile_rating_{rating_type}: Could not insert rating entries, aime_id: {aime_id}", + ) + return + + return result.lastrowid From 75bf8f4cb73f7925eab19ba19f2617ce189259d3 Mon Sep 17 00:00:00 2001 From: zaphkito Date: Thu, 14 Mar 2024 14:48:06 +0000 Subject: [PATCH 4/5] add python-multipart to requirements.txt (#112) because of frontend now required python-multipart in requestments Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/112 Co-authored-by: zaphkito Co-committed-by: zaphkito --- requirements.txt | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/requirements.txt b/requirements.txt index 1bfd667..fe5b4ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,23 +1,24 @@ -mypy -wheel -pytz -pyyaml -sqlalchemy==1.4.46 -mysqlclient -pyopenssl -service_identity -PyCryptodome -inflection -coloredlogs -pylibmc; platform_system != "Windows" -wacky -bcrypt -jinja2 -protobuf -pillow -pyjwt==2.8.0 -websockets -starlette -asyncio -uvicorn -alembic +mypy +wheel +pytz +pyyaml +sqlalchemy==1.4.46 +mysqlclient +pyopenssl +service_identity +PyCryptodome +inflection +coloredlogs +pylibmc; platform_system != "Windows" +wacky +bcrypt +jinja2 +protobuf +pillow +pyjwt==2.8.0 +websockets +starlette +asyncio +uvicorn +alembic +python-multipart \ No newline at end of file From 942b636b3ebddd8f50be952158dc0867d00adf39 Mon Sep 17 00:00:00 2001 From: Midorica Date: Mon, 18 Mar 2024 22:33:39 -0400 Subject: [PATCH 5/5] cxb: fixing rev s1 support --- changelog.md | 4 +++ titles/cxb/data/rss1/Shop/ShopList_Sale.csv | 3 -- titles/cxb/data/rss1/Shop/ShopList_SkinBg.csv | 4 --- .../data/rss1/Shop/ShopList_SkinEffect.csv | 11 ------ .../cxb/data/rss1/Shop/ShopList_SkinNotes.csv | 6 ---- titles/cxb/rss1.py | 36 ------------------- 6 files changed, 4 insertions(+), 60 deletions(-) delete mode 100644 titles/cxb/data/rss1/Shop/ShopList_Sale.csv delete mode 100644 titles/cxb/data/rss1/Shop/ShopList_SkinBg.csv delete mode 100644 titles/cxb/data/rss1/Shop/ShopList_SkinEffect.csv delete mode 100644 titles/cxb/data/rss1/Shop/ShopList_SkinNotes.csv diff --git a/changelog.md b/changelog.md index 3aa0559..437a3b2 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,10 @@ # Changelog Documenting updates to ARTEMiS, to be updated every time the master branch is pushed to. +## 20240318 +### CXB ++ Fixing handle_data_shop_list_detail_request for Sunrise S1 + ## 20240302 ### SAO + Fixing new profile creation with right heroes and start VP diff --git a/titles/cxb/data/rss1/Shop/ShopList_Sale.csv b/titles/cxb/data/rss1/Shop/ShopList_Sale.csv deleted file mode 100644 index 5e9fb72..0000000 --- a/titles/cxb/data/rss1/Shop/ShopList_Sale.csv +++ /dev/null @@ -1,3 +0,0 @@ -saleID.,�J�n��,�I����,ShopID,Price, -0,1411696799,1443236400,0,7000, -1,1411783199,1443322800,1,7000, diff --git a/titles/cxb/data/rss1/Shop/ShopList_SkinBg.csv b/titles/cxb/data/rss1/Shop/ShopList_SkinBg.csv deleted file mode 100644 index 44c4843..0000000 --- a/titles/cxb/data/rss1/Shop/ShopList_SkinBg.csv +++ /dev/null @@ -1,4 +0,0 @@ -shopID.,pNo.,Ver.,otO,otOQID,,o,Ŏ,ItemCode,i,\^Cv,Text,Type,Value(op),Value,Ώۋ,Difficulty(op),Difficulty,Level(op),Level,Grade(Op),Grade,GaugeType(op),GaugeType,HS(op)i,HS,APP,DAP,F-V,F-H,FullCombo,Combo(op),Combo,ClearRate(op),ClearRate,vC,n, -3000,1,1.00.00,1,-1,-,1411697520.0288,1443233520.0288,skb0000,10,1,MASTERȏ2S+ȏtR{NAB,1,1,1,-,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -3001,2,1.00.00,1,-1,-,1411697520.0288,1443233520.0288,skb0001,10,1,Next Frontier (MasterjNA,0,-1,-1,bleeze,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -3002,3,1.00.00,1,-1,-,1412103600.0288,1443639598.992,skb0002,10,2,Masterȏ1ȂS+ȏŃNAB,1,1,1,-,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,1, diff --git a/titles/cxb/data/rss1/Shop/ShopList_SkinEffect.csv b/titles/cxb/data/rss1/Shop/ShopList_SkinEffect.csv deleted file mode 100644 index bb6486e..0000000 --- a/titles/cxb/data/rss1/Shop/ShopList_SkinEffect.csv +++ /dev/null @@ -1,11 +0,0 @@ -shopID.,�����pNo.,Ver.,�o���t���O,�o���t���O�Q��ID,����,�o������,���Ŏ���,ItemCode,���i,�\���^�C�v,Text,Type,Value(op),Value,�Ώۋ�,Difficulty(op),Difficulty,Level(op),Level,Grade(Op),Grade,GaugeType(op),GaugeType,HS(op)i,HS,APP,DAP,F-V,F-H,FullCombo,Combo(op),Combo,ClearRate(op),ClearRate,�v���C��,�n��, -5000,1,10000,1,-1,-,1411697520,1443233520,ske0000,10,1,MASTER�ȏ��2��S+�ȏ�t���R���{�N���A����B,1,1,1,-,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -5001,2,10000,1,-1,-,1411697520,1443233520,ske0001,10,1,Next Frontier (Master�j���N���A,0,-1,-1,megaro,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -5002,3,10000,1,-1,-,1412103600,1443639598,ske0002,10,2,Master�ȏ��1�Ȃ�S+�ȏ�ŃN���A����B,1,1,1,-,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,1, -5003,4,10000,1,-1,-,1412103600,1443639598,ske0003,10,0,Master�ȏ��1�Ȃ�S+�ȏ�ŃN���A����B,1,1,1,-,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -5004,5,10000,1,-1,-,1412103600,1443639598,ske0004,10,2,2�ȃN���A,1,1,2,-,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -5005,5,10000,1,-1,-,1412103600,1443639598,ske0005,10,2,3�ȃN���A,1,1,3,-,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -5006,5,10000,1,-1,-,1412103600,1443639598,ske0006,10,2,4�ȃN���A,1,1,4,-,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -5007,5,10000,1,-1,-,1412103600,1443639598,ske0007,10,2,5�ȃN���A,1,1,5,-,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -5008,5,10000,1,-1,-,1412103600,1443639598,ske0008,10,2,6�ȃN���A,1,1,6,-,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -5009,5,10000,1,-1,-,1412103600,1443639598,ske0009,10,2,7�ȃN���A,1,1,7,-,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, diff --git a/titles/cxb/data/rss1/Shop/ShopList_SkinNotes.csv b/titles/cxb/data/rss1/Shop/ShopList_SkinNotes.csv deleted file mode 100644 index 0b496f2..0000000 --- a/titles/cxb/data/rss1/Shop/ShopList_SkinNotes.csv +++ /dev/null @@ -1,6 +0,0 @@ -shopID.,�����pNo.,Ver.,�o���t���O,�o���t���O�Q��ID,����,�o������,���Ŏ���,ItemCode,���i,�\���^�C�v,Text,Type,Value(op),Value,�Ώۋ�,Difficulty(op),Difficulty,Level(op),Level,Grade(Op),Grade,GaugeType(op),GaugeType,HS(op)i,HS,APP,DAP,F-V,F-H,FullCombo,Combo(op),Combo,ClearRate(op),ClearRate,�v���C��,�n��, -4000,1,10000,1,-1,-,1411697520,4096483201,skt0000,10,1,MASTER�ȏ��2��S+�ȏ�t���R���{�N���A����B,1,1,1,-,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -4001,2,10000,1,-1,-,1411697520,4096483201,skt0001,10,1,Next Frontier (Master�j���N���A,0,-1,-1,megaro,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -4002,3,10000,1,-1,-,1412103600,4096483201,skt0002,10,2,Master�ȏ��1�Ȃ�S+�ȏ�ŃN���A����B,1,1,1,-,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,1, -4003,4,10000,1,-1,-,1412103600,4096483201,skt0003,10,0,Master�ȏ��1�Ȃ�S+�ȏ�ŃN���A����B,1,1,1,-,1,2,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, -4004,5,10000,1,-1,-,1412103600,4096483201,skt0004,10,2,aaaaaaaaaaaaaaaaa,1,1,20,-,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,,, diff --git a/titles/cxb/rss1.py b/titles/cxb/rss1.py index cce0315..4999cc5 100644 --- a/titles/cxb/rss1.py +++ b/titles/cxb/rss1.py @@ -73,42 +73,6 @@ class CxbRevSunriseS1(CxbBase): for line in lines: ret_str += f"{line[:-1]}\r\n" - # ShopListSale load - ret_str += "\r\n#ShopListSale\r\n" - with open( - r"titles/cxb/data/rss1/Shop/ShopList_Sale.csv", encoding="shift-jis" - ) as shop: - lines = shop.readlines() - for line in lines: - ret_str += f"{line[:-1]}\r\n" - - # ShopListSkinBg load - ret_str += "\r\n#ShopListSkinBg\r\n" - with open( - r"titles/cxb/data/rss1/Shop/ShopList_SkinBg.csv", encoding="shift-jis" - ) as shop: - lines = shop.readlines() - for line in lines: - ret_str += f"{line[:-1]}\r\n" - - # ShopListSkinEffect load - ret_str += "\r\n#ShopListSkinEffect\r\n" - with open( - r"titles/cxb/data/rss1/Shop/ShopList_SkinEffect.csv", encoding="shift-jis" - ) as shop: - lines = shop.readlines() - for line in lines: - ret_str += f"{line[:-1]}\r\n" - - # ShopListSkinNotes load - ret_str += "\r\n#ShopListSkinNotes\r\n" - with open( - r"titles/cxb/data/rss1/Shop/ShopList_SkinNotes.csv", encoding="shift-jis" - ) as shop: - lines = shop.readlines() - for line in lines: - ret_str += f"{line[:-1]}\r\n" - # ShopListTitle load ret_str += "\r\n#ShopListTitle\r\n" with open(