pack

Module containing Pack and all its subclasses.

It contains three submodules, and a sub-submodule:

  1. lihzahrd.terraria.utils.pack.pack, with the abstract base class;

  2. lihzahrd.terraria.utils.pack.primitive, for single units of data;

  3. lihzahrd.terraria.utils.pack.primitive.op, for adding operators to those single units of data;

  4. lihzahrd.terraria.utils.pack.composite, for composite data.

pack

Submodule for the base Pack abstract class.

class lihzahrd.terraria.utils.pack.pack.Pack

Block of adjacent data in a Terraria save file.

Instances of classes inheriting from this one always have:

To better support future Terraria updates, or just to allow more tinkering with the save files, inheritors of Pack should try to allow as much leeway as it makes sense to in reading and writing values that do not pass validation.

abstractmethod classmethod read(fp: FileProcessor, *, strict: bool = True, **kwargs: Any) PackRead[Self]

Read a value from the given FileProcessor, validate it, then use it to create an instance of this class.

Parameters:
  • fp – The FileProcessor to read from.

  • strict – Whether any ValidationError raised should be raised again, or ignored.

  • kwargs – Additional keyword arguments that may be used by implementations to do conditional processing.

Returns:

A PackRead instance with the created instance and validation information.

Raises:
  • ValidationError – If the read value is invalid and validation is strict.

  • ReadError – If the value could not be read.

exception ReadError

A failure of some kind in read(), preventing the object from being read.

abstractmethod write(fp: FileProcessor, *, strict: bool = True, **kwargs: Any) PackWrite[Self]

Validate the value represented by this instance, then write it to the given FileProcessor.

Parameters:
  • fp – The FileProcessor to write to.

  • strict – Whether any ValidationError raised should be raised again, or ignored.

  • kwargs – Additional keyword arguments that may be used by implementations to do conditional processing.

Returns:

A PackWrite instance with validation information.

Raises:
  • ValidationError – If the value to write is invalid and validation is strict.

  • WriteError – If the value could not be written.

exception WriteError

A failure of some kind in write(), preventing the object from being written.

abstractmethod validate(*, strict: bool = True, **kwargs: Any) bool

Validate the value represented by this instance.

Note

This method is separate from read() and write(), but can be called by them at their own discretion.

Parameters:
  • strict – Whether any ValidationError encountered should be re-raised (True) or ignored (False).

  • kwargs – Additional keyword arguments that may be used by implementations to do conditional processing.

Returns:

True if the value is valid, False if the value is invalid and validation isn’t strict.

Raises:

ValidationError – If the value is invalid and validation is strict.

exception ValidationError

A failure in validation of some kind; if this occurs, it means that the data represented by this instance would not be valid in a Terraria save file.

Tip

You can ignore errors of this type in read(), write(), and validate() by specifying strict=False as a keyword argument!

class lihzahrd.terraria.utils.pack.pack.PackRead(instance: Pck, valid: bool)

The result of a call to Pack.read().

The generic type Pck is the Pack instance returning this.

Used to bubble up validity information.

Attributes on this class are frozen.

instance: Pck

The created Pack instance representing the read value.

valid: bool

Whether the read value passed validation.

__bool__() bool
Returns:

Whether the read value is valid.

__str__() str
Returns:

The repr() of the instance, followed by either " (ok)" or " (invalid)" depending on valid.

class lihzahrd.terraria.utils.pack.pack.PackWrite(valid: bool)

The result of a call to Pack.write().

The generic type Pck is the Pack instance returning this.

Used to bubble up validity information.

Attributes on this class are frozen.

valid: bool

Whether the written value passed validation.

__bool__() bool
Returns:

Whether the written value is valid.

__str__() str
Returns:

Either "ok" or "invalid" depending on the value of valid.

primitive

Submodule for subclasses of Pack directly representing single units of data.

primitive

Submodule containing the abstract base class of Pack primitives.

class lihzahrd.terraria.utils.pack.primitive.primitive.PackPrimitive(value: Value)

A Pack representing a single unit of data of generic type InternalValue.

Automatically implements logging, validation, and structured results in __init__(), read(), write(), and validate(), but still requires the inheritor to specify what should be performed in each of those methods by implementing _read(), _write(), and _validate().

Tip

