autoangel

AutoAngel is a general-purpose library designed to make it easy to work with angelica engine game files.

It supports the following file formats:

Quick Start

Working with elements.data

Let's start with importing autoangel:

import autoangel

Now you can load any elements.data you want using read_elements:

data = autoangel.read_elements('/path/to/elements.data')

By default read_elements will try to use one of the bundled config. This should work for you, if you don't use exotic game version (otherwise, you should load config with read_elements_config and pass it manually).

You can inspect data:

print(f'Version: {data.version}')
print(f'Number of lists: {len(data)}')

You can explore all the entries among all the lists. For example:

weapons_list = data[3]

# print list name
print(f'List: {weapons_list.config.caption}')

# print first 10 entries in list
for i in range(10):
  weapon = weapons_list[i]
  print(f'ID: {weapon.ID}, name: {weapon.Name}')

You can also modify anything you want like changing durability of all the weapons:

for weapon in weapons_list:
  weapon.durability_min = weapon.durability_max = 99999

All the modifications won't affect original elements.data until you save it:

data.save('elements2.data')

Working with pck/pkx

You can load a pck package using read_pck:

import autoangel

# Load a single pck file
package = autoangel.read_pck('/path/to/package.pck')

# Load a pck file with its corresponding pkx file
package = autoangel.read_pck('/path/to/package.pck', '/path/to/package.pkx')

Once you have a PckPackage object, you can explore its contents:

# Get a list of all files in the package
file_list = package.file_list()
print(f'Number of files: {len(file_list)}')

# Find files with a specific prefix
textures = package.find_prefix('textures/')
print(f'Number of texture files: {len(textures)}')

# Get the content of a specific file
file_content = package.get_file('path/to/file.txt')
if file_content is not None:
    print(f'File content: {file_content.decode("utf-8")}')
else:
    print('File not found')
1from .autoangel import *
2
3__doc__ = autoangel.__doc__
4if hasattr(autoangel, "__all__"):
5    __all__ = autoangel.__all__
class Bone:

A single bone in a skeleton.

children: List[int]

Indices of child bones.

is_fake: bool

Whether this bone is a fake (non-rendering) bone.

is_flipped: bool

Whether this bone is flipped (mirrored axis).

mat_bone_init: List[float]

Inverse bind-pose transform matrix (column-major, 4x4 = 16 floats).

mat_relative: List[float]

Relative transform matrix (column-major, 4x4 = 16 floats).

name: str

Bone name.

parent: int

Parent bone index (-1 for a root bone).

class BoneScaleEntry:

Bone scale entry from an ECM model.

Old format: scale is (scale_x, scale_y, scale_z) and scale_type is populated. New (BoneScaleEx) format: scale is (len, thick, whole) and scale_type is None.

bone_index: int

Index of the bone this scale applies to.

scale: Tuple[float, float, float]

Scale triple — meaning depends on format (see class docstring).

scale_type: int | None

Old-format scale-type tag; None for the new BoneScaleEx format.

class BoneTrack:

Per-bone animation track data.

bone_id: int

Bone identifier.

position: Track

Position track for this bone.

rotation: Track

Rotation track for this bone.

class ChildModel:

Child model attachment from an ECM model.

cc_name: str

Counterpart hook name on the child model.

hh_name: str

Hook name on the parent skeleton (e.g. HH_lefthandweapon).

name: str

Logical attachment slot name (e.g. wq_l, wq_r).

path: str

Engine-relative path to the child ECM.

class EcmEvent:

A visual/sound event triggered during animation or as persistent CoGfx.

event_type determines which optional fields are populated: 100 = GFX (gfx_scale / gfx_speed), 101 = Sound (volume / min_dist / max_dist / force_2d / is_loop).

bind_parent: bool

If true, the spawned effect follows the bone; otherwise frozen at spawn world position.

event_type: int

Event-type id (100 = GFX, 101 = Sound, 102+ = engine-internal types).

fade_out: int

Fade-out duration in milliseconds.

force_2d: bool | None

Sound events only: if true, plays as 2D (no spatial positioning).

fx_file_path: str

Engine-relative path to the GFX (event_type=100) or sound (101) file.

gfx_scale: float | None

GFX events only: scale multiplier for the spawned effect.

gfx_speed: float | None

GFX events only: playback-rate multiplier.

hook_name: str

Skeleton attachment-point name (typically HH_*); empty if unset.

