575 lines
19 KiB
Python
575 lines
19 KiB
Python
from lib.fileutils import *
|
|
from dataclasses import dataclass, field
|
|
from typing import List, Union
|
|
import math
|
|
import prettyprinter
|
|
from prettyprinter import pprint
|
|
import sys
|
|
|
|
prettyprinter.install_extras(exclude=["ipython", "django", "ipython_repr_pretty", "attrs"])
|
|
|
|
|
|
def with_offset(func):
|
|
def wrapped_do_offset(*args, **kwargs):
|
|
offset = kwargs.pop("offset", None)
|
|
|
|
b = args[1]
|
|
old = b.tell()
|
|
if offset:
|
|
b.seek(offset)
|
|
|
|
r = func(*args, **kwargs)
|
|
|
|
if offset:
|
|
b.seek(old)
|
|
return r
|
|
|
|
return wrapped_do_offset
|
|
|
|
|
|
NAM_FlagHasHandles = (1 << 0)
|
|
NAM_FlagCaseInsensitive = (1 << 1)
|
|
ANM_NODE_FLAG_POS_ANIMATED = (1 << 0)
|
|
ANM_NODE_FLAG_ROT_ANIMATED = (1 << 1)
|
|
ANM_NODE_FLAG_ROL_ANIMATED = (1 << 2)
|
|
ANM_NODE_FLAG_SCL_ANIMATED = (1 << 3)
|
|
ANM_NODE_FLAG_AFF_ANIMATED = (1 << 4)
|
|
ANM_NODE_FLAG_USR_ANIMATED = (1 << 5)
|
|
ANM_NODE_FLAG_ANIMATED = ((1 << 6) - 1)
|
|
NAM_STRING_KEY = 0
|
|
NAM_HANDLE_KEY = 1
|
|
|
|
|
|
class ANM_KeyType:
|
|
@classmethod
|
|
def get_name(cls, i):
|
|
for d in cls.__dict__:
|
|
if cls.__dict__[d] == i:
|
|
return d
|
|
return None
|
|
ANM_KEYS_TYPE_NULL = 0
|
|
ANM_KEYS_TYPE_REAL_TCB = 1
|
|
ANM_KEYS_TYPE_REAL_BEZ = 2
|
|
ANM_KEYS_TYPE_REAL_LIN = 3
|
|
ANM_KEYS_TYPE_VEC3_TCB = 4
|
|
ANM_KEYS_TYPE_VEC3_BEZ = 5
|
|
ANM_KEYS_TYPE_VEC3_LIN = 6
|
|
ANM_KEYS_TYPE_QUAT_TCB = 7
|
|
ANM_KEYS_TYPE_QUAT_BEZ = 8
|
|
ANM_KEYS_TYPE_QUAT_LIN = 9
|
|
ANM_KEYS_TYPE_AFFINE_SAM = 10
|
|
|
|
|
|
@dataclass
|
|
class Vec3:
|
|
x: float
|
|
y: float
|
|
z: float
|
|
|
|
def distance(self, other: 'Vec3') -> float:
|
|
return math.sqrt(math.pow(self.x - other.x, 2) + math.pow(self.y - other.y, 2) + math.pow(self.z - other.z, 2))
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
x = read_float_and_print("Vec3->x", b)
|
|
y = read_float_and_print("Vec3->y", b)
|
|
z = read_float_and_print("Vec3->z", b)
|
|
return cls(x=x, y=y, z=z)
|
|
|
|
|
|
@dataclass
|
|
class Vec3Indexed(Vec3):
|
|
index: int
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
x = read_float_and_print("Vec3Indexed->x", b)
|
|
y = read_float_and_print("Vec3Indexed->y", b)
|
|
z = read_float_and_print("Vec3Indexed->z", b)
|
|
index = read_int_and_print("Vec3Indexed->index", b)
|
|
return cls(x=x, y=y, z=z, index=index)
|
|
|
|
|
|
@dataclass
|
|
class Vec3IndexedWeighted(Vec3Indexed):
|
|
weight: float
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
x = read_float_and_print("Vec3IndexedWeighted->x", b)
|
|
y = read_float_and_print("Vec3IndexedWeighted->y", b)
|
|
z = read_float_and_print("Vec3IndexedWeighted->z", b)
|
|
index = read_int_and_print("Vec3IndexedWeighted->index", b)
|
|
weight = read_float_and_print("Vec3IndexedWeighted->weight", b)
|
|
return cls(x=x, y=y, z=z, index=index, weight=weight)
|
|
|
|
|
|
@dataclass
|
|
class Vec4(Vec3):
|
|
w: float
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
x = read_float_and_print("Vec4->x", b)
|
|
y = read_float_and_print("Vec4->y", b)
|
|
z = read_float_and_print("Vec4->z", b)
|
|
w = read_float_and_print("Vec4->w", b)
|
|
return cls(x=x, y=y, z=z, w=w)
|
|
|
|
|
|
@dataclass
|
|
class AnmKey:
|
|
time: int
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
time = read_byte_and_print("ANM_Key->Time", b)
|
|
return cls(time=time)
|
|
|
|
|
|
@dataclass
|
|
class AnmKeys:
|
|
keys_type: int
|
|
ort_before: int
|
|
ort_after: int
|
|
flags: int
|
|
p_interpolate: int
|
|
num_keys: int
|
|
keys: list
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
keys_type = read_byte_and_print("ANM_Keys->Type", b)
|
|
debug_print("ANM_KeyType: %s" % ANM_KeyType.get_name(keys_type))
|
|
ort_before = read_byte_and_print("ANM_Keys->ORTBefore", b)
|
|
ort_after = read_byte_and_print("ANM_Keys->ORTAfter", b)
|
|
flags = read_byte_and_print("ANM_Keys->Flags", b)
|
|
p_interpolate = read_int_and_print("ANM_Keys->Interpolate", b)
|
|
num_keys = read_int_and_print("ANM_Keys->NumKeys", b)
|
|
p_keys = read_int_and_print("ANM_Keys->Keys", b)
|
|
keys = []
|
|
_old = b.tell()
|
|
b.seek(p_keys)
|
|
for _ in range(num_keys):
|
|
keys.append(AnmKey.create(b))
|
|
b.seek(_old)
|
|
return cls(keys_type=keys_type, ort_before=ort_before, ort_after=ort_after, flags=flags,
|
|
p_interpolate=p_interpolate, num_keys=num_keys, keys=keys)
|
|
|
|
|
|
@dataclass
|
|
class AnmObj:
|
|
custom: int = field(repr=False)
|
|
skin: int = field(repr=False)
|
|
zero_cluster: int
|
|
total_number_vertices: int
|
|
num_clusters: int
|
|
clusters: List['AnmCluster']
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
custom = read_int_and_print("ANM_Obj->Custom", b)
|
|
skin = read_int_and_print("ANM_Obj->Skin", b)
|
|
zero = read_int_and_print("ANM_Obj->ZeroCluster", b)
|
|
total_vertices = read_int_and_print("ANM_Obj->TotalNumberOfVertices", b)
|
|
num_clusters = read_int_and_print("ANM_Obj->NumberOfClusters", b)
|
|
clusters_offset = read_int_and_print("ANM_Obj->Clusters", b)
|
|
clusters = []
|
|
_old1 = b.tell()
|
|
b.seek(clusters_offset)
|
|
for _ in range(num_clusters):
|
|
cluster = AnmCluster.create(b)
|
|
clusters.append(cluster)
|
|
|
|
b.seek(_old1)
|
|
r = cls(custom=custom, skin=skin, zero_cluster=zero, total_number_vertices=total_vertices,
|
|
num_clusters=num_clusters, clusters=clusters)
|
|
for cluster in clusters:
|
|
cluster.obj = r
|
|
return r
|
|
|
|
|
|
@dataclass
|
|
class AnmCluster:
|
|
custom: int = field(repr=False)
|
|
obj: Union[AnmObj, None] = field(repr=False)
|
|
handle: int
|
|
bounding_box: List[Vec3] = field(repr=False) # size 2
|
|
num_vertices: int
|
|
vertices: List[Vec3Indexed] = field(repr=False)
|
|
bone_name: str = ""
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
custom = read_int_and_print("ANM_Cluster->Custom", b)
|
|
obj_offset = read_int_and_print("ANM_Cluster->Obj", b)
|
|
if obj_offset == 0: # ugly hack, dunno why we need that
|
|
custom = read_int_and_print("ANM_Cluster->Custom", b)
|
|
obj_offset = read_int_and_print("ANM_Cluster->Obj", b)
|
|
obj = None # is set by parent Obj
|
|
handle = read_int_and_print("ANM_Cluster->Handle", b)
|
|
bbox1 = Vec3.create(b)
|
|
bbox2 = Vec3.create(b)
|
|
bounding_box = [bbox1, bbox2]
|
|
num_vertices = read_int_and_print("ANM_Cluster->num_vertices", b)
|
|
vertices = []
|
|
for _ in range(num_vertices):
|
|
v = Vec3Indexed.create(b)
|
|
vertices.append(v)
|
|
|
|
return cls(custom=custom, obj=obj, handle=handle, bounding_box=bounding_box, num_vertices=num_vertices,
|
|
vertices=vertices)
|
|
|
|
|
|
class NamDictionnary:
|
|
@staticmethod
|
|
@with_offset
|
|
def create(cls, b, depth=1):
|
|
r = {}
|
|
|
|
read_int_and_print("NAM_Dictionnary->MemGroup", b) # MAP_MemGroup*
|
|
namemapper = read_int_and_print("NAM_Dictionnary->pNameMapper", b) # MAP_Mapper*
|
|
flags = read_int_and_print("NAM_Dictionnary->Flags", b) # X_BOOL
|
|
debug_print("Flags: NAM_FlagHasHandles: %s, NAM_FlagCaseInsensitive: %s" % (
|
|
flags & NAM_FlagHasHandles, flags & NAM_FlagCaseInsensitive))
|
|
read_short_and_print("NAM_Dictionnary->NameHandle", b) # NAM_NameHandle -> X_UINT16
|
|
|
|
b.seek(namemapper)
|
|
read_int_and_print("MemGroup*", b) # MAP_MemGroup*
|
|
read_int_and_print("MemBaseSize", b) # X_UINT
|
|
read_int_and_print("MemBlocks", b) # X_UINT
|
|
read_int_and_print("MemSize", b) # X_UINT
|
|
read_int_and_print("MemFree", b) # X_UINT
|
|
read_int_and_print("Mem*", b) # MAP_Mapping*
|
|
read_int_and_print("MaxMappings", b) # X_UINT
|
|
totalmappings = read_int_and_print("TotalMappings", b) # X_UINT
|
|
total_keys = read_int_and_print("TotalKeys", b) # X_UINT
|
|
p_key_contexts = read_int_and_print("KeyContexts*", b) # MAP_KeyContext*
|
|
|
|
for key in range(total_keys):
|
|
key_context_size = [
|
|
4, # X_UINT Size
|
|
4, # MAP_BinSearchCallback* Callback
|
|
4, # X_UINT Index
|
|
4, # X_INT Test
|
|
4, # MAP_Mapping **LUT
|
|
4, # X_UINT Reserve
|
|
4, # X_VOID *Data
|
|
]
|
|
key_context_size = sum(key_context_size)
|
|
key_context_begin = p_key_contexts + key * key_context_size
|
|
debug_print("getting keys for type %s" % key)
|
|
b.seek(key_context_begin) # NAM_Dictionnary.KeyContexts[KEY]
|
|
# we are now in the KeyContext for type "key"
|
|
debug_print("Current keycontext: %s" % b.tell())
|
|
keytype_size = read_int_and_print("\tSize", b) # MAP_BinSearchContext -> X_UINT
|
|
read_int_and_print("\t\tpCallback", b) # MAP_BinSearchContext -> MAP_BinSearchCallback*
|
|
read_int_and_print("\t\tIndex", b) # MAP_BinSearchContext -> X_UINT
|
|
read_int_and_print("\t\tTest", b) # MAP_BinSearchContext -> X_INT
|
|
p_lut = read_int_and_print("\tMAP_Mapping** LUT", b) # MAP_Mapping**
|
|
read_int_and_print("\tReserve", b) # X_UINT
|
|
read_int_and_print("\tpData", b) # X_VOID*
|
|
|
|
# i=0; tant que l'addresse que renvoie MAP_MappingGet (Dictionary->NameMapper, i, NAM_STRING_KEY) != 0; i++
|
|
# mappingget: return Mapper->KeyContexts[Key].LUT[Index];
|
|
|
|
"""
|
|
|
|
"""
|
|
key_index = 0
|
|
while True:
|
|
if key_index >= totalmappings:
|
|
break
|
|
b.seek(p_lut + key_index * 4) # NAM_Dictionnary.KeyContexts[KEY].LUT[INDEX] -> LA je suis au MAP_Mapping* == NAM_Name*
|
|
debug_print("MAP_Mapping*")
|
|
addr_begin_mapping = read_int_and_print("MAP_Mapping*", b) # MAP_MapIndex* -> X_UINT16*
|
|
if addr_begin_mapping == 0:
|
|
break
|
|
b.seek(addr_begin_mapping)
|
|
# we are now in MAP_Mapping == NAM_Name header
|
|
"""
|
|
struct _MAP_Mapping
|
|
{
|
|
MAP_MapIndex TotalSize;
|
|
};
|
|
typedef X_UINT16 MAP_MapIndex;
|
|
"""
|
|
debug_print("MAP_Mapping")
|
|
read_short_and_print("TotalSize", b) # MAP_MapIndex* -> X_UINT16*
|
|
after_mapping = b.tell()
|
|
b.seek(after_mapping + key * 2)
|
|
debug_print("MAP_MapIndex at %s" % b.tell())
|
|
index = read_short_and_print("MAP_MapIndex value", b)
|
|
|
|
b.seek(addr_begin_mapping+index)
|
|
debug_print("STRINGDATA* OU HANDLEDATA* at %s" % b.tell())
|
|
# pdata = read_int_and_print("Data*", b)
|
|
# b.seek(pdata)
|
|
if key == NAM_STRING_KEY:
|
|
val = read_int_and_print("ValueOrCustom", b) # X_INT or X_VOID*
|
|
name = read_string_until_none_and_print("name", b)
|
|
if flags & NAM_FlagHasHandles:
|
|
r[key_index] = {"Name": name}
|
|
elif depth > 1:
|
|
item = NamDictionnary.create(cls, b, depth - 1, offset=val)
|
|
r[name] = item
|
|
else:
|
|
item = cls.create(b, offset=val)
|
|
r[name] = item
|
|
if key == NAM_HANDLE_KEY:
|
|
read_short_and_print("RefCnt", b) # NAM_NameRefCnt == X_UINT16
|
|
handle = read_short_and_print("Handle", b) # NAM_NameHandle == X_UINT16
|
|
r[key_index]["Handle"] = handle
|
|
key_index += 1
|
|
debug_print("Key_index=%s" % key_index)
|
|
return r
|
|
|
|
|
|
@dataclass
|
|
class GeoMat4x4:
|
|
m: List[float]
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
m = []
|
|
for _ in range(4):
|
|
for _j in range(4):
|
|
m.append(read_float(b))
|
|
return cls(m=m)
|
|
|
|
|
|
@dataclass
|
|
class GeoMat:
|
|
mat_class: int
|
|
s: GeoMat4x4
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
mat_class = read_int(b)
|
|
s = GeoMat4x4.create(b)
|
|
return cls(mat_class=mat_class, s=s)
|
|
|
|
|
|
@dataclass
|
|
class GeoAffine:
|
|
transform: Vec3
|
|
quat: Vec4
|
|
scale: Vec3
|
|
affine_class: int
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
trans = Vec3.create(b)
|
|
quat = Vec4.create(b)
|
|
scale = Vec3.create(b)
|
|
affine_class = read_int(b)
|
|
return cls(transform=trans, quat=quat, scale=scale, affine_class=affine_class)
|
|
|
|
|
|
@dataclass
|
|
class AnmTransform:
|
|
time: int
|
|
affine: GeoAffine
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
time = read_int(b)
|
|
affine = GeoAffine.create(b)
|
|
return cls(time=time, affine=affine)
|
|
|
|
|
|
@dataclass
|
|
class AnmNode:
|
|
custom: int
|
|
node_type: int
|
|
x_form_type: int
|
|
flags: int
|
|
p_anim: int
|
|
p_parent: int
|
|
p_target: int
|
|
p_usercall: int
|
|
p_usercontext: int
|
|
stamp: int
|
|
geo_mat: GeoMat
|
|
transform: AnmTransform
|
|
pos_keys: Union[AnmKeys, int]
|
|
rot_keys: Union[AnmKeys, int]
|
|
scl_keys: Union[AnmKeys, int]
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
custom = read_int_and_print("ANM_Node->Custom", b)
|
|
node_type = read_short_and_print("ANM_Node->Type", b)
|
|
x_form_type = read_short_and_print("ANM_Node->XformType", b)
|
|
flags = read_int_and_print("ANM_Node->Flags", b)
|
|
p_anim = read_int_and_print("ANM_Node->pAnim", b)
|
|
p_parent = read_int_and_print("ANM_Node->pParent", b)
|
|
p_target = read_int_and_print("ANM_Node->pTarget", b)
|
|
p_usercall = read_int_and_print("ANM_Node->pUserCall", b)
|
|
p_usercontext = read_int_and_print("ANM_Node->pUserContext", b)
|
|
stamp = read_int_and_print("ANM_Node->Stamp", b)
|
|
geo_mat = GeoMat.create(b)
|
|
transform = AnmTransform.create(b)
|
|
pos_keys = read_int_and_print("ANM_Node->pPosKeys", b)
|
|
rot_keys = read_int_and_print("ANM_Node->pRotKeys", b)
|
|
scl_keys = read_int_and_print("ANM_Node->pSclKeys", b)
|
|
|
|
if pos_keys > 0:
|
|
pos_keys = AnmKeys.create(b, offset=pos_keys)
|
|
|
|
if rot_keys > 0:
|
|
rot_keys = AnmKeys.create(b, offset=rot_keys)
|
|
|
|
if scl_keys > 0:
|
|
scl_keys = AnmKeys.create(b, offset=scl_keys)
|
|
|
|
return cls(custom=custom, node_type=node_type, x_form_type=x_form_type, flags=flags, p_anim=p_anim,
|
|
p_parent=p_parent, p_target=p_target, p_usercall=p_usercall, p_usercontext=p_usercontext,
|
|
stamp=stamp, geo_mat=geo_mat, transform=transform, pos_keys=pos_keys, rot_keys=rot_keys,
|
|
scl_keys=scl_keys)
|
|
|
|
|
|
@dataclass
|
|
class AnmAnim:
|
|
custom: int
|
|
fileversion: int
|
|
image: int
|
|
memgroup: int
|
|
start_time: int
|
|
end_time: int
|
|
ticks_per_frame: int
|
|
framerate: int
|
|
tree_dictionnary: dict
|
|
default_obj_dictionnary: dict
|
|
num_nodes: int
|
|
|
|
extra_stamp: int
|
|
extra_flags: int
|
|
|
|
extra_time1: int
|
|
extra_stamp1: int
|
|
|
|
extra_time2: int
|
|
extra_stamp2: int
|
|
|
|
extra_factor: float
|
|
extra_other_anim: int
|
|
name: str
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
custom = read_int_and_print("ANM_Anim->Custom", b)
|
|
version = read_int_and_print("ANM_Anim->FileVersion", b)
|
|
image = read_int_and_print("ANM_Anim->pImage", b)
|
|
memgroup = read_int_and_print("ANM_Anim->pMemGroup", b)
|
|
|
|
start_time = read_int_and_print("ANM_Anim->StartTime", b)
|
|
end_time = read_int_and_print("ANM_Anim->EndTime", b)
|
|
ticks_per_frame = read_int_and_print("TicksPerFrame", b)
|
|
framerate = read_int_and_print("FrameRate", b)
|
|
treedict = read_int_and_print("pTreeDictionary", b)
|
|
defaultobjdict = read_int_and_print("pDefaultObjDictionary", b)
|
|
num_nodes = read_int_and_print("NumberOfNodes", b)
|
|
stamp = read_int_and_print("ANM_AnimExtra->Stamp", b)
|
|
flags = read_int_and_print("ANM_AnimExtra->Flags", b)
|
|
time1 = read_int_and_print("ANM_AnimExtra->Time1", b)
|
|
stamp1 = read_int_and_print("ANM_AnimExtra->Stamp1", b)
|
|
time2 = read_int_and_print("ANM_AnimExtra->Time2", b)
|
|
stamp2 = read_int_and_print("ANM_AnimExtra->Stamp2", b)
|
|
factor = read_float_and_print("ANM_AnimExtra->Factor", b)
|
|
otheranim = read_int_and_print("ANM_AnimExtra->OtherAnim", b)
|
|
name = read_string_until_none(b)
|
|
|
|
treedict = NamDictionnary.create(AnmNode, b, depth=2, offset=treedict)
|
|
defaultobjdict = NamDictionnary.create(AnmNode, b, offset=defaultobjdict)
|
|
|
|
return cls(custom=custom, fileversion=version, image=image, memgroup=memgroup, start_time=start_time,
|
|
end_time=end_time, ticks_per_frame=ticks_per_frame, framerate=framerate, tree_dictionnary=treedict,
|
|
default_obj_dictionnary=defaultobjdict, num_nodes=num_nodes, extra_stamp=stamp, extra_flags=flags,
|
|
extra_time1=time1, extra_stamp1=stamp1, extra_time2=time2, extra_stamp2=stamp2, extra_factor=factor,
|
|
extra_other_anim=otheranim, name=name)
|
|
|
|
|
|
@dataclass
|
|
class AnmSkin:
|
|
custom: int
|
|
file_version: int
|
|
image: int
|
|
memgroup: int
|
|
node_dictionnary: dict
|
|
tree_dictionnary: dict
|
|
default_obj_dictionnary: dict
|
|
total_number_trees: int
|
|
total_number_objs: int
|
|
total_number_clusters: int
|
|
name: str
|
|
|
|
@staticmethod
|
|
def link(nodedict, defaultobjtree):
|
|
|
|
m = {}
|
|
for node_index in nodedict:
|
|
node = nodedict[node_index]
|
|
m[node["Handle"]] = node["Name"]
|
|
|
|
for obj_name, obj in defaultobjtree.items():
|
|
for cluster in obj.clusters:
|
|
cluster.bone_name = m[cluster.handle]
|
|
|
|
@classmethod
|
|
@with_offset
|
|
def create(cls, b):
|
|
custom = read_int_and_print("pCustom", b)
|
|
version = read_int_and_print("FileVersion", b)
|
|
image = read_int_and_print("pImage", b)
|
|
memgroup = read_int_and_print("pMemGroup", b)
|
|
node = read_int_and_print("pNodeDictionary", b)
|
|
tree = read_int_and_print("pTreeDictionary", b)
|
|
defaultobj = read_int_and_print("pDefaultObjDictionary", b)
|
|
num_trees = read_int_and_print("TotalNumberOfTrees", b)
|
|
num_objs = read_int_and_print("TotalNumberOfObjs", b)
|
|
num_clusters = read_int_and_print("TotalNumberOfClusters", b)
|
|
name = read_string_until_none_and_print("Name", b)
|
|
|
|
nodedict = NamDictionnary.create(AnmObj, b, offset=node)
|
|
treedict = NamDictionnary.create(AnmObj, b, depth=2, offset=tree)
|
|
defaultobjdict = NamDictionnary.create(AnmObj, b, offset=defaultobj)
|
|
|
|
AnmSkin.link(nodedict, defaultobjdict)
|
|
return cls(custom=custom, file_version=version, image=image, memgroup=memgroup, node_dictionnary=nodedict,
|
|
tree_dictionnary=treedict, default_obj_dictionnary=defaultobjdict, total_number_trees=num_trees,
|
|
total_number_objs=num_objs, total_number_clusters=num_clusters, name=name)
|
|
|
|
|
|
@dataclass
|
|
class AnmFile:
|
|
@staticmethod
|
|
def parse(b, cls):
|
|
_ = read_int_and_print("size", b)
|
|
memgroupoffset = read_int_and_print("memgroupoffset", b)
|
|
b.seek(memgroupoffset)
|
|
read_int_and_print("\tNode", b)
|
|
read_int_and_print("\tSize", b)
|
|
read_int_and_print("\tFlags", b)
|
|
|
|
read_int_and_print("pMemGroup", b)
|
|
read_int_and_print("MemList", b)
|
|
read_int_and_print("TotalSize", b)
|
|
read_int_and_print("TotalBlocks", b)
|
|
base = read_int_and_print("pBase", b)
|
|
return cls.create(b, offset=base)
|