To alter the value of PackPrimitives, you can either use the methods specific to the inheriting class, like set_from_variant(), or directly operate on the value attribute, like this:

p.value = 67

Via this approach, you can set the value of the PackPrimitive to anything you want, including invalid values!

value: Value

The raw InternalValue represented by this instance.

_LOG: Logger

The logging.Logger to use to emit messages about the packing process.

Note

logging.Logger is not created as a global variable because in this way, logging can be filtered by section being processed instead of by class doing the processing, which arguably is more useful in debugging.

classmethod _validate(value: Value, **kwargs: Any) None

Validate the given InternalValue, raising ValidationError if it’s invalid.

Parameters:
  • value – The InternalValue to validate.

  • kwargs – Additional keyword arguments that may be used by implementations to do conditional processing.

Raises:

ValidationError – If value is not valid.

abstractmethod classmethod _read(fp: FileProcessor, **kwargs: Any) Value

Read a InternalValue from the given Packer.

Example

The usual implementation of this method will have a body like:

def _read(cls, fp: FileProcessor, **kwargs: Any) -> int:
    return fp.read_int()
Parameters:
  • fp – The FilePacker to read from.

  • kwargs – Additional keyword arguments that may be used by implementations to do conditional processing.

Returns:

The read InternalValue.

Raises:

ReadError – If the value could not be read.

abstractmethod classmethod _write(fp: FileProcessor, value: Value, **kwargs: Any) None

Write the given InternalValue to the given Packer.

Example

The usual implementation of this method will have a body like:

def _write(cls, fp: FileProcessor, value: int, **kwargs: Any) -> None:
    fp.write_int(value)
Parameters:
  • fp – The FilePacker to write to.

  • value – The InternalValue to write.

  • kwargs – Additional keyword arguments that may be used by implementations to do conditional processing.

Raises:

WriteError – If the value could not be written.

exception ValidationError(value: Value)

A ValidationError in which InternalValue can be stored.

_validate() is expected to raise this kind of error if the value represented by this class is invalid.

value: Value

The value which failed validation.

bool

Submodule containing processors for boolean types.

class lihzahrd.terraria.utils.pack.primitive.bool.PackBool(value: Value)

A PackPrimitive processing a BOOL as bool.

class lihzahrd.terraria.utils.pack.primitive.bool.PackTrue(value: Value)

A PackBool where only True values pass validation, and False values raise IsFalseError.

exception IsFalseError(value: Value)

The value is False.

int

Submodule containing processors for integer types.

class lihzahrd.terraria.utils.pack.primitive.int.PackInteger(value: Value)

A PackPrimitive processing integers.

On validation, it ensures that the represented value is between VALUE_MIN and VALUE_MAX, and raises OverflowError otherwise.

VALUE_MIN: int = NotImplemented

The minimum value that this type of integer can take.

VALUE_MAX: int = NotImplemented

The maximum value that this type of integer can take.

exception OverflowError(value: Value)

The processed value is out of representable range.

class lihzahrd.terraria.utils.pack.primitive.int.PackSByte(value: Value)

A PackInteger processing a SBYTE as int.

class lihzahrd.terraria.utils.pack.primitive.int.PackByte(value: Value)

A PackInteger processing a BYTE as int.

class lihzahrd.terraria.utils.pack.primitive.int.PackShort(value: Value)

A PackInteger processing a SHORT as int.

class lihzahrd.terraria.utils.pack.primitive.int.PackUShort(value: Value)

A PackInteger processing a USHORT as int.

class lihzahrd.terraria.utils.pack.primitive.int.PackInt(value: Value)

A PackInteger processing a INT as int.

class lihzahrd.terraria.utils.pack.primitive.int.PackUInt(value: Value)

A PackInteger processing a UINT as int.

class lihzahrd.terraria.utils.pack.primitive.int.PackLong(value: Value)

A PackInteger processing a LONG as int.

class lihzahrd.terraria.utils.pack.primitive.int.PackULong(value: Value)

A PackInteger processing a ULONG as int.

float

Submodule containing processors for floating-point numeric types.

class lihzahrd.terraria.utils.pack.primitive.float.PackFloating(value: Value)

A PackPrimitive processing floating-point numeric types.

class lihzahrd.terraria.utils.pack.primitive.float.PackFloat(value: Value)

A PackFloating processing a FLOAT as float.

class lihzahrd.terraria.utils.pack.primitive.float.PackDouble(value: Value)

A PackDouble processing a FLOAT as float.

coordinates

Submodule containing processors for Coordinates.

class lihzahrd.terraria.utils.pack.primitive.coordinates.PackCoordinatesInt(value: Value)

A PackPrimitive processing a pair of int as Coordinates.

exception OverflowError(value: Value)

The bounds are not within the representable range.

rectangle

Submodule containing processors for Rectangle.

class lihzahrd.terraria.utils.pack.primitive.rectangle.PackRectangleInt(value: Value)

A PackPrimitive processing four int as a Rectangle.

On validation, it ensures that the represented value is between INT_MIN and INT_MAX.

exception OverflowError(value: Value)

One of the Rectangle edges is not within representable range.

date

Submodule containing processors for datetime.

class lihzahrd.terraria.utils.pack.primitive.date.PackDatetime(value: Value)

A PackPrimitive processing a datetime.

bytes

Submodule containing processors for raw bytes.

class lihzahrd.terraria.utils.pack.primitive.bytes.PackUnknown(value: Value)

A PackPrimitive processing blocks of raw bytes.

When this class starts a read(), it keeps on reading until it reaches the address specified by the until keyword argument.

If instance of this class contain a non-zero amount of bytes, it will fail validation with UnknonwnBytesError (as that probably means that something went wrong during the parsing of the corresponding save file section), unless the acceptable keyword argument is True.

Tip

This behavior can be useful when you want to deliberately skip processing some sections of a save file, because for example they were loaded from a cache. This behavior can be useful when you want to deliberately skip processing some sections of a save file, because for example they were loaded from a cache.

Parameters:
  • until – The byte offset at which to stop reading.

  • acceptable – If True, no UnknownBytesError will be raised on validation.

exception UnknownBytesError(value: Value)

Unknown bytes are present.

str

Submodule containing processors for strings.

class lihzahrd.terraria.utils.pack.primitive.str.PackStrFixed(value: Value)

A PackPrimitive processing fixed-length strings.

On validation, it ensures that the represented value is exactly DATA_LEN bytes long, and raises InvalidLengthError otherwise.

DATA_LEN: int = NotImplemented

The expected length of the string.

exception InvalidLengthError(value: Value)

The string is not of the required length.

class lihzahrd.terraria.utils.pack.primitive.str.PackStrVariable(value: Value)

A PackPrimitive processing variable-length strings.

uuid_

Submodule containing processors for UUID.

class lihzahrd.terraria.utils.pack.primitive.uuid_.PackUUID(value: Value)

A PackPrimitive processing a UUID.

enumeration

Submodule containing processors for classes in enum.

class lihzahrd.terraria.utils.pack.primitive.enumeration.PackEnum(value: Value)

A PackPrimitive where all the valid values are known at class definition time, and are represented by the Enum ValidValue, whose value is of the generic type InternalValue.

On validation, it checks that the represented value is a valid value of ENUM, and raises UnknownVariantError otherwise.

ENUM: type[ValidValue] = NotImplemented

The type containing all the known values.

classmethod from_variant(variant: ValidValue) Self

Create an instance of this class from an Enum variant.

Parameters:

variant – The variant to use to create the instance.

Returns:

The created instance.

classmethod from_name(key) Self

Create an instance of this class from an Enum variant’s name.

Parameters:

key – The name to use to create the instance.

Returns:

The created instance.

variant() ValidValue

Convert this instance to the corresponding Enum variant.

Returns:

The created variant.

Raises:

ValueError – If the value does not correspond to any enum variant.

name() str

Convert this instance to the corresponding Enum variant name.

Returns:

The enum name.

set_from_variant(variant: ValidValue) None

Set the value of this class instance to the value of the given variant.

Parameters:

variant – The variant to use to set the value.

set_from_name(name: str) None

Set the value of this class instance to the value of the variant with the specified name.

Parameters:

name – The name to use to set the value.

exception UnknownVariantError(value: Value)

The specified value is not among the known values ENUM can take.

class lihzahrd.terraria.utils.pack.primitive.enumeration.PackFlags(value: Value)

A PackPrimitive where all the valid values are known at class definition time, and are represented by the Flag ValidValue, whose value is of the generic type InternalValue.

On validation, it checks that the represented value is a valid value of FLAGS, and raises UnknownVariantError otherwise.

FLAGS: type[ValidValue] = NotImplemented

The type containing all the known values.

exception UnknownFlagsError(value: Value)

The specified value is not among the known values FLAGS can take.

classmethod from_variant(variant: ValidValue) Self

Create an instance of this class from a Flag variant.

Parameters:

variant – The variant to use to create the instance.

Returns:

The created instance.

variant() ValidValue

Convert this instance to the corresponding Flag variant.

Returns:

The created variant.

Raises:

ValueError – If the value does not correspond to any enum variant.

set_from_variant(variant: ValidValue) None

Set the value of this class instance to the value of the given variant.

Parameters:

variant – The variant to use to set the value.

op

Module containing mixins to add various operators to classes inheriting from PackPrimitive.

Example

To allow instances of a class inheriting from PackInt to behave like regular int would, you can mixin OpInteger:

class WorldRevision(OpInteger, PackInt):
    ...

Allowing for code like the following:

p1: WorldRevision = WorldRevision.read(fp).instance
p2: WorldRevision = WorldRevision.read(fp).instance
p3: WorldRevision = p1 + p2
assert p3.value == p1.value + p2.value

equality

Submodule for OpEquality.

class lihzahrd.terraria.utils.pack.primitive.op.equality.OpEquality(value: Value)

Extension of PackPrimitive which adds equality operators based on value.

__eq__(other) Self
__ne__(other) Self

boolean

Submodule for OpBoolean.

class lihzahrd.terraria.utils.pack.primitive.op.boolean.OpBoolean(value: Value)

Extension of OpEquality which adds boolean operators based on value.

__bool__() bool
__and__(other: Any) Self
__iand__(other: Any) None
__or__(other: Any) Self
__ior__(other: Any) None
__xor__(other: Any) Self
__ixor__(other: Any) None
__invert__() Self

collection

Submodule for OpCollection.

class lihzahrd.terraria.utils.pack.primitive.op.collection.OpCollection(value: Value)

Extension of OpEquality which adds collection operators based on value.

__len__() int
__length_hint__() int
__getitem__(item) Any
__setitem__(key, value) None
__delitem__(key) None
__iter__() Iterator[Any]
__reversed__() Iterator[Any]
__contains__(item) bool

comparison

Submodule for OpComparison.

class lihzahrd.terraria.utils.pack.primitive.op.comparison.OpComparison(value: Value)

Extension of OpEquality which adds comparison operators based on value.

__gt__(other) Self
__ge__(other) Self
__lt__(other) Self
__le__(other) Self

number

Submodule for OpNumber.

class lihzahrd.terraria.utils.pack.primitive.op.number.OpNumber(value: Value)

Extension of OpComparison which adds number operators based on value.

Note

__pow__() and __ipow__() are not implemented due to ambiguity regarding how to handle the modulo parameter.

__neg__() Self
__pos__() Self
__abs__() Self
__add__(other) Self
__iadd__(other) None
__sub__(other) Self
__isub__(other) None
__mul__(other) Self
__imul__(other) None
__truediv__(other) Self
__itruediv__(other) None

integer

Submodule for OpInteger.

class lihzahrd.terraria.utils.pack.primitive.op.integer.OpInteger(value: Value)

Extension of both OpNumber and OpBoolean which adds integer operators based on value.

__int__() int
__index__() int
__floordiv__(other) Self
__ifloordiv__(other) None
__mod__(other) Self
__imod__(other) None
__lshift__(other) Self
__ilshift__(other) None
__rshift__(other) Self
__irshift__(other) None

floating

Submodule for OpFloating.

class lihzahrd.terraria.utils.pack.primitive.op.floating.OpFloating(value: Value)

Extension of OpNumber which adds floating-point operators based on value.

__float__() float
__complex__() complex
__round__(ndigits=None) Self
__trunc__() Self
__floor__() Self
__ceil__() Self

composite

Submodule for subclasses of Pack representing composite sections of data, composed of multiple underlying sub- Pack.

composite

Submodule for PackComposite.

class lihzahrd.terraria.utils.pack.composite.composite.PackComposite(*args: Pack, **kwargs)