hook_offset: Tuple[float, float, float]

Local-space offset on the hook bone.

hook_pitch: float

Pitch rotation on the hook (radians).

hook_rot: float

Roll rotation on the hook (radians).

hook_yaw: float

Yaw rotation on the hook (radians).

is_loop: bool | None

Sound events only: if true, sound loops.

max_dist: float | None

Sound events only: maximum audible distance.

min_dist: float | None

Sound events only: minimum audible distance.

once: bool

If true, the event fires only once per clip iteration.

start_time: int

Start time in milliseconds (0 if unset).

time_span: int

Lifetime in milliseconds; -1 = infinite.

use_model_alpha: bool

If true, the effect inherits the parent model's alpha.

volume: int | None

Sound events only: playback volume.

class EcmModel:

Parsed ECM (composite model) file.

additional_skins: List[str]
bone_scale_count: int

Number of bone scale entries.

child_count: int

Number of child-model attachments.

co_gfx_count: int

Number of persistent CoGfx events.

def co_gfx_fx_file_path(self, i: int) -> str:

FX file path of persistent CoGfx event at index i.

combine_action_count: int

Number of combined actions.

def combine_action_event_count(self, i: int) -> int:

Number of events in combined action at index i.

def combine_action_loop_count(self, i: int) -> int:

Loop count of combined action at index i.

def combine_action_name(self, i: int) -> str:

Name of combined action at index i.

def_play_speed: float
dest_blend: int
def get_bone_scale(self, i: int) -> BoneScaleEntry | None:

Return the bone-scale entry at i, or None if out of bounds.

def get_child(self, i: int) -> ChildModel | None:

Return the child-model entry at i, or None if out of bounds.

def get_event(self, action_idx: int, event_idx: int) -> EcmEvent | None:

Return the event at (action_idx, event_idx), or None if either index is out of bounds.

new_bone_scale: bool

Whether BoneScaleEx (new) format is used for bone scaling.

org_color: int

Original color as ARGB hex value.

outer_floats: List[float]
scale_base_bone: str | None
skin_model_path: str

Path to the skin model (SMD) file.

src_blend: int
version: int
class ElementBody:

Typed body for a GFX element. Accessed via GfxElement.body.

Instances are always one of the nested variant classes (ElementBody.Decal, ElementBody.Trail, ..., ElementBody.Unknown) — ElementBody itself is the common base. Narrow with isinstance().

class ElementBody.Container(ElementBody):

Body of a GfxContainer element (type 200) — nested .gfx reference.

dummy_use_g_scale: bool | None
gfx_path: str
loop_flag: bool | None
out_color: bool | None
play_speed: float | None
class ElementBody.Decal(ElementBody):

Body of a Decal element (types 100 / 101 / 102).

grnd_norm_only: bool | None
height: float
match_surface: bool | None
max_extent: float | None
no_scale: Tuple[bool, bool] | None
org_pt: Tuple[float, float] | None
rot_from_view: bool
screen_space: bool | None
surface_use_parent_dir: bool | None
width: float
yaw_effect: bool | None
z_offset: float | None
class ElementBody.GridDecal3D(ElementBody):

Body of a GridDecal3D element (type 210) — freeform w × h vertex-grid decal.

aff_by_scl: bool | None
always_on_ground: bool | None
animation_keys: List[GridAnimKey]
grid_size: float
h_number: int
offset_height: float | None
rot_from_view: bool | None
vertices: List[GridVertex]
w_number: int
z_offset: float | None
class ElementBody.Light(ElementBody):

Body of a Light element (type 130) — dynamic light source (D3DLIGHT9-style parameters).

ambient: int
attenuation0: float
attenuation1: float
attenuation2: float
diffuse: int
direction: Tuple[float, float, float]
falloff: float
inner_use: bool | None
light_type: int
phi: float
position: Tuple[float, float, float]
range: float
specular: int
theta: float
class ElementBody.Lightning(ElementBody):

Body of a Lightning element (type 150) — segmented lightning bolt between two points.

fields: LightningFields
class ElementBody.LightningEx(ElementBody):

Body of a LightningEx element (type 152) — extends Lightning with tail / render-side flags.

fields: LightningFields
is_append: bool | None
is_tail_disappear: bool | None
is_tail_fadeout: bool | None
render_side: int | None
verts_life: int | None
class ElementBody.LtnBolt(ElementBody):

