152 lines
4.9 KiB
Python
152 lines
4.9 KiB
Python
"""
|
|
Copyright (C) 2025 283375
|
|
|
|
This file is part of "arcaea-apk-assets" (stated as "this program" below).
|
|
|
|
This program is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
Foundation, either version 3 of the License, or (at your option) any later
|
|
version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program. If not, see <https://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from ._shared import blank_str_to_none
|
|
from .defs import ARCAEA_LANGUAGE_KEYS, Pack, PackLocalization
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class PacklistFormatError(Exception):
|
|
pass
|
|
|
|
|
|
class ArcaeaPacklistParser:
|
|
@staticmethod
|
|
def _assert_root_content(root: Any):
|
|
if not isinstance(root, dict):
|
|
msg = f"packlist root should be `dict`, got {type(root)}"
|
|
raise PacklistFormatError(msg)
|
|
|
|
packs = root.get("packs")
|
|
if packs is None:
|
|
msg = "`packs` field does not exist"
|
|
raise PacklistFormatError(msg)
|
|
|
|
if not isinstance(packs, list):
|
|
msg = f"`packs` field should be `list`, got {type(packs)}"
|
|
raise PacklistFormatError(msg)
|
|
|
|
@staticmethod
|
|
def _assert_pack_object(obj: Any):
|
|
if not isinstance(obj, dict):
|
|
msg = f"A pack object should be `dict`, got {type(obj)}"
|
|
raise PacklistFormatError(msg)
|
|
|
|
id_ = obj.get("id")
|
|
if not isinstance(id_, str):
|
|
msg = f"`id` attribute of a pack should be `str`, got value {id_!r}"
|
|
raise PacklistFormatError(msg)
|
|
|
|
@classmethod
|
|
def items(
|
|
cls, packlist_content: dict, *, skip_asserts: bool = False
|
|
) -> list[Pack | PackLocalization]:
|
|
try:
|
|
cls._assert_root_content(packlist_content)
|
|
except PacklistFormatError as e:
|
|
if skip_asserts:
|
|
logger.exception("Error skipped during packlist parsing:")
|
|
return []
|
|
|
|
raise e
|
|
|
|
packs = packlist_content["packs"]
|
|
results: list[Pack | PackLocalization] = [
|
|
Pack(
|
|
id="single",
|
|
name="Memory Archive",
|
|
description=None,
|
|
section=None,
|
|
plus_character=None,
|
|
append_parent_id=None,
|
|
)
|
|
]
|
|
|
|
for pack in packs:
|
|
try:
|
|
cls._assert_pack_object(pack)
|
|
except PacklistFormatError as e:
|
|
if skip_asserts:
|
|
logger.exception("Error skipped during packlist parsing:")
|
|
continue
|
|
|
|
raise e
|
|
|
|
name_localized = pack.get("name_localized", {})
|
|
description_localized = pack.get("description_localized", {})
|
|
|
|
id_ = pack["id"]
|
|
name = blank_str_to_none(name_localized.get("en"))
|
|
description = blank_str_to_none(description_localized.get("en"))
|
|
section = blank_str_to_none(pack.get("section"))
|
|
append_parent_id = pack.get("pack_parent")
|
|
plus_character = (
|
|
pack["plus_character"] if pack.get("plus_character", -1) > -1 else None
|
|
)
|
|
|
|
results.append(
|
|
Pack(
|
|
id=id_,
|
|
name=name,
|
|
description=description,
|
|
section=section,
|
|
plus_character=plus_character,
|
|
append_parent_id=append_parent_id,
|
|
)
|
|
)
|
|
|
|
for lang_key in ARCAEA_LANGUAGE_KEYS:
|
|
name_l10n = blank_str_to_none(name_localized.get(lang_key))
|
|
description_l10n = blank_str_to_none(
|
|
description_localized.get(lang_key)
|
|
)
|
|
|
|
if name_l10n or description_l10n:
|
|
results.append(
|
|
PackLocalization(
|
|
id=id_,
|
|
lang=lang_key,
|
|
name=name_l10n,
|
|
description=description_l10n,
|
|
)
|
|
)
|
|
|
|
return results
|
|
|
|
@classmethod
|
|
def packs(cls, packlist_content: dict, *, skip_asserts: bool = False) -> list[Pack]:
|
|
return [
|
|
item
|
|
for item in cls.items(packlist_content, skip_asserts=skip_asserts)
|
|
if isinstance(item, Pack)
|
|
]
|
|
|
|
@classmethod
|
|
def pack_localizations(
|
|
cls, packlist_content: dict, *, skip_asserts: bool = False
|
|
) -> list[PackLocalization]:
|
|
return [
|
|
item
|
|
for item in cls.items(packlist_content, skip_asserts=skip_asserts)
|
|
if isinstance(item, PackLocalization)
|
|
]
|