A Pack representing an ordered and fixed-length set of heterogenous Pack items.

Automatically implements read(), write(), and validate() with logging, validation, and structured results, but requires the inheritor to define the fields that instances should contain, and specify the order they should be processed to via _fields().

abstractmethod __init__(*args: Pack, **kwargs)

Create a new instance of the PackComposite by determining the fields it will have with the given kwargs, then by setting the value of each to the arg with the same index.

For instances to have correct attribute suggestions in IDEs, the __init__() method of each PackComposite must be overridden.

The override should define a new instance-level attribute for each field, annotating it with the type of the field value, and assigning to it the value Ellipsis (which will be ignored by Field).

Warning

Not setting the value to Ellipsis will result in the type annotation becoming Any for IDEs!

Example

From FileMetadata:

@override
def __init__(self, *args: Pack, **kwargs):
    self.version: PackFileVersion = ...
    self.signature: PackFileSignature = ...
    self.kind: PackFileKind = ...
    self.revision: PackFileRevision = ...
    self.flags: PackFileFlags = ...

    super().__init__(*args, **kwargs)
Parameters:
  • kwargs – The arguments to pass to _fields() to determine which fields will exist on the instance.

  • args – The values to use for each field returned by _fields().

class Field(ty: type[Value])

A descriptor for one of the Pack values making up the composite object.

Necessary to allow read() to determine the class to call read() on.

If a field is attempted to be set to Ellipsis, the action is ignored; this is used to make instance-level type hinting prevail over the class-level descriptor access on IDEs.

__init__(ty: type[Value]) None

Create a new field.

You should call this as if defining a class-level variable.

The name of the field is determined via __set_name__().

Parameters:

ty – The type of the value to store in it.

container_name() str
Returns:

The name of the variable to use to store the actual value in.

abstractmethod classmethod _fields(**kwargs) list[Field[Self, Pack]]

Get a list of the fields that should be processed, in the order they should be processed.

Warning

Getters of the included properties must have a correct type annotation!

Parameters:

kwargs – Additional keyword arguments that may be used by implementations to do conditional processing.

Returns:

The property() that should be validated, read, or written, in the order these operations should be done.

_LOG = <Logger lihzahrd.terraria.utils.pack.composite.composite (WARNING)>

The logging.Logger to use to emit messages about the packing process.

count_array

Submodule for PackCountArray.

class lihzahrd.terraria.utils.pack.composite.count_array.PackCountArray(items: list[Item])

A Pack representing an ordered and variable-length set of homogeneous Pack items.

The serialization it expects is:

  1. Item count

  2. Item #1

  3. Item #2

Automatically implements read(), write(), and validate() with logging, validation, and structured results, but it requires the inheritor to define the way to read or write the item count by implementing _read_count() and _write_count().

On validation, if MAX_COUNT is not None, it ensures that the collection represented by this object is not larger than MAX_COUNT, and raises LimitExceededError otherwise.

__iter__() Iterator
Returns:

An iterator of the items in the collection.

ITEM: type[Pack]

The type of items to read or write.

abstractmethod classmethod _read_count(fp: FileProcessor) int

Read the amount of items to subsequently read to the collection.

Parameters:

fp – The lihzahrd.terraria.utils.file_processor.FileProcessor to read from.

Returns:

The number of items to read to the collection.

abstractmethod classmethod _write_count(fp: FileProcessor, count: int) None

Write the amount of items to subsequently write to the collection.

Parameters:
MAX_COUNT: int | None = None

The maximum number of items that this collection can contain.

Usually specified because of hardcoded limits in the Terraria save file format.

exception LimitExceededError

The collection has more items than how many are allowed by MAX_COUNT.

flag_array

Submodule for PackFlagArray.

class lihzahrd.terraria.utils.pack.composite.flag_array.PackFlagArray(items: list[Item])

A Pack representing an ordered and variable-length set of homogeneous Pack items.

The serialization it expects is:

  1. Boolean True (“there is an item afterward”)

  2. Item #1

  3. Boolean True (“there is an item afterward”)

  4. Item #2

  5. Boolean False (“items have ended”)

Automatically implements read(), write(), and validate() with logging, validation, and structured results.

__iter__() Iterator
Returns:

An iterator of the items in the collection.

ITEM: type[Pack]

The type of items to read or write.