Body of a LtnBolt element (type 151) — branching lightning bolt (no noise prefix).

alpha_end: float
alpha_start: float
circles: int
deviation: float
interval: int
max_branches: int
max_steps: int
per_bolts: int
step_max: float
step_min: float
stroke_amp: float
width_end: float
width_start: float
class ElementBody.Model(ElementBody):

Body of a Model element (type 160) — embedded 3D model reference.

alpha_cmp: bool | None
facing_dir: bool | None
loops: int | None
model_act_name: str | None
model_path: str
use_3d_cam: bool | None
write_z: bool | None
class ElementBody.Particle(ElementBody):

Body of a Particle element (types 120 / 121 / 122 / 123 / 124 / 125).

emitter: Emitter
facing: int
init_random_texture: bool | None
is_start_on_grnd: bool | None
is_use_par_uv: bool | None
no_scale: Tuple[bool, bool] | None
org_pt: Tuple[float, float] | None
particle_height: float
particle_width: float
quota: int
scale_no_off: bool | None
stop_emit_when_fade: bool | None
three_d_particle: bool
z_offset: float | None
class ElementBody.Ring(ElementBody):

Body of a Ring element (type 140) — expanding ring effect.

height: float
no_hei_scale: bool | None
no_rad_scale: bool | None
org_at_center: bool | None
pitch: float
radius: float
sects: int | None
class ElementBody.Sound(ElementBody):

Body of a Sound element (type 170) — 3D positional sound emitter.

audio_event: SoundAudioEvent | None
param_info: SoundParamInfo
paths: List[str]
class ElementBody.Trail(ElementBody):

Body of a Trail element (type 110) — ribbon trail between two moving endpoints.

bind: bool | None
enable_mat: bool
enable_org_pos1: bool
enable_org_pos2: bool
face_camera: bool | None
org_pos1: Tuple[float, float, float]
org_pos2: Tuple[float, float, float]
perturb_mode: int | None
sample_freq: int | None
seg_life: int
spline: int | None
trail_perturb: TrailPerturbSpreading | None
class ElementBody.Unknown(ElementBody):

Body of an element whose type has no typed parser — raw text lines preserved.

lines: List[str]
class ElementsConfig:

Configuration for elements.data.

Attributes:
  • lists: elements.data lists configs
  • name: name of config specified when parsing it (i.e. file name)

List configs.

name: str | None

Config name.

class ElementsData:

Object describing parsed elements.data. It also works as immutable array of data lists (ElementsDataList).

Implements basic list interface such as len(..) and __getitem__.

Attributes:
  • version: elements.data version

See also: ElementsDataList

def find_entry( self, id: int, space_id: str | None = None, allow_unknown: bool = True) -> ElementsDataEntry | None:

Find entry by ID and space ID.

Parameters
  • id: Entry ID
  • space_id: Optional space ID (None by default). If None, find among all the lists, otherwise - only in lists with specified space_id.
  • allow_unknown: If set, include lists with "unknown" space_id in search, otherwise - ignore them (True by default).
Returns

Found entry or None

def save(self, path: str) -> None:

Saves elements.data to file at path.

Parameters
  • path: Path to output file
Raises
  • Exception: If any I/O error occurs
def save_bytes(self) -> bytes:

Saves elements.data to byte array.

Returns

Serialized elements.data

version: int

elements.data version.

class ElementsDataEntry:

Single data entry.

Implements basic dict[str, object]-like and object-like interface such as len(..), __getattr__, __setattr__, __getitem__, __setitem__ and __contains__.

Number of fields, its names and types depend on elements.data version and list config. Use entry.keys() to get field names.

One can access fields with either entry['name'] (by key) or entry.name (as an attribute) syntax.

Each field can be read and modified and has one of the following types:

  • int
  • float
  • str
  • bytes

See also: ElementsListConfig

def copy(self) -> ElementsDataEntry:

Get deep copy of self.

Returns

Deep copy of entry

def keys(self) -> List[str]:

Get entry field names

Returns

Field names

class ElementsDataList:

Contains data of specific list in elements.data such as list info (like ElementsListConfig) and all data entries (ElementsDataEntry). Implements basic list interface such as len(..), __getitem__ and __setitem__.

Attributes:
  • config: list config

See also: ElementsDataEntry.

def append(self, entry: ElementsDataEntry) -> None:

Append entry at the end of list.

Parameters
  • entry: New entry
