From e16bfc713aaa5dbfc6a85c0ea5f194f054d97d68 Mon Sep 17 00:00:00 2001 From: Hay1tsme Date: Tue, 8 Apr 2025 00:41:49 -0400 Subject: [PATCH] chuni: add opt to reader --- .../ae364c078429_chuni_nameplate_add_opt.py | 30 +++++++ titles/chuni/read.py | 21 +++-- titles/chuni/schema/static.py | 84 +++++++++++++------ 3 files changed, 102 insertions(+), 33 deletions(-) create mode 100644 core/data/alembic/versions/ae364c078429_chuni_nameplate_add_opt.py diff --git a/core/data/alembic/versions/ae364c078429_chuni_nameplate_add_opt.py b/core/data/alembic/versions/ae364c078429_chuni_nameplate_add_opt.py new file mode 100644 index 0000000..b6f61bd --- /dev/null +++ b/core/data/alembic/versions/ae364c078429_chuni_nameplate_add_opt.py @@ -0,0 +1,30 @@ +"""chuni_nameplate_add_opt + +Revision ID: ae364c078429 +Revises: 5cf98cfe52ad +Create Date: 2025-04-08 00:22:22.370660 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +# revision identifiers, used by Alembic. +revision = 'ae364c078429' +down_revision = '5cf98cfe52ad' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('chuni_static_nameplate', sa.Column('opt', sa.BIGINT(), nullable=True)) + op.create_foreign_key(None, 'chuni_static_nameplate', 'chuni_static_opt', ['opt'], ['id'], onupdate='cascade', ondelete='SET NULL') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint("chuni_static_nameplate_ibfk_1", 'chuni_static_nameplate', type_='foreignkey') + op.drop_column('chuni_static_nameplate', 'opt') + # ### end Alembic commands ### diff --git a/titles/chuni/read.py b/titles/chuni/read.py index fb81d1d..bd6ff07 100644 --- a/titles/chuni/read.py +++ b/titles/chuni/read.py @@ -78,7 +78,7 @@ class ChuniReader(BaseReader): is_enabled = True if (disableFlag is None or disableFlag.text == "false") else False result = await self.data.static.put_login_bonus_preset( - self.version, id, name, is_enabled + self.version, id, name, is_enabled, opt_id ) if result is not None: @@ -125,6 +125,7 @@ class ChuniReader(BaseReader): item_num, need_login_day_count, login_bonus_category_type, + opt_id ) if result is not None: @@ -149,7 +150,7 @@ class ChuniReader(BaseReader): event_type = substances.find("type").text result = await self.data.static.put_event( - self.version, id, event_type, name + self.version, id, event_type, name, opt_id ) if result is not None: self.logger.info(f"Inserted event {id}") @@ -221,6 +222,7 @@ class ChuniReader(BaseReader): genre, jacket_path, we_chara, + opt_id ) if result is not None: @@ -254,6 +256,7 @@ class ChuniReader(BaseReader): expirationDays, consumeType, sellingAppeal, + opt_id ) if result is not None: @@ -286,7 +289,7 @@ class ChuniReader(BaseReader): self.copy_image(texturePath, f"{root}/{dir}", "titles/chuni/img/avatar/") result = await self.data.static.put_avatar( - self.version, id, name, category, iconPath, texturePath, is_enabled, defaultHave, sortName + self.version, id, name, category, iconPath, texturePath, is_enabled, defaultHave, sortName, opt_id ) if result is not None: @@ -315,7 +318,7 @@ class ChuniReader(BaseReader): self.copy_image(texturePath, f"{root}/{dir}", "titles/chuni/img/nameplate/") result = await self.data.static.put_nameplate( - self.version, id, name, texturePath, is_enabled, defaultHave, sortName + self.version, id, name, texturePath, is_enabled, defaultHave, sortName, opt_id ) if result is not None: @@ -340,7 +343,7 @@ class ChuniReader(BaseReader): defaultHave = xml_root.find("defaultHave").text == 'true' result = await self.data.static.put_trophy( - self.version, id, name, rareType, is_enabled, defaultHave + self.version, id, name, rareType, is_enabled, defaultHave, opt_id ) if result is not None: @@ -387,7 +390,7 @@ class ChuniReader(BaseReader): self.logger.warning(f"Unable to location character {id} images") result = await self.data.static.put_character( - self.version, id, name, sortName, worksName, rareType, imagePath1, imagePath2, imagePath3, is_enabled, defaultHave + self.version, id, name, sortName, worksName, rareType, imagePath1, imagePath2, imagePath3, is_enabled, defaultHave, opt_id ) if result is not None: @@ -415,7 +418,7 @@ class ChuniReader(BaseReader): is_enabled = True if (disableFlag is None or disableFlag.text == "false") else False result = await self.data.static.put_map_icon( - self.version, id, name, sortName, iconPath, is_enabled, defaultHave + self.version, id, name, sortName, iconPath, is_enabled, defaultHave, opt_id ) if result is not None: @@ -443,7 +446,7 @@ class ChuniReader(BaseReader): is_enabled = True if (disableFlag is None or disableFlag.text == "false") else False result = await self.data.static.put_system_voice( - self.version, id, name, sortName, imagePath, is_enabled, defaultHave + self.version, id, name, sortName, imagePath, is_enabled, defaultHave, opt_id ) if result is not None: @@ -490,6 +493,8 @@ class ChuniReader(BaseReader): if not opt_id: self.logger.error(f"Failed to put opt folder info for {opt_folder}") return None + else: + opt_id = opt_id['id'] self.logger.info(f"Opt folder {opt_folder} (Database ID {opt_id}) contains {data_config['Version']['Name']} v{data_config['Version']['VerMajor']}.{data_config['Version']['VerMinor']}.{opt_seq}") return opt_id diff --git a/titles/chuni/schema/static.py b/titles/chuni/schema/static.py index 0f7dc4a..f4f0f9f 100644 --- a/titles/chuni/schema/static.py +++ b/titles/chuni/schema/static.py @@ -13,6 +13,7 @@ from sqlalchemy.schema import ForeignKey from sqlalchemy.sql import func, select from sqlalchemy.dialects.mysql import insert from datetime import datetime +from sqlalchemy.sql.functions import coalesce from core.data.schema import BaseData, metadata @@ -107,6 +108,7 @@ nameplate = Table( Column("isEnabled", Boolean, server_default="1"), Column("defaultHave", Boolean, server_default="0"), Column("sortName", String(255)), + Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")), UniqueConstraint("version", "nameplateId", name="chuni_static_nameplate_uk"), mysql_charset="utf8mb4", ) @@ -299,6 +301,7 @@ class ChuniStaticData(BaseData): item_num: int, need_login_day_count: int, login_bonus_category_type: int, + opt_id: int = None ) -> Optional[int]: sql = insert(login_bonus).values( version=version, @@ -310,6 +313,7 @@ class ChuniStaticData(BaseData): itemNum=item_num, needLoginDayCount=need_login_day_count, loginBonusCategoryType=login_bonus_category_type, + opt=coalesce(login_bonus.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( @@ -318,6 +322,7 @@ class ChuniStaticData(BaseData): itemNum=item_num, needLoginDayCount=need_login_day_count, loginBonusCategoryType=login_bonus_category_type, + opt=coalesce(login_bonus.c.opt, opt_id) ) result = await self.execute(conflict) @@ -359,17 +364,19 @@ class ChuniStaticData(BaseData): return result.fetchone() async def put_login_bonus_preset( - self, version: int, preset_id: int, preset_name: str, isEnabled: bool + self, version: int, preset_id: int, preset_name: str, isEnabled: bool, opt_id: int = None ) -> Optional[int]: sql = insert(login_bonus_preset).values( presetId=preset_id, version=version, presetName=preset_name, isEnabled=isEnabled, + opt=coalesce(login_bonus_preset.c.opt, opt_id) ) - - conflict = sql.on_duplicate_key_update( - presetName=preset_name, isEnabled=isEnabled + + # Chuni has a habbit of including duplicates in it's opt files, so only update opt if it's null + conflict = sql.on_duplicate_key_update( + presetName=preset_name, isEnabled=isEnabled, opt=coalesce(login_bonus_preset.c.opt, opt_id) ) result = await self.execute(conflict) @@ -393,13 +400,13 @@ class ChuniStaticData(BaseData): return result.fetchall() async def put_event( - self, version: int, event_id: int, type: int, name: str + self, version: int, event_id: int, type: int, name: str, opt_id: int = None ) -> Optional[int]: sql = insert(events).values( - version=version, eventId=event_id, type=type, name=name + version=version, eventId=event_id, type=type, name=name, opt=coalesce(events.c.opt, opt_id) ) - conflict = sql.on_duplicate_key_update(name=name) + conflict = sql.on_duplicate_key_update(name=name, opt=coalesce(events.c.opt, opt_id)) result = await self.execute(conflict) if result is None: @@ -467,6 +474,7 @@ class ChuniStaticData(BaseData): genre: str, jacketPath: str, we_tag: str, + opt_id: int = None ) -> Optional[int]: sql = insert(music).values( version=version, @@ -478,6 +486,7 @@ class ChuniStaticData(BaseData): genre=genre, jacketPath=jacketPath, worldsEndTag=we_tag, + opt=coalesce(music.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( @@ -487,6 +496,7 @@ class ChuniStaticData(BaseData): genre=genre, jacketPath=jacketPath, worldsEndTag=we_tag, + opt=coalesce(music.c.opt, opt_id) ) result = await self.execute(conflict) @@ -502,6 +512,7 @@ class ChuniStaticData(BaseData): expiration_days: int, consume_type: int, selling_appeal: bool, + opt_id: int = None ) -> Optional[int]: sql = insert(charge).values( version=version, @@ -510,6 +521,7 @@ class ChuniStaticData(BaseData): expirationDays=expiration_days, consumeType=consume_type, sellingAppeal=selling_appeal, + opt=coalesce(charge.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( @@ -517,6 +529,7 @@ class ChuniStaticData(BaseData): expirationDays=expiration_days, consumeType=consume_type, sellingAppeal=selling_appeal, + opt=coalesce(charge.c.opt, opt_id) ) result = await self.execute(conflict) @@ -584,7 +597,8 @@ class ChuniStaticData(BaseData): texturePath: str, isEnabled: int, defaultHave: int, - sortName: str + sortName: str, + opt_id: int = None ) -> Optional[int]: sql = insert(avatar).values( version=version, @@ -595,7 +609,8 @@ class ChuniStaticData(BaseData): texturePath=texturePath, isEnabled=isEnabled, defaultHave=defaultHave, - sortName=sortName + sortName=sortName, + opt=coalesce(avatar.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( @@ -605,7 +620,8 @@ class ChuniStaticData(BaseData): texturePath=texturePath, isEnabled=isEnabled, defaultHave=defaultHave, - sortName=sortName + sortName=sortName, + opt=coalesce(avatar.c.opt, opt_id) ) result = await self.execute(conflict) @@ -632,7 +648,8 @@ class ChuniStaticData(BaseData): texturePath: str, isEnabled: int, defaultHave: int, - sortName: str + sortName: str, + opt_id: int = None ) -> Optional[int]: sql = insert(nameplate).values( version=version, @@ -641,7 +658,8 @@ class ChuniStaticData(BaseData): texturePath=texturePath, isEnabled=isEnabled, defaultHave=defaultHave, - sortName=sortName + sortName=sortName, + opt=coalesce(nameplate.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( @@ -649,7 +667,8 @@ class ChuniStaticData(BaseData): texturePath=texturePath, isEnabled=isEnabled, defaultHave=defaultHave, - sortName=sortName + sortName=sortName, + opt=coalesce(nameplate.c.opt, opt_id) ) result = await self.execute(conflict) @@ -676,6 +695,7 @@ class ChuniStaticData(BaseData): rareType: int, isEnabled: int, defaultHave: int, + opt_id: int = None ) -> Optional[int]: sql = insert(trophy).values( version=version, @@ -683,14 +703,16 @@ class ChuniStaticData(BaseData): name=name, rareType=rareType, isEnabled=isEnabled, - defaultHave=defaultHave + defaultHave=defaultHave, + opt=coalesce(trophy.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( name=name, rareType=rareType, isEnabled=isEnabled, - defaultHave=defaultHave + defaultHave=defaultHave, + opt=coalesce(trophy.c.opt, opt_id) ) result = await self.execute(conflict) @@ -718,6 +740,7 @@ class ChuniStaticData(BaseData): iconPath: str, isEnabled: int, defaultHave: int, + opt_id: int = None ) -> Optional[int]: sql = insert(map_icon).values( version=version, @@ -726,7 +749,8 @@ class ChuniStaticData(BaseData): sortName=sortName, iconPath=iconPath, isEnabled=isEnabled, - defaultHave=defaultHave + defaultHave=defaultHave, + opt=coalesce(map_icon.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( @@ -734,7 +758,8 @@ class ChuniStaticData(BaseData): sortName=sortName, iconPath=iconPath, isEnabled=isEnabled, - defaultHave=defaultHave + defaultHave=defaultHave, + opt=coalesce(map_icon.c.opt, opt_id) ) result = await self.execute(conflict) @@ -762,6 +787,7 @@ class ChuniStaticData(BaseData): imagePath: str, isEnabled: int, defaultHave: int, + opt_id: int = None ) -> Optional[int]: sql = insert(system_voice).values( version=version, @@ -770,7 +796,8 @@ class ChuniStaticData(BaseData): sortName=sortName, imagePath=imagePath, isEnabled=isEnabled, - defaultHave=defaultHave + defaultHave=defaultHave, + opt=coalesce(system_voice.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( @@ -778,7 +805,8 @@ class ChuniStaticData(BaseData): sortName=sortName, imagePath=imagePath, isEnabled=isEnabled, - defaultHave=defaultHave + defaultHave=defaultHave, + opt=coalesce(system_voice.c.opt, opt_id) ) result = await self.execute(conflict) @@ -809,7 +837,8 @@ class ChuniStaticData(BaseData): imagePath2: str, imagePath3: str, isEnabled: int, - defaultHave: int + defaultHave: int, + opt_id: int = None ) -> Optional[int]: sql = insert(character).values( version=version, @@ -822,7 +851,8 @@ class ChuniStaticData(BaseData): imagePath2=imagePath2, imagePath3=imagePath3, isEnabled=isEnabled, - defaultHave=defaultHave + defaultHave=defaultHave, + opt=coalesce(character.c.opt, opt_id) ) conflict = sql.on_duplicate_key_update( @@ -834,7 +864,8 @@ class ChuniStaticData(BaseData): imagePath2=imagePath2, imagePath3=imagePath3, isEnabled=isEnabled, - defaultHave=defaultHave + defaultHave=defaultHave, + opt=coalesce(character.c.opt, opt_id) ) result = await self.execute(conflict) @@ -858,12 +889,14 @@ class ChuniStaticData(BaseData): version: int, gacha_id: int, gacha_name: int, + opt_id: int = None, **gacha_data, ) -> Optional[int]: sql = insert(gachas).values( version=version, gachaId=gacha_id, gachaName=gacha_name, + opt=coalesce(gachas.c.opt, opt_id), **gacha_data, ) @@ -871,6 +904,7 @@ class ChuniStaticData(BaseData): version=version, gachaId=gacha_id, gachaName=gacha_name, + opt=coalesce(gachas.c.opt, opt_id), **gacha_data, ) @@ -940,10 +974,10 @@ class ChuniStaticData(BaseData): return None return result.fetchone() - async def put_card(self, version: int, card_id: int, **card_data) -> Optional[int]: - sql = insert(cards).values(version=version, cardId=card_id, **card_data) + async def put_card(self, version: int, card_id: int, opt_id: int = None,**card_data) -> Optional[int]: + sql = insert(cards).values(version=version, cardId=card_id, opt=coalesce(cards.c.opt, opt_id), **card_data) - conflict = sql.on_duplicate_key_update(**card_data) + conflict = sql.on_duplicate_key_update(opt=coalesce(cards.c.opt, opt_id), **card_data) result = await self.execute(conflict) if result is None: