mirror of
https://gitea.tendokyu.moe/Hay1tsme/artemis.git
synced 2026-02-14 03:37:29 +08:00
chuni: add stage import and frontend config
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
"""Linked VERSE
|
"""CHUNITHM X-VERSE
|
||||||
|
|
||||||
Revision ID: 8b57e9646449
|
Revision ID: 8b57e9646449
|
||||||
Revises: bdf710616ba4
|
Revises: bdf710616ba4
|
||||||
@@ -18,6 +18,10 @@ depends_on = None
|
|||||||
|
|
||||||
def upgrade():
|
def upgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column(
|
||||||
|
"chuni_profile_data",
|
||||||
|
sa.Column("stageId", sa.Integer(), nullable=False, server_default="99999"),
|
||||||
|
)
|
||||||
op.create_table(
|
op.create_table(
|
||||||
"chuni_static_linked_verse",
|
"chuni_static_linked_verse",
|
||||||
sa.Column("id", sa.Integer(), nullable=False),
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
@@ -67,9 +71,20 @@ def upgrade():
|
|||||||
sa.UniqueConstraint("user", "linkedVerseId", name="chuni_item_linked_verse_uk"),
|
sa.UniqueConstraint("user", "linkedVerseId", name="chuni_item_linked_verse_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
op.add_column(
|
op.create_table(
|
||||||
"chuni_profile_data",
|
"chuni_static_stage",
|
||||||
sa.Column("stageId", sa.Integer(), nullable=False, server_default="99999"),
|
sa.Column("id", sa.Integer(), primary_key=True, nullable=False),
|
||||||
|
sa.Column("version", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("stageId", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(length=255)),
|
||||||
|
sa.Column("imagePath", sa.String(length=255)),
|
||||||
|
sa.Column("isEnabled", sa.Boolean(), server_default="1"),
|
||||||
|
sa.Column("defaultHave", sa.Boolean(), server_default="0"),
|
||||||
|
sa.Column("opt", sa.BIGINT(), sa.ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
|
sa.UniqueConstraint(
|
||||||
|
"version", "stageId", name="chuni_static_stage_uk"
|
||||||
|
),
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
@@ -79,4 +94,5 @@ def downgrade():
|
|||||||
op.drop_column("chuni_profile_data", "stageId")
|
op.drop_column("chuni_profile_data", "stageId")
|
||||||
op.drop_table("chuni_item_linked_verse")
|
op.drop_table("chuni_item_linked_verse")
|
||||||
op.drop_table("chuni_static_linked_verse")
|
op.drop_table("chuni_static_linked_verse")
|
||||||
|
op.drop_table("chuni_static_stage")
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
@@ -24,6 +24,7 @@ mods:
|
|||||||
nameplates: False
|
nameplates: False
|
||||||
trophies: False
|
trophies: False
|
||||||
character_icons: False
|
character_icons: False
|
||||||
|
stages: False
|
||||||
|
|
||||||
version:
|
version:
|
||||||
11:
|
11:
|
||||||
|
|||||||
@@ -330,6 +330,8 @@ class ItemKind(IntEnum):
|
|||||||
reaching S rank on EXPERT difficulty or above.
|
reaching S rank on EXPERT difficulty or above.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
STAGE = 13
|
||||||
|
|
||||||
|
|
||||||
class FavoriteItemKind(IntEnum):
|
class FavoriteItemKind(IntEnum):
|
||||||
MUSIC = 1
|
MUSIC = 1
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ class ChuniFrontend(FE_Base):
|
|||||||
Route("/avatar", self.render_GET_avatar, methods=['GET']),
|
Route("/avatar", self.render_GET_avatar, methods=['GET']),
|
||||||
Route("/update.map-icon", self.update_map_icon, methods=['POST']),
|
Route("/update.map-icon", self.update_map_icon, methods=['POST']),
|
||||||
Route("/update.system-voice", self.update_system_voice, methods=['POST']),
|
Route("/update.system-voice", self.update_system_voice, methods=['POST']),
|
||||||
|
Route("/update.stage", self.update_stage, methods=['POST']),
|
||||||
Route("/update.userbox", self.update_userbox, methods=['POST']),
|
Route("/update.userbox", self.update_userbox, methods=['POST']),
|
||||||
Route("/update.avatar", self.update_avatar, methods=['POST']),
|
Route("/update.avatar", self.update_avatar, methods=['POST']),
|
||||||
Route("/update.name", self.update_name, methods=['POST']),
|
Route("/update.name", self.update_name, methods=['POST']),
|
||||||
@@ -141,6 +142,7 @@ class ChuniFrontend(FE_Base):
|
|||||||
# version here - it'll just end up being empty sets and the jinja will ignore the variables anyway.
|
# version here - it'll just end up being empty sets and the jinja will ignore the variables anyway.
|
||||||
map_icons, total_map_icons = await self.get_available_map_icons(version, profile)
|
map_icons, total_map_icons = await self.get_available_map_icons(version, profile)
|
||||||
system_voices, total_system_voices = await self.get_available_system_voices(version, profile)
|
system_voices, total_system_voices = await self.get_available_system_voices(version, profile)
|
||||||
|
stages, total_stages = await self.get_available_stages(version, profile)
|
||||||
|
|
||||||
resp = Response(template.render(
|
resp = Response(template.render(
|
||||||
title=f"{self.core_config.server.name} | {self.nav_name}",
|
title=f"{self.core_config.server.name} | {self.nav_name}",
|
||||||
@@ -155,7 +157,9 @@ class ChuniFrontend(FE_Base):
|
|||||||
map_icons=map_icons,
|
map_icons=map_icons,
|
||||||
system_voices=system_voices,
|
system_voices=system_voices,
|
||||||
total_map_icons=total_map_icons,
|
total_map_icons=total_map_icons,
|
||||||
total_system_voices=total_system_voices
|
total_system_voices=total_system_voices,
|
||||||
|
stages=stages,
|
||||||
|
total_stages=total_stages
|
||||||
), media_type="text/html; charset=utf-8")
|
), media_type="text/html; charset=utf-8")
|
||||||
|
|
||||||
if usr_sesh.chunithm_version >= 0:
|
if usr_sesh.chunithm_version >= 0:
|
||||||
@@ -404,6 +408,31 @@ class ChuniFrontend(FE_Base):
|
|||||||
|
|
||||||
return (items, len(rows))
|
return (items, len(rows))
|
||||||
|
|
||||||
|
async def get_available_stages(self, version: int, profile: Row) -> Tuple[List[Dict], int]:
|
||||||
|
if profile is None:
|
||||||
|
return ([], 0)
|
||||||
|
items = dict()
|
||||||
|
rows = await self.data.static.get_stages(version)
|
||||||
|
if rows is None:
|
||||||
|
return (items, 0) # can only happen with old db
|
||||||
|
|
||||||
|
force_unlocked = self.game_cfg.mods.forced_item_unlocks("stages")
|
||||||
|
|
||||||
|
user_stages = []
|
||||||
|
if not force_unlocked:
|
||||||
|
user_stages = await self.data.item.get_items(profile.user, ItemKind.STAGE.value)
|
||||||
|
user_stages = [icon["itemId"] for icon in user_stages] + [profile.stageId]
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
if force_unlocked or row["defaultHave"] or row["stageId"] in user_stages:
|
||||||
|
item = dict()
|
||||||
|
item["id"] = row["stageId"]
|
||||||
|
item["name"] = row["name"]
|
||||||
|
item["imagePath"] = path.splitext(row["imagePath"])[0] + ".webp"
|
||||||
|
items[row["stageId"]] = item
|
||||||
|
|
||||||
|
return (items, len(rows))
|
||||||
|
|
||||||
async def get_available_nameplates(self, version: int, profile: Row) -> Tuple[List[Dict], int]:
|
async def get_available_nameplates(self, version: int, profile: Row) -> Tuple[List[Dict], int]:
|
||||||
items = dict()
|
items = dict()
|
||||||
rows = await self.data.static.get_nameplates(version)
|
rows = await self.data.static.get_nameplates(version)
|
||||||
@@ -651,6 +680,22 @@ class ChuniFrontend(FE_Base):
|
|||||||
|
|
||||||
return RedirectResponse("/game/chuni/", 303)
|
return RedirectResponse("/game/chuni/", 303)
|
||||||
|
|
||||||
|
async def update_stage(self, request: Request) -> bytes:
|
||||||
|
usr_sesh = self.validate_session(request)
|
||||||
|
if not usr_sesh:
|
||||||
|
return RedirectResponse("/gate/", 303)
|
||||||
|
|
||||||
|
form_data = await request.form()
|
||||||
|
new_system_voice: str = form_data.get("id")
|
||||||
|
|
||||||
|
if not new_system_voice:
|
||||||
|
return RedirectResponse("/gate/?e=4", 303)
|
||||||
|
|
||||||
|
if not await self.data.profile.update_stage(usr_sesh.user_id, usr_sesh.chunithm_version, new_system_voice):
|
||||||
|
return RedirectResponse("/gate/?e=999", 303)
|
||||||
|
|
||||||
|
return RedirectResponse("/game/chuni/", 303)
|
||||||
|
|
||||||
async def update_userbox(self, request: Request) -> bytes:
|
async def update_userbox(self, request: Request) -> bytes:
|
||||||
usr_sesh = self.validate_session(request)
|
usr_sesh = self.validate_session(request)
|
||||||
if not usr_sesh:
|
if not usr_sesh:
|
||||||
|
|||||||
4
titles/chuni/img/stage/.gitignore
vendored
Normal file
4
titles/chuni/img/stage/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
||||||
@@ -69,6 +69,7 @@ class ChuniReader(BaseReader):
|
|||||||
await self.read_system_voice(f"{dir}/systemVoice", this_opt_id)
|
await self.read_system_voice(f"{dir}/systemVoice", this_opt_id)
|
||||||
await self.read_unlock_challenge(f"{dir}/unlockChallenge")
|
await self.read_unlock_challenge(f"{dir}/unlockChallenge")
|
||||||
await self.read_linked_verse(f"{dir}/linkedVerse")
|
await self.read_linked_verse(f"{dir}/linkedVerse")
|
||||||
|
await self.read_stage(f"{dir}/stage", this_opt_id)
|
||||||
|
|
||||||
async def read_login_bonus(self, root_dir: str, opt_id: Optional[int] = None) -> None:
|
async def read_login_bonus(self, root_dir: str, opt_id: Optional[int] = None) -> None:
|
||||||
for root, dirs, files in walk(f"{root_dir}loginBonusPreset"):
|
for root, dirs, files in walk(f"{root_dir}loginBonusPreset"):
|
||||||
@@ -570,6 +571,33 @@ class ChuniReader(BaseReader):
|
|||||||
else:
|
else:
|
||||||
self.logger.warning(f"Failed to Linked VERSE {id}")
|
self.logger.warning(f"Failed to Linked VERSE {id}")
|
||||||
|
|
||||||
|
async def read_stage(self, stage_dir: str, opt_id: Optional[int] = None) -> None:
|
||||||
|
for root, dirs, files in walk(stage_dir):
|
||||||
|
for dir in dirs:
|
||||||
|
if path.exists(f"{root}/{dir}/Stage.xml"):
|
||||||
|
with open(f"{root}/{dir}/Stage.xml", "r", encoding='utf-8') as fp:
|
||||||
|
strdata = fp.read()
|
||||||
|
|
||||||
|
xml_root = ET.fromstring(strdata)
|
||||||
|
for name in xml_root.findall("name"):
|
||||||
|
id = name.find("id").text
|
||||||
|
name = name.find("str").text
|
||||||
|
for image in xml_root.findall("image"):
|
||||||
|
image_path = image.find("path").text
|
||||||
|
self.copy_image(image_path, f"{root}/{dir}", "titles/chuni/img/stage/")
|
||||||
|
default_have = xml_root.find("defaultHave").text == 'true'
|
||||||
|
disable_flag = xml_root.find("disableFlag") # may not exist in older data
|
||||||
|
is_enabled = True if (disable_flag is None or disable_flag.text == "false") else False
|
||||||
|
|
||||||
|
result = await self.data.static.put_stage(
|
||||||
|
self.version, id, name, image_path, is_enabled, default_have, opt_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
self.logger.info(f"Inserted stage {id}")
|
||||||
|
else:
|
||||||
|
self.logger.warning(f"Failed to insert stage {id}")
|
||||||
|
|
||||||
def copy_image(self, filename: str, src_dir: str, dst_dir: str) -> None:
|
def copy_image(self, filename: str, src_dir: str, dst_dir: str) -> None:
|
||||||
# Convert the image to webp so we can easily display it in the frontend
|
# Convert the image to webp so we can easily display it in the frontend
|
||||||
file_src = path.join(src_dir, filename)
|
file_src = path.join(src_dir, filename)
|
||||||
|
|||||||
@@ -477,6 +477,17 @@ class ChuniProfileData(BaseData):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
async def update_stage(self, user_id: int, version: int, new_stage: int) -> bool:
|
||||||
|
sql = profile.update((profile.c.user == user_id) & (profile.c.version == version)).values(
|
||||||
|
stageId=new_stage
|
||||||
|
)
|
||||||
|
result = await self.execute(sql)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
self.logger.warning(f"Failed to set user {user_id} stage")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def update_userbox(self, user_id: int, version: int, new_nameplate: int, new_trophy: int, new_trophy_sub_1: int, new_trophy_sub_2: int, new_character: int) -> bool:
|
async def update_userbox(self, user_id: int, version: int, new_nameplate: int, new_trophy: int, new_trophy_sub_1: int, new_trophy_sub_2: int, new_character: int) -> bool:
|
||||||
sql = profile.update((profile.c.user == user_id) & (profile.c.version == version)).values(
|
sql = profile.update((profile.c.user == user_id) & (profile.c.version == version)).values(
|
||||||
nameplateId=new_nameplate,
|
nameplateId=new_nameplate,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ events = Table(
|
|||||||
Column("name", String(255)),
|
Column("name", String(255)),
|
||||||
Column("startDate", TIMESTAMP, server_default=func.now()),
|
Column("startDate", TIMESTAMP, server_default=func.now()),
|
||||||
Column("enabled", Boolean, server_default="1"),
|
Column("enabled", Boolean, server_default="1"),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "eventId", name="chuni_static_events_uk"),
|
UniqueConstraint("version", "eventId", name="chuni_static_events_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -58,7 +58,7 @@ music = Table(
|
|||||||
Column("genre", String(255)),
|
Column("genre", String(255)),
|
||||||
Column("jacketPath", String(255)),
|
Column("jacketPath", String(255)),
|
||||||
Column("worldsEndTag", String(7)),
|
Column("worldsEndTag", String(7)),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "songId", "chartId", name="chuni_static_music_uk"),
|
UniqueConstraint("version", "songId", "chartId", name="chuni_static_music_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -74,7 +74,7 @@ charge = Table(
|
|||||||
Column("consumeType", Integer),
|
Column("consumeType", Integer),
|
||||||
Column("sellingAppeal", Boolean),
|
Column("sellingAppeal", Boolean),
|
||||||
Column("enabled", Boolean, server_default="1"),
|
Column("enabled", Boolean, server_default="1"),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "chargeId", name="chuni_static_charge_uk"),
|
UniqueConstraint("version", "chargeId", name="chuni_static_charge_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -92,7 +92,7 @@ avatar = Table(
|
|||||||
Column("isEnabled", Boolean, server_default="1"),
|
Column("isEnabled", Boolean, server_default="1"),
|
||||||
Column("defaultHave", Boolean, server_default="0"),
|
Column("defaultHave", Boolean, server_default="0"),
|
||||||
Column("sortName", String(255)),
|
Column("sortName", String(255)),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "avatarAccessoryId", name="chuni_static_avatar_uk"),
|
UniqueConstraint("version", "avatarAccessoryId", name="chuni_static_avatar_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -108,7 +108,7 @@ nameplate = Table(
|
|||||||
Column("isEnabled", Boolean, server_default="1"),
|
Column("isEnabled", Boolean, server_default="1"),
|
||||||
Column("defaultHave", Boolean, server_default="0"),
|
Column("defaultHave", Boolean, server_default="0"),
|
||||||
Column("sortName", String(255)),
|
Column("sortName", String(255)),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "nameplateId", name="chuni_static_nameplate_uk"),
|
UniqueConstraint("version", "nameplateId", name="chuni_static_nameplate_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -128,7 +128,7 @@ character = Table(
|
|||||||
Column("imagePath3", String(255)),
|
Column("imagePath3", String(255)),
|
||||||
Column("isEnabled", Boolean, server_default="1"),
|
Column("isEnabled", Boolean, server_default="1"),
|
||||||
Column("defaultHave", Boolean, server_default="0"),
|
Column("defaultHave", Boolean, server_default="0"),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "characterId", name="chuni_static_character_uk"),
|
UniqueConstraint("version", "characterId", name="chuni_static_character_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -143,7 +143,7 @@ trophy = Table(
|
|||||||
Column("rareType", Integer),
|
Column("rareType", Integer),
|
||||||
Column("isEnabled", Boolean, server_default="1"),
|
Column("isEnabled", Boolean, server_default="1"),
|
||||||
Column("defaultHave", Boolean, server_default="0"),
|
Column("defaultHave", Boolean, server_default="0"),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "trophyId", name="chuni_static_trophy_uk"),
|
UniqueConstraint("version", "trophyId", name="chuni_static_trophy_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -159,7 +159,7 @@ map_icon = Table(
|
|||||||
Column("iconPath", String(255)),
|
Column("iconPath", String(255)),
|
||||||
Column("isEnabled", Boolean, server_default="1"),
|
Column("isEnabled", Boolean, server_default="1"),
|
||||||
Column("defaultHave", Boolean, server_default="0"),
|
Column("defaultHave", Boolean, server_default="0"),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "mapIconId", name="chuni_static_mapicon_uk"),
|
UniqueConstraint("version", "mapIconId", name="chuni_static_mapicon_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -175,7 +175,7 @@ system_voice = Table(
|
|||||||
Column("imagePath", String(255)),
|
Column("imagePath", String(255)),
|
||||||
Column("isEnabled", Boolean, server_default="1"),
|
Column("isEnabled", Boolean, server_default="1"),
|
||||||
Column("defaultHave", Boolean, server_default="0"),
|
Column("defaultHave", Boolean, server_default="0"),
|
||||||
Column("opt", ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "voiceId", name="chuni_static_systemvoice_uk"),
|
UniqueConstraint("version", "voiceId", name="chuni_static_systemvoice_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -197,7 +197,7 @@ gachas = Table(
|
|||||||
Column("endDate", TIMESTAMP, server_default="2038-01-01 00:00:00.0"),
|
Column("endDate", TIMESTAMP, server_default="2038-01-01 00:00:00.0"),
|
||||||
Column("noticeStartDate", TIMESTAMP, server_default="2018-01-01 00:00:00.0"),
|
Column("noticeStartDate", TIMESTAMP, server_default="2018-01-01 00:00:00.0"),
|
||||||
Column("noticeEndDate", TIMESTAMP, server_default="2038-01-01 00:00:00.0"),
|
Column("noticeEndDate", TIMESTAMP, server_default="2038-01-01 00:00:00.0"),
|
||||||
Column("opt", ForeignKey("cm_static_opts.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT,ForeignKey("cm_static_opts.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "gachaId", "gachaName", name="chuni_static_gachas_uk"),
|
UniqueConstraint("version", "gachaId", "gachaName", name="chuni_static_gachas_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -218,7 +218,7 @@ cards = Table(
|
|||||||
Column("combo", Integer, nullable=False),
|
Column("combo", Integer, nullable=False),
|
||||||
Column("chain", Integer, nullable=False),
|
Column("chain", Integer, nullable=False),
|
||||||
Column("skillName", String(255), nullable=False),
|
Column("skillName", String(255), nullable=False),
|
||||||
Column("opt", ForeignKey("cm_static_opts.id", ondelete="SET NULL", onupdate="cascade")),
|
Column("opt", BIGINT, ForeignKey("cm_static_opts.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
UniqueConstraint("version", "cardId", name="chuni_static_cards_uk"),
|
UniqueConstraint("version", "cardId", name="chuni_static_cards_uk"),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -304,13 +304,13 @@ unlock_challenge = Table(
|
|||||||
Column("courseId4", Integer),
|
Column("courseId4", Integer),
|
||||||
Column("courseId5", Integer),
|
Column("courseId5", Integer),
|
||||||
UniqueConstraint(
|
UniqueConstraint(
|
||||||
"version", "unlockChallengeId", name="chuni_static_unlock_challenge_pk"
|
"version", "unlockChallengeId", name="chuni_static_unlock_challenge_uk"
|
||||||
),
|
),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
linked_verse: Table = Table(
|
linked_verse = Table(
|
||||||
"chuni_static_linked_verse",
|
"chuni_static_linked_verse",
|
||||||
metadata,
|
metadata,
|
||||||
Column("id", Integer, primary_key=True, nullable=False),
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
@@ -325,7 +325,24 @@ linked_verse: Table = Table(
|
|||||||
Column("courseId4", Integer),
|
Column("courseId4", Integer),
|
||||||
Column("courseId5", Integer),
|
Column("courseId5", Integer),
|
||||||
UniqueConstraint(
|
UniqueConstraint(
|
||||||
"version", "linkedVerseId", name="chuni_static_linked_verse_pk"
|
"version", "linkedVerseId", name="chuni_static_linked_verse_uk"
|
||||||
|
),
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
|
)
|
||||||
|
|
||||||
|
stage = Table(
|
||||||
|
"chuni_static_stage",
|
||||||
|
metadata,
|
||||||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
|
Column("version", Integer, nullable=False),
|
||||||
|
Column("stageId", Integer, nullable=False),
|
||||||
|
Column("name", String(255)),
|
||||||
|
Column("imagePath", String(255)),
|
||||||
|
Column("isEnabled", Boolean, server_default="1"),
|
||||||
|
Column("defaultHave", Boolean, server_default="0"),
|
||||||
|
Column("opt", BIGINT, ForeignKey("chuni_static_opt.id", ondelete="SET NULL", onupdate="cascade")),
|
||||||
|
UniqueConstraint(
|
||||||
|
"version", "stageId", name="chuni_static_stage_uk"
|
||||||
),
|
),
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
@@ -1307,3 +1324,54 @@ class ChuniStaticData(BaseData):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
return result.fetchall()
|
return result.fetchall()
|
||||||
|
|
||||||
|
async def put_stage(
|
||||||
|
self,
|
||||||
|
version: int,
|
||||||
|
stage_id: int,
|
||||||
|
name: str,
|
||||||
|
image_path: str,
|
||||||
|
is_enabled: int,
|
||||||
|
default_have: int,
|
||||||
|
opt_id: int = None
|
||||||
|
) -> Optional[int]:
|
||||||
|
|
||||||
|
sql = insert(stage).values(
|
||||||
|
version=version,
|
||||||
|
stageId=stage_id,
|
||||||
|
name=name,
|
||||||
|
imagePath=image_path,
|
||||||
|
isEnabled=is_enabled,
|
||||||
|
defaultHave=default_have,
|
||||||
|
opt=coalesce(stage.c.opt, opt_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
conflict = sql.on_duplicate_key_update(
|
||||||
|
name=name,
|
||||||
|
imagePath=image_path,
|
||||||
|
isEnabled=is_enabled,
|
||||||
|
defaultHave=default_have,
|
||||||
|
opt=coalesce(stage.c.opt, opt_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await self.execute(conflict)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return result.lastrowid
|
||||||
|
|
||||||
|
async def get_stages(self, version: int) -> Optional[List[Dict]]:
|
||||||
|
sql = stage.select(
|
||||||
|
and_(
|
||||||
|
stage.c.version == version,
|
||||||
|
stage.c.isEnabled == True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await self.execute(sql)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return result.fetchall()
|
||||||
|
|||||||
@@ -79,6 +79,12 @@
|
|||||||
<td><div id="system-voice-name">{{ system_voices[profile.voiceId]["name"] if system_voices|length > 0 else "Server DB needs upgraded or is not populated with necessary data" }}</div></td>
|
<td><div id="system-voice-name">{{ system_voices[profile.voiceId]["name"] if system_voices|length > 0 else "Server DB needs upgraded or is not populated with necessary data" }}</div></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if cur_version >= 18 %} <!-- STAGE introduced in X-VERSE -->
|
||||||
|
<tr>
|
||||||
|
<td>Stage:</td>
|
||||||
|
<td><div id="stage-name">{{ stages[profile.stageId]["name"] if stages|length > 0 else "Server DB needs upgraded or is not populated with necessary data" }}</div></td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -111,6 +117,21 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if cur_version >= 18 %} <!-- STAGE introduced in X-VERSE -->
|
||||||
|
<!-- STAGE SELECTION -->
|
||||||
|
<div class="col-lg-8 m-auto mt-3 scrolling-lists">
|
||||||
|
<div class="card bg-card rounded">
|
||||||
|
<button class="collapsible">Stage: {{ stages|length }}/{{ total_stages }}</button>
|
||||||
|
<div id="scrollable-stage" class="collapsible-content">
|
||||||
|
{% for item in stages.values() %}
|
||||||
|
<img id="stage-{{ item["id"] }}" style="padding: 8px 8px;" onclick="saveItem('stage', '{{ item["id"] }}', '{{ item["name"] }}')" src="img/stage/{{ item["imagePath"] }}" alt="{{ item["name"] }}">
|
||||||
|
<span id="stage-br-{{ loop.index }}"></span>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="col-lg-8 m-auto mt-3">
|
<div class="col-lg-8 m-auto mt-3">
|
||||||
<div class="card bg-card rounded">
|
<div class="card bg-card rounded">
|
||||||
<table class="table-large table-rowdistinct">
|
<table class="table-large table-rowdistinct">
|
||||||
@@ -201,6 +222,10 @@ items = {
|
|||||||
"map-icon": ["{{ map_icons|length }}", "{{ profile.mapIconId }}"],
|
"map-icon": ["{{ map_icons|length }}", "{{ profile.mapIconId }}"],
|
||||||
"system-voice":["{{ system_voices|length }}", "{{ profile.voiceId }}"]
|
"system-voice":["{{ system_voices|length }}", "{{ profile.voiceId }}"]
|
||||||
};
|
};
|
||||||
|
// STAGE introduced in X-VERSE
|
||||||
|
if ({{cur_version}} >= 18) {
|
||||||
|
items.stage = ["{{ stages|length }}", "{{ profile.stageId }}"]
|
||||||
|
}
|
||||||
types = Object.keys(items);
|
types = Object.keys(items);
|
||||||
|
|
||||||
function changeItem(type, id, name) {
|
function changeItem(type, id, name) {
|
||||||
|
|||||||
Reference in New Issue
Block a user