Source code for esp_parser.records._wrld

#!/usr/bin/env python3
#
#  _wrld.py
"""
WRLD record type.
"""
#
#  Copyright © 2024 Dominic Davis-Foster <dominic@davis-foster.co.uk>
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in all
#  copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
#  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
#  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
#  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
#  OR OTHER DEALINGS IN THE SOFTWARE.
#

# stdlib
import struct
from io import BytesIO
from typing import Iterator, NamedTuple, Type

# 3rd party
from typing_extensions import Self

# this package
from esp_parser.subrecords import EDID
from esp_parser.types import CStringRecord, Float32Record, FormIDRecord, Record, RecordType, Uint8Record
from esp_parser.utils import namedtuple_qualname_repr

__all__ = ["WRLD"]


[docs]class WRLD(Record): """ Worldspace. """
[docs] class FULL(CStringRecord): """ Name. """
[docs] class XEZN(FormIDRecord): """ Encounter Zone. Form ID of an :class:`~.ECZN` record. """
[docs] class WNAM(FormIDRecord): """ Parent worldspace. Form ID of a :class:`~.WRLD` record. """
[docs] class PNAM(NamedTuple): """ Parent worldspace flags. """ flags: int unknown: bytes
[docs] @classmethod def parse(cls: Type[Self], raw_bytes: BytesIO) -> Self: """ Parse this subrecord. :param raw_bytes: Raw bytes for this record """ assert raw_bytes.read(2) == b"\x02\x00" # size field return cls(*struct.unpack("<Bs", raw_bytes.read(2)))
[docs] def unparse(self) -> bytes: """ Turn this subrecord back into raw bytes for an ESP file. """ return b"PNAM\x02\x00" + struct.pack("<B", self.flags) + self.unknown
def __repr__(self) -> str: return namedtuple_qualname_repr(self)
[docs] class CNAM(FormIDRecord): """ Climate. Form ID of a :class:`~.CLMT` record. """
[docs] class NAM2(FormIDRecord): """ Water. Form ID of a :class:`~.WATR` record. """
[docs] class NAM3(FormIDRecord): """ LOD water type. Form ID of a :class:`~.WATR` record. """
[docs] class NAM4(Float32Record): """ LOD water height. """
[docs] class DNAM(NamedTuple): """ Land Data. """ default_land_height: float default_water_height: float
[docs] @classmethod def parse(cls: Type[Self], raw_bytes: BytesIO) -> Self: """ Parse this subrecord. :param raw_bytes: Raw bytes for this record """ assert raw_bytes.read(2) == b"\x08\x00" # size field return cls(*struct.unpack(">ff", raw_bytes.read(8)))
[docs] def unparse(self) -> bytes: """ Turn this subrecord back into raw bytes for an ESP file. """ return b"DNAM\x08\x00" + struct.pack(">ff", *self)
def __repr__(self) -> str: return namedtuple_qualname_repr(self)
[docs] class ICON(CStringRecord): """ Large icon filename. """
[docs] class MICO(CStringRecord): """ Small icon filename. """
[docs] class MNAM(NamedTuple): """ Map Data. """ useable_x_size: int useable_y_size: int nw_x_coord: int nw_y_coord: int se_x_coord: int se_y_coord: int
[docs] @classmethod def parse(cls: Type[Self], raw_bytes: BytesIO) -> Self: """ Parse this subrecord. :param raw_bytes: Raw bytes for this record """ assert raw_bytes.read(2) == b"\x10\x00" # size field return cls(*struct.unpack(">iihhhh", raw_bytes.read(16)))
[docs] def unparse(self) -> bytes: """ Turn this subrecord back into raw bytes for an ESP file. """ return b"MNAM\x10\x00" + struct.pack(">iihhhh", *self)
def __repr__(self) -> str: return namedtuple_qualname_repr(self)
[docs] class ONAM(NamedTuple): """ World Map Offset Data. """ world_map_scale: float cell_x_offset: float cell_y_offset: float
[docs] @classmethod def parse(cls: Type[Self], raw_bytes: BytesIO) -> Self: """ Parse this subrecord. :param raw_bytes: Raw bytes for this record """ assert raw_bytes.read(2) == b"\x0c\x00" # size field return cls(*struct.unpack(">fff", raw_bytes.read(12)))
[docs] def unparse(self) -> bytes: """ Turn this subrecord back into raw bytes for an ESP file. """ return b"ONAM\x0c\x00" + struct.pack(">fff", *self)
def __repr__(self) -> str: return namedtuple_qualname_repr(self)
[docs] class INAM(FormIDRecord): """ Image space. Form ID of an :class:`~.IMGS` record. """
[docs] class DATA(Uint8Record): """ Flags. See https://tes5edit.github.io/fopdoc/Fallout3/Records/WRLD.html """
[docs] class NAM0(NamedTuple): """ Min Object Bounds. """ x: float y: float
[docs] @classmethod def parse(cls: Type[Self], raw_bytes: BytesIO) -> Self: """ Parse this subrecord. :param raw_bytes: Raw bytes for this record """ assert raw_bytes.read(2) == b"\x08\x00" # size field return cls(*struct.unpack("<ff", raw_bytes.read(8)))
[docs] def unparse(self) -> bytes: """ Turn this subrecord back into raw bytes for an ESP file. """ return b"NAM0\x08\x00" + struct.pack("<ff", *self)
def __repr__(self) -> str: return namedtuple_qualname_repr(self)
[docs] class NAM9(NAM0): """ Max Object Bounds. """
[docs] def unparse(self) -> bytes: """ Turn this subrecord back into raw bytes for an ESP file. """ return b"NAM9\x08\x00" + struct.pack("<ff", *self)
RecordType.register(PNAM) RecordType.register(MNAM) RecordType.register(DNAM) RecordType.register(ONAM) RecordType.register(NAM0) RecordType.register(NAM9)
[docs] class ZNAM(FormIDRecord): """ Music. Form ID of a :class:`~.MUSC` record. """
[docs] class NNAM(CStringRecord): """ Canopy Shadow. """
[docs] class XNAM(CStringRecord): """ Water Noise Texture. """
# class IMPS(RecordType): # """ # Swapped Impact. # """ # class IMPF(RecordType): # """ # Footstep Material. # # https://tes5edit.github.io/fopdoc/FalloutNV/Records/Subrecords/IMPF.html # """ # class OFST(RecordType): # """ # Offset Data. # """
[docs] @classmethod def parse_subrecords(cls, raw_bytes: BytesIO) -> Iterator[RecordType]: """ Parse this record's subrecords. :param raw_bytes: Raw bytes for this record's subrecords """ while True: record_type = raw_bytes.read(4) if not record_type: break if record_type == b"EDID": yield EDID.parse(raw_bytes) elif record_type in { b"CNAM", b"DATA", b"DNAM", b"FULL", b"ICON", b"IMPF", b"IMPS", b"INAM", b"MICO", b"MNAM", b"NAM0", b"NAM2", b"NAM3", b"NAM4", b"NAM9", b"NNAM", b"OFST", b"ONAM", b"PNAM", b"WNAM", b"XEZN", b"XNAM", b"ZNAM", }: yield getattr(cls, record_type.decode()).parse(raw_bytes) else: raise NotImplementedError(record_type)