From 6cc21efa71f2a90ab0dee6c4d21c9819e5f3ef0f Mon Sep 17 00:00:00 2001 From: Danila Date: Thu, 14 Mar 2024 15:16:43 +0300 Subject: [PATCH] feat(tags): support for new texture and movie clip tags --- system/lib/features/sc/decode.py | 6 +++--- system/lib/objects/movie_clip.py | 5 ++++- system/lib/objects/texture.py | 22 +++++++++++++++++++-- system/lib/swf.py | 33 +++++++++++++++++++------------- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/system/lib/features/sc/decode.py b/system/lib/features/sc/decode.py index 3b73807..b9f0273 100644 --- a/system/lib/features/sc/decode.py +++ b/system/lib/features/sc/decode.py @@ -59,7 +59,7 @@ def decode_and_render_objects(): files = os.listdir(input_folder) for file in files: - if file.endswith("_tex.sc"): + if file.endswith("_tex.sc") or not file.endswith(".sc"): continue try: @@ -99,9 +99,9 @@ def get_file_basename(swf: SupercellSWF): def _create_objects_output_folder(output_folder: Path, base_name: str) -> Path: objects_output_folder = output_folder / base_name - if os.path.isdir(objects_output_folder): + if objects_output_folder.exists(): shutil.rmtree(objects_output_folder) - os.mkdir(objects_output_folder) + objects_output_folder.mkdir(parents=True) return objects_output_folder diff --git a/system/lib/objects/movie_clip.py b/system/lib/objects/movie_clip.py index cc69f2a..148c635 100644 --- a/system/lib/objects/movie_clip.py +++ b/system/lib/objects/movie_clip.py @@ -62,6 +62,9 @@ def load(self, swf: "SupercellSWF", tag: int): if tag in (3, 14): pass else: + if tag == 49: + swf.reader.read_char() # unknown + transforms_count = swf.reader.read_uint() for i in range(transforms_count): @@ -79,7 +82,7 @@ def load(self, swf: "SupercellSWF", tag: int): bind_id = swf.reader.read_ushort() # bind_id self.binds.append(bind_id) - if tag in (12, 35): + if tag in (12, 35, 49): for i in range(binds_count): blend = swf.reader.read_char() # blend self.blends.append(blend) diff --git a/system/lib/objects/texture.py b/system/lib/objects/texture.py index a8944a7..a3b2a56 100644 --- a/system/lib/objects/texture.py +++ b/system/lib/objects/texture.py @@ -1,5 +1,9 @@ +from __future__ import annotations + import os +from typing import TYPE_CHECKING +import zstandard from PIL import Image from system.lib.images import ( @@ -10,6 +14,9 @@ ) from system.lib.pvr_tex_tool import get_image_from_ktx_data +if TYPE_CHECKING: + from system.lib.swf import SupercellSWF + class SWFTexture: def __init__(self): @@ -17,12 +24,15 @@ def __init__(self): self.height = 0 self.pixel_type = -1 + self.khronos_texture_filename: str | None = None - self.image: Image.Image + self.image: Image.Image | None = None - def load(self, swf, tag: int, has_texture: bool): + def load(self, swf: SupercellSWF, tag: int, has_texture: bool): if tag == 45: khronos_texture_length = swf.reader.read_int() + elif tag == 47: + self.khronos_texture_filename = swf.reader.read_string() self.pixel_type = swf.reader.read_char() self.width, self.height = (swf.reader.read_ushort(), swf.reader.read_ushort()) @@ -35,6 +45,14 @@ def load(self, swf, tag: int, has_texture: bool): khronos_texture_data = swf.reader.read(khronos_texture_length) self.image = get_image_from_ktx_data(khronos_texture_data) return + elif tag == 47: + with open( + swf.filepath.parent / self.khronos_texture_filename, "rb" + ) as file: + decompressor = zstandard.ZstdDecompressor() + decompressed = decompressor.decompress(file.read()) + self.image = get_image_from_ktx_data(decompressed) + return img = Image.new( get_format_by_pixel_type(self.pixel_type), (self.width, self.height) diff --git a/system/lib/swf.py b/system/lib/swf.py index c2bc392..9645b61 100644 --- a/system/lib/swf.py +++ b/system/lib/swf.py @@ -1,4 +1,5 @@ import os +from pathlib import Path from typing import List, Tuple from loguru import logger @@ -14,15 +15,15 @@ class SupercellSWF: - TEXTURES_TAGS = (1, 16, 28, 29, 34, 19, 24, 27, 45) + TEXTURES_TAGS = (1, 16, 28, 29, 34, 19, 24, 27, 45, 47) SHAPES_TAGS = (2, 18) - MOVIE_CLIPS_TAGS = (3, 10, 12, 14, 35) + MOVIE_CLIPS_TAGS = (3, 10, 12, 14, 35, 49) TEXTURE_EXTENSION = "_tex.sc" def __init__(self): - self.filename: str - self.reader: Reader + self.filename: str | None = None + self.reader: Reader | None = None self.use_lowres_texture: bool = False @@ -32,8 +33,8 @@ def __init__(self): self.xcod_writer = Writer("big") - self._filepath: str - self._uncommon_texture_path: str + self._filepath: Path | None = None + self._uncommon_texture_path: str | os.PathLike | None = None self._lowres_suffix: str = DEFAULT_LOWRES_SUFFIX self._highres_suffix: str = DEFAULT_HIGHRES_SUFFIX @@ -50,13 +51,13 @@ def __init__(self): self._export_names: List[str] = [] self._matrix_banks: List[MatrixBank] = [] - self._matrix_bank: MatrixBank + self._matrix_bank: MatrixBank | None = None def load(self, filepath: str | os.PathLike) -> Tuple[bool, bool]: - self._filepath = str(filepath) + self._filepath = Path(filepath) texture_loaded, use_lzham = self._load_internal( - self._filepath, self._filepath.endswith("_tex.sc") + self._filepath, self._filepath.name.endswith("_tex.sc") ) if not texture_loaded: @@ -65,12 +66,14 @@ def load(self, filepath: str | os.PathLike) -> Tuple[bool, bool]: self._uncommon_texture_path, True ) else: - texture_path = self._filepath[:-3] + SupercellSWF.TEXTURE_EXTENSION + texture_path = str(self._filepath)[:-3] + SupercellSWF.TEXTURE_EXTENSION texture_loaded, use_lzham = self._load_internal(texture_path, True) return texture_loaded, use_lzham - def _load_internal(self, filepath: str, is_texture_file: bool) -> Tuple[bool, bool]: + def _load_internal( + self, filepath: str | os.PathLike, is_texture_file: bool + ) -> Tuple[bool, bool]: self.filename = os.path.basename(filepath) logger.info(locale.collecting_inf % self.filename) @@ -180,12 +183,12 @@ def _load_tags(self, is_texture_file: bool) -> bool: elif tag == 30: self._use_uncommon_texture = True highres_texture_path = ( - self._filepath[:-3] + str(self._filepath)[:-3] + self._highres_suffix + SupercellSWF.TEXTURE_EXTENSION ) lowres_texture_path = ( - self._filepath[:-3] + str(self._filepath)[:-3] + self._lowres_suffix + SupercellSWF.TEXTURE_EXTENSION ) @@ -231,3 +234,7 @@ def get_display_object( def get_matrix_bank(self, index: int) -> MatrixBank: return self._matrix_banks[index] + + @property + def filepath(self) -> Path: + return self._filepath