Raises
  • ValueError: If entry comes from a list with a different config

List config.

class ElementsListConfig:

Configuration for a list in elements.data.

Attributes:
  • caption: list caption
  • data_type: list data type
  • fields: array of fields
  • offset: list offset
  • space_id: list space id (may be "unknown")
caption: str

List caption.

data_type: int

List data type.

Array of fields.

offset: int | Literal['AUTO']

List offset.

space_id: str

List space ID.

class ElementsListConfigArray:

Array of list configurations.

class ElementsMetaField:

Field metadata.

Attributes:
  • name: field name
  • type: field type
name: str

Field name.

type: str

Field type.

class ElementsMetaFieldArray:

Array of field metadata.

class Emitter:

Particle emitter block — shared emitter fields plus a shape-specific payload.

acc: float
acc_dir: Tuple[float, float, float]
angle: float
color_max: int
color_min: int
drag_pow: float | None
emission_rate: float
is_bind: bool
is_drag: bool | None
is_surface: bool
is_use_hsv_interp: bool | None
par_acc: float | None
par_ini_dir: Tuple[float, float, float] | None
rot_max: float | None
rot_min: float | None
scale_max: float
scale_min: float
shape: EmitterShape
speed: float
ttl: float
class EmitterShape:

Emitter-shape-specific payload. Instances are one of the nested classes EmitterShape.Point / EmitterShape.Box / EmitterShape.Ellipsoid / EmitterShape.Cylinder / EmitterShape.MultiPlane / EmitterShape.Curve.

class EmitterShape.Box(EmitterShape):
area_size: Tuple[float, float, float]
class EmitterShape.Curve(EmitterShape):
raw_lines: List[str]
class EmitterShape.Cylinder(EmitterShape):
alpha_seg: int | None
area_size: Tuple[float, float, float]
beta_seg: int | None
is_avg_gen: bool | None
class EmitterShape.Ellipsoid(EmitterShape):
alpha_seg: int | None
area_size: Tuple[float, float, float]
beta_seg: int | None
is_avg_gen: bool | None
class EmitterShape.MultiPlane(EmitterShape):
raw_lines: List[str]
class EmitterShape.Point(EmitterShape):
class FileEntry:

Metadata for a single file entry in a pck package.

compressed_size: int

Compressed file size in bytes.

hash: int

CRC32 hash of the compressed (on-disk) file data.

path: str

Normalized file path (lowercase, backslash-separated).

size: int

Uncompressed file size in bytes.

class FloatValueTrans:

Animatable float value track (v>=102 lightning amplitude).

dest_num: int
dest_values: List[float]

dest_num + 1 values.

start_time: int
trans_times: List[int]

dest_num values.

class GfxEffect:

Parsed GFX (visual effect) file.

aabb_max: Tuple[float, float, float] | None

AABB maximum corner (present for v >= 25).

aabb_min: Tuple[float, float, float] | None

AABB minimum corner (present for v >= 25).

default_alpha: float
default_scale: float
elements: List[GfxElement]
face_to_viewer: int
fade_by_dist: int
fade_end: float
fade_start: float
play_speed: float
use_aabb: int
version: int
class GfxElement:

A single visual effect element within a GFX file.

affectors: List[KpController]

Particle affector controllers — always empty for non-particle element types (the engine only emits AffectorCount: inside A3DParticleSystemEx::Load).

body: ElementBody

Typed element-specific body; unparsed types keep their raw lines in ElementBody::Unknown.

dest_blend: int
is_dummy: int
key_point_set: KeyPointSet | None

Animation KeyPointSet appended to most elements. A small minority of real-world elements (~0.6%) omit it — in that case this field is None.

name: str
priority: int
repeat_count: int
repeat_delay: int
src_blend: int
tex_col: int
tex_file: str
tex_interval: int
tex_row: int
tile_mode: int
type_id: int

Numeric element type id, e.g. 100 for Decal3D. Use GfxElementType::from_id(type_id) to recover the typed enum.

z_enable: int
class GridAnimKey:

Grid-animation keyframe — modified vertex array at time time_ms.

time_ms: int
vertices: List[GridVertex]

Same length and row-major order as ElementBody::GridDecal3D::vertices.

class GridVertex:

Single vertex of a GridDecal3D grid — position plus packed ARGB color.

color: int
pos: Tuple[float, float, float]
class Hook:

A hook (attachment point) in a skeleton.

Distinct from a bone: an attachment point parented to a bone with a fixed local transform. ECM events typically target hooks (HH_*) rather than bones directly.

bone_index: int

Index of the bone this hook is attached to.

hook_type: int

Engine-defined hook-type identifier.

name: str

Hook name (typically HH_* for engine-recognized attachment points).

transform: List[float]

Local-to-bone transform matrix (column-major, 4x4 = 16 floats).

class KeyPoint:

One animation keyframe — transform snapshot plus per-frame controller overlays.

color: int

ARGB color packed as i32 on disk; surfaced as u32.

controllers: List[KpController]
direction: Tuple[float, float, float, float]

XYZW quaternion.

interpolate_mode: int

Interpolation between this keypoint and the next: 0 = nearest, 1 = linear, 2 = spline.

position: Tuple[float, float, float]
rad_2d: float
scale: float
time_span: int

Delta ms from the previous keypoint. -1 = hold forever.

class KeyPointSet:

Animation keyframe track attached to most GFX elements.

keypoints: List[KeyPoint]
start_time: int
class KpController:

Single keypoint controller — same wire format as a particle affector.

body: KpCtrlBody
end_time: float | None
start_time: float | None
class KpCtrlBody:

Typed controller body. Narrow with isinstance().

The full set of variants mirrors the CreateKPCtrl dispatch in A3DGFXKeyPoint.cpp. Unknown CtrlTypes fall back to KpCtrlBody.Unknown.

class KpCtrlBody.CentriMove(KpCtrlBody):

CtrlType 104 — centripetal force toward a point.

acc: float
center: Tuple[float, float, float]
vel: float
class KpCtrlBody.ClNoise(KpCtrlBody):

CtrlType 107 — color noise overlay (NoiseCtrl prefix + BaseColor).

base_color: int
noise: NoiseCtrl
class KpCtrlBody.ClTrans(KpCtrlBody):

CtrlType 108 — color transition track.

alpha_only: bool | None
color_origin: int
dest_colors: List[int]
trans_times_ms: List[float]
class KpCtrlBody.Color(KpCtrlBody):

CtrlType 105 — signed ARGB deltas per second.

color_delta: Tuple[int, int, int, int]
class KpCtrlBody.CurveMove(KpCtrlBody):

CtrlType 110 — movement along a cubic-bezier curve.

calc_dir: bool | None
vertices: List[Tuple[float, float, float]]
class KpCtrlBody.Move(KpCtrlBody):

CtrlType 100 — linear translation.

acc: float
dir: Tuple[float, float, float]
vel: float
class KpCtrlBody.NoiseBase(KpCtrlBody):

CtrlType 112 — base Perlin-like noise controller.

noise: NoiseCtrl
class KpCtrlBody.Revol(KpCtrlBody):

CtrlType 103 — revolution (orbit around an axis).

acc: float
axis: Tuple[float, float, float]
pos: Tuple[float, float, float]
vel: float
class KpCtrlBody.Rot(KpCtrlBody):

CtrlType 101 — 2D rotation around origin.

acc: float
vel: float
class KpCtrlBody.RotAxis(KpCtrlBody):

CtrlType 102 — rotation around arbitrary axis.

acc: float
axis: Tuple[float, float, float]
pos: Tuple[float, float, float]
vel: float
class KpCtrlBody.ScaNoise(KpCtrlBody):

CtrlType 109 — scale noise overlay.

noise: NoiseCtrl
class KpCtrlBody.Scale(KpCtrlBody):

CtrlType 106 — scale delta with min/max clamp.

max_scale: float
min_scale: float
scale_delta: float
class KpCtrlBody.ScaleTrans(KpCtrlBody):

CtrlType 111 — scale transition track.

dest_scales: List[float]
scale_origin: float
trans_times_ms: List[float]
class KpCtrlBody.Unknown(KpCtrlBody):

Unknown CtrlType — raw lines preserved for forward compatibility.

ctrl_type: int
raw_lines: List[str]
class LightningFields:

Scalar payload shared by Lightning and LightningEx bodies.

alpha_end: float | None
alpha_mid: float | None
alpha_start: float | None
amplitude: float | None

Some for v<=101 (single scalar); mutually exclusive with amplitude_trans.

amplitude_trans: FloatValueTrans | None

Some for v>=102 (animated amplitude track).

