Source code for scfile.core.content

"""
Shared content data containers for handlers.
Defines data structures that hold parsed file contents.
"""

from abc import ABC
from collections import defaultdict
from dataclasses import MISSING, dataclass, field, fields
from typing import Generic, TypeAlias, TypeVar, cast
from uuid import UUID

from scfile.enums import FileType
from scfile.structures.models import ModelFlags, ModelScene
from scfile.structures.regions import RegionChunk
from scfile.structures.textures import CubemapTexture, DefaultTexture, TextureType


NbtValue: TypeAlias = None | int | float | bytes | str | list[int] | list["NbtValue"] | dict[str, "NbtValue"]


[docs] @dataclass class BaseContent(ABC): """Base class for file content types.""" type: FileType = field(default=FileType.NONE)
[docs] def reset(self): for f in fields(self): if f.default_factory is not MISSING: setattr(self, f.name, f.default_factory()) elif f.default is not MISSING: setattr(self, f.name, f.default)
ContentType = TypeVar("ContentType", bound=BaseContent)
[docs] @dataclass class ModelContent(BaseContent): """Content container for 3D models.""" type: FileType = field(default=FileType.MODEL) version: float = 0.0 flags: ModelFlags = field(default_factory=lambda: defaultdict(bool)) scene: ModelScene = field(default_factory=ModelScene)
[docs] @dataclass class TextureContent(BaseContent, Generic[TextureType]): """Content container for textures (2D or cubemap).""" type: FileType = field(default=FileType.TEXTURE) width: int = 0 height: int = 0 mipmap_count: int = 0 format: bytes = field(default_factory=bytes) texture: TextureType = field(default_factory=lambda: cast(TextureType, DefaultTexture())) @property def is_cubemap(self) -> bool: return isinstance(self.texture, CubemapTexture) @property def is_compressed(self) -> bool: return self.fourcc in (b"DXT1", b"DXT3", b"DXT5", b"ATI2", b"DX10") @property def fourcc(self) -> bytes: match self.format: case b"DXN_XY": return b"ATI2" case b"RGBA32F": return b"DX10" case _: return self.format
[docs] @dataclass class ImageContent(BaseContent): """Content container for images.""" type: FileType = field(default=FileType.IMAGE) image: bytes = field(default_factory=bytes)
[docs] @dataclass class TexarrContent(BaseContent): """Content container for texture arrays.""" type: FileType = field(default=FileType.TEXARR) count: int = 0 textures: list[tuple[str, bytes]] = field(default_factory=list)
[docs] @dataclass class NbtContent(BaseContent): """Content container for NBT (Named Binary Tag) data.""" type: FileType = field(default=FileType.NBT) value: NbtValue = None
[docs] @dataclass class RegionContent(BaseContent): """Content container for regions (world terrain).""" type: FileType = field(default=FileType.REGION) rx: int = 0 rz: int = 0 offsets: list[int] = field(default_factory=list) counts: list[int] = field(default_factory=list) uuid: list[UUID] = field(default_factory=list) chunks: list[RegionChunk] = field(default_factory=list)