end_pos: Tuple[float, float, float]
filter_type: int | None
fix_wave_length: bool | None
interval: int
light_num: int
noise_ctrl: NoiseCtrl
normal: Tuple[float, float, float] | None
num_waves: float | None
pos1_enable: bool
pos2_enable: bool
segs: int
start_pos: Tuple[float, float, float]
use_normal: bool | None
wave_len: float
wave_moving: bool | None
wave_moving_speed: float | None
width_end: float

At v<=5 the engine duplicates width_start here.

width_mid: float | None
width_start: float
class Material:

A material definition from a skin file.

ambient: tuple[float, float, float, float]

Ambient color as (r, g, b, a) tuple.

diffuse: tuple[float, float, float, float]

Diffuse color as (r, g, b, a) tuple.

emissive: tuple[float, float, float, float]

Emissive color as (r, g, b, a) tuple.

name: str

Material name.

power: float

Specular power.

specular: tuple[float, float, float, float]

Specular color as (r, g, b, a) tuple.

two_sided: bool

Whether the material is two-sided.

class NoiseCtrl:

Perlin noise parameters — prefix of every Lightning / LightningEx body.

amplitude: float
buf_len: int
octave_num: int
persistence: float
wave_len: int
class PackageBuilder:

Builder for creating or modifying pck packages.

PackageBuilder()

Create an empty builder (from scratch).

def add_file(self, path: str, data: bytes) -> None:

Add or overwrite a file. Path is normalized internally.

Parameters
  • path: File path inside the package.
  • data: File content as bytes.
def file_list(self) -> List[str]:

List the final set of files (source - removed + added), sorted.

Returns

Sorted list of normalized file paths.

def remove_file(self, path: str) -> bool:

Remove a file from the package.

Parameters
  • path: File path inside the package.
Returns

True if the file existed, False otherwise.

def save( self, path: str, *, version: int | None = None, config: PackageConfig | None = None) -> None:

Save the package to a file.

Parameters
  • path: Output file path.
  • version: Package format version (default: source version or 0x20002).
  • config: Package configuration. Defaults to standard Angelica Engine config.
def to_bytes( self, *, version: int | None = None, config: PackageConfig | None = None) -> bytes:

Serialize the package to bytes.

Parameters
  • version: Package format version (default: source version or 0x20002).
  • config: Package configuration. Defaults to standard Angelica Engine config.
Returns

Serialized package bytes.

class PackageConfig:

Configuration for pck package encryption keys and guard values.

PackageConfig( key1: int = 2828235874, key2: int = 1496793649, guard1: int = 4261281518, guard2: int = 4027432687)

Create a new PackageConfig with optional custom values.

Parameters
  • key1: First key value.
  • key2: Second key value.
  • guard1: First guard value.
  • guard2: Second guard value.
guard1: int

First guard value.

guard2: int

Second guard value.

key1: int

First key value.

key2: int

Second key value.

class PckPackage:

Object describing parsed pck package.

def file_list(self) -> List[str]:

Returns list of file paths in package.

Returns

All paths in package.

def find_prefix(self, prefix: str) -> List[str]:

Finds all files in archive with path prefixed by prefix.

Parameters
  • prefix: Path prefix.
Returns

All paths in package prefixed by prefix or empty list if no files were found.

def get_file(self, path: str) -> bytes | None:

Get file content by its path.

Parameters
  • path: Path to file inside package.
Returns

None if file not found. Otherwise, returns file content.

def save(self, path: str, config: PackageConfig | None = None) -> None:

Save the package to a file.

This method saves the package to a file at the specified path. The saved package will be identical to the original when loaded back.

Parameters
  • path: Path where to save the package.
  • config: Custom package configuration. Defaults to None.
Raises
  • Exception: If any I/O error occurs during saving.
def scan_entries( self, *, paths: List[str], on_chunk: Callable[[List[FileEntry]], NoneType], interval_ms: int = 100) -> None:

Scan file entries with metadata (including compressed data CRC32 hashes). Hashes are computed from compressed (on-disk) data without decompression. Results are delivered in chunks via on_chunk callback.

Parameters
  • paths: List of file paths to scan.
  • on_chunk: Callback receiving a list of FileEntry for each chunk. Raise an exception to cancel scanning.
  • interval_ms: Minimum interval in milliseconds between chunk callbacks (100 by default). The final chunk is always delivered regardless of throttling.
def to_builder(self) -> PackageBuilder:

Create a builder pre-populated with this package's files.

Returns

A new PackageBuilder with this package's files.

class RigidMesh:

A rigid (static) mesh from a skin file.

bone_index: int

Index of the bone this mesh is attached to.

indices: List[int]

Triangle indices.

material_index: int

Index of the material used by this mesh (-1 = none).

name: str

Mesh name.

normals: List[float]

Flat array of vertex normals [x0, y0, z0, x1, y1, z1, ...].

positions: List[float]

Flat array of vertex positions [x0, y0, z0, x1, y1, z1, ...].

texture_index: int

Index of the texture used by this mesh (-1 = none).

uvs: List[float]

Flat array of UV coordinates [u0, v0, u1, v1, ...].

class Skeleton:

Parsed BON (skeleton) file.

bones: List[Bone]

List of bones in the skeleton.

hooks: List[Hook]

List of hook attachment points.

version: int

BON format version.

class Skin:

Parsed SKI (skin) file containing meshes, textures, and materials.

bone_names: List[str]

Bone names referenced by this skin.

materials: List[Material]

Materials defined in this skin.

num_ske_bone: int

Total skeleton bone count from the header (identity remap range for SKI version < 9).

rigid_meshes: List[RigidMesh]

Rigid (bone-attached) meshes.

skin_meshes: List[SkinMesh]

Skinned (weighted) meshes.

textures: List[str]

Texture file paths referenced by this skin.

version: int

SKI format version.

class SkinMesh:

A weighted (skeletal) mesh from a skin file.

bone_indices: List[int]

Flat array of bone indices [b0, b1, b2, b3, ...] per vertex (4 indices each).

bone_weights: List[float]

Flat array of bone weights [w0, w1, w2, w3, ...] per vertex (4 weights each, w3 derived).

indices: List[int]

Triangle indices.

material_index: int

Index of the material used by this mesh (-1 = none).

name: str

Mesh name.

normals: List[float]

Flat array of vertex normals [x0, y0, z0, x1, y1, z1, ...].

positions: List[float]

Flat array of vertex positions [x0, y0, z0, x1, y1, z1, ...].

texture_index: int

Index of the texture used by this mesh (-1 = none).

uvs: List[float]

Flat array of UV coordinates [u0, v0, u1, v1, ...].

class SmdModel:

Parsed SMD (skin model data) file.

skeleton_path: str

Path to the skeleton file.

skin_paths: List[str]

Skin texture paths.

tcks_dir: str | None

Directory for TCKS animation files (may be None).

version: int

SMD format version.

class SoundAudioEvent:

Audio-event sub-block present on Sound bodies at v>=96.

event_path: str
max_dist: float
min_dist: float
use_custom: bool
class SoundParamInfo:

GfxSoundParamInfo — sound parameter block with its own internal sound_ver gating.

absolute_volume: bool | None
fix_speed: bool | None
force_2d: bool
group: int | None
is_loop: bool
max_dist: float
min_dist: float
percent_start: float | None
pitch_max: float | None
pitch_min: float | None
silent_header: int | None
sound_ver: int
volume_max: int
volume_min: int
class Track:

A single animation track (position or rotation keyframes).

frame_rate: int

Frame rate of this track.

key_frame_ids: List[int] | None

Per-key frame IDs; None for V1 files.

keys: List[float]

Flat keyframe data: 3 floats per key (position) or 4 floats per key (rotation).

track_length_ms: int

Track length in milliseconds.

class TrackSet:

Parsed STCK (skeleton track set) file.

anim_end: int

Animation end frame.

anim_fps: int

Animation frames per second.

anim_start: int

Animation start frame.

bone_tracks: List[BoneTrack]

Per-bone animation tracks.

version: int

STCK format version.

class TrailPerturbSpreading:

Trail Spreading perturb sub-block (v>=122, perturb_mode == 1).

disappear_acceleration: float
disappear_delay: float
disappear_speed: float
spread_acceleration: float
spread_delay: float
spread_dir_max: Tuple[float, float, float]
spread_dir_min: Tuple[float, float, float]
spread_seg_count: int
spread_speed: float
def read_ecm(data: bytes) -> EcmModel:

Parse an ECM (composite model) file from bytes.

Parameters
  • data: Raw ECM file content.
Returns

Parsed ECM model.

Raises
  • ValueError: If the data is not a valid ECM file.
def read_elements( elements_path: str, config: ElementsConfig | None = None) -> ElementsData:

Parses elements.data from file elements_path and returns ElementsData. Doesn't load file content into memory, uses memory-mapped I/O - so file cannot be modified while ElementsData is alive.

Parameters
  • elements_path: Path to elements.data.
  • config: Optional config describing elements.data structure (None by default). If no config specified, one of predefined will be used.
Returns

Object describing parsed elements.data.

Raises
  • Exception: If any I/O error occurs, elements.data has invalid internal structure or config has incompatible version.
def read_elements_bytes( content: bytes, config: ElementsConfig | None = None) -> ElementsData:

Parses elements.data from byte array content and returns ElementsData.

Parameters
  • content: Content of elements.data.
  • config: Optional config describing elements.data structure (None by default). If no config specified, one of predefined will be used.
Returns

Object describing parsed elements.data.

Raises
  • Exception: If elements.data has invalid internal structure or config has incompatible version.
def read_elements_config(path: str) -> ElementsConfig:

Parses elements.data config from file at path path and returns ElementsConfig describing parsed file.

Parameters
  • path: Path to elements config.
Returns

Object describing parsed config.

Raises
  • Exception: If any I/O error occurs or config has invalid internal structure.
def read_elements_config_string(content: str) -> ElementsConfig:

Parses elements.data config from string content and returns ElementsConfig describing parsed file.

Parameters
  • content: String containing elements config.
Returns

Object describing parsed config.

Raises
  • Exception: If config has invalid internal structure.
def read_gfx(data: bytes) -> GfxEffect:

Parse a GFX (visual effect) file from bytes.

Parameters
  • data: Raw GFX file content.
Returns

Parsed GFX effect.

Raises
  • ValueError: If the data is not a valid GFX file.
def read_pck( pck_path: str, pkx_paths: str | List[str] | None = None, *, config: PackageConfig | None = None, on_progress: Callable[[int, int], NoneType] | None = None, progress_interval_ms: int = 0) -> PckPackage:

Parses pck package from file at path pck_path (and optionally pkx file(s)) and returns PckPackage describing parsed file(s). Doesn't load file content into memory, uses memory-mapped I/O - so file(s) cannot be modified while PckPackage is alive.

Parameters
  • pck_path: Path to pck package.
  • pkx_paths: Optional pkx path(s) — a single string or list of strings (None by default).
  • config: Custom package configuration. Defaults to None.
  • on_progress: Optional callback (index, total) called for each file entry during parsing. Raise an exception to cancel parsing.
  • progress_interval_ms: Minimum interval in milliseconds between progress callbacks (0 by default — no throttling). The last entry is always reported regardless of throttling.
Returns

Object describing parsed package.

Raises
  • Exception: If any I/O error occurs or package has invalid internal structure.
def read_pck_bytes( content: bytes, config: PackageConfig | None = None, *, on_progress: Callable[[int, int], NoneType] | None = None, progress_interval_ms: int = 0) -> PckPackage:

Parses package from byte array content and returns PckPackage.

Parameters
  • content: Content of package.
  • config: Custom package configuration. Defaults to None.
  • on_progress: Optional callback (index, total) called for each file entry during parsing. Raise an exception to cancel parsing.
  • progress_interval_ms: Minimum interval in milliseconds between progress callbacks (0 by default — no throttling). The last entry is always reported regardless of throttling.
Returns

Object describing parsed package.

Raises
  • Exception: If package has invalid internal structure.
def read_skeleton(data: bytes) -> Skeleton:

Parse a BON (skeleton) file from bytes.

Parameters
  • data: Raw BON file content.
Returns

Parsed skeleton.

Raises
  • ValueError: If the data is not a valid BON file.
def read_skin(data: bytes) -> Skin:

Parse a SKI (skin) file from bytes.

Parameters
  • data: Raw SKI file content.
Returns

Parsed skin.

Raises
  • ValueError: If the data is not a valid SKI file.
def read_smd(data: bytes) -> SmdModel:

Parse an SMD (skin model data) file from bytes.

Parameters
  • data: Raw SMD file content.
Returns

Parsed SMD model.

Raises
  • ValueError: If the data is not a valid SMD file.
def read_track_set(data: bytes) -> TrackSet:

Parse a STCK (skeleton track set) file from bytes.

Parameters
  • data: Raw STCK file content.
Returns

Parsed track set.

Raises
  • ValueError: If the data is not a valid STCK file.