from lib.fileutils import * import logging import sys class MConsoleHandler(logging.StreamHandler): special_code = '[!n]' def emit(self, record) -> None: record.msg = str(record.msg) if self.special_code in record.msg: record.msg = record.msg.replace(self.special_code, '') self.terminator = '' else: self.terminator = '\n' return super().emit(record) logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) cs = MConsoleHandler(sys.stdout) fmt = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") fmt = logging.Formatter("%(message)s") cs.setFormatter(fmt) logger.addHandler(cs) 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) def printdebug(msg): logger.debug(msg) def printinfo(msg): logger.info(msg, ) def tb(i): return 1 if i > 0 else 0 def read_int_and_print(n, b): a = read_int(b) printdebug("%s=%s" % (n, a)) return a def read_float_and_print(n, b): a = read_float(b) printdebug("%s=%s" % (n, a)) return a def read_byte_and_print(n, b): a = read_byte(b) printdebug("%s=%s" % (n, a)) return a def read_short_and_print(n, b): a = read_short(b) printdebug("%s=%s" % (n, a)) return a class ANM_Anim: def __init__(self): self.custom = 0 self.file_version = 0 self.image = 0 self.memgroup = 0 self.node_dictionary = 0 self.tree_dictionary = 0 self.default_obj_dictionnary = 0 self.total_number_trees = 0 self.total_number_objs = 0 self.total_number_clusters = 0 self.name = 0 @classmethod def parse(cls, b): printinfo("Decoding %s" % b.name) printdebug("MAP_Image") read_int_and_print("size", b) memgroupoffset = read_int_and_print("memgroupoffset", b) b.seek(memgroupoffset) printdebug("MAP_MemGroup") printdebug("\tMAP_Mem") 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) b.seek(base) printdebug("=========") printdebug("ANM_Anim") read_int_and_print("pCustom", b) read_int_and_print("FileVersion", b) read_int_and_print("pImage", b) read_int_and_print("pMemGroup", b) starttime = read_int_and_print("StartTime", b) endtime = read_int_and_print("EndTime", b) ticksperframe = read_int_and_print("TicksPerFrame", b) framerate = read_int_and_print("FrameRate", b) tree = read_int_and_print("pTreeDictionary", b) defaultobj = read_int_and_print("pDefaultObjDictionary", b) numnodes = read_int_and_print("NumberOfNodes", b) printdebug("ANM_AnimExtra") read_int_and_print("ANM_AnimExtra->Stamp", b) read_int_and_print("ANM_AnimExtra->Flags", b) read_int_and_print("ANM_AnimExtra->Time1", b) read_int_and_print("ANM_AnimExtra->Stamp1", b) read_int_and_print("ANM_AnimExtra->Time2", b) read_int_and_print("ANM_AnimExtra->Stamp2", b) read_float_and_print("ANM_AnimExtra->Factor", b) read_int_and_print("ANM_AnimExtra->OtherAnim", b) name = read_string_until_none(b) printdebug(name) printinfo("[%s] StartTime:%s EndTime:%s TicksPerFrame:%s FrameRate:%s NumNodes:%s" % (name, starttime, endtime, ticksperframe , framerate, numnodes)) printdebug("=========") printdebug("ANM_Anim->pTreeDictionary NAM_Dictionary") b.seek(defaultobj) read_int_and_print("pMemGroup", b) namemapper = read_int_and_print("pNameMapper", b) flags = read_int_and_print("Flags", b) printdebug("Flags: NAM_FlagHasHandles: %s, NAM_FlagCaseInsensitive: %s" % (flags & NAM_FlagHasHandles, flags & NAM_FlagCaseInsensitive)) namehandle = read_short_and_print("NameHandle", b) printdebug("MAP_Image->ANM_Anim->NAM_Dictionnary->MAP_Mapper") b.seek(namemapper) pMemGroup = read_int_and_print("pMemGroup", b) read_int_and_print("MemBaseSize", b) read_int_and_print("MemBlocks", b) read_int_and_print("MemSize", b) read_int_and_print("MemFree", b) mem = read_int_and_print("pMem", b) read_int_and_print("MaxMappings", b) totalmappings = read_int_and_print("TotalMappings", b) read_int_and_print("TotalKeys", b) pKeyContexts = read_int_and_print("pKeyContexts", b) printdebug("MAP_Image->ANM_Anim->NAM_Dictionnary->MAP_Mapper->MAP_KeyContext NAM_STRING_KEY") b.seek(pKeyContexts) read_int_and_print("\tSize", b) read_int_and_print("\tpCallback", b) read_int_and_print("\tIndex", b) read_int_and_print("\tTest", b) pLUTNAM_STRING_KEY = read_int_and_print("pLUT", b) read_int_and_print("Reserve", b) read_int_and_print("pData", b) def showdictbyindex(i): assert(0 <= i < totalmappings) printdebug("LUT NAM_STRING_KEY") b.seek(pLUTNAM_STRING_KEY) pind0_string = read_int_and_print("LUT NAM_STRING_KEY[0]", b) for _ in range(i): pind0_string = read_int_and_print("LUT NAM_STRING_KEY[0]", b) printdebug("NAM_StringData") b.seek(pind0_string) read_int_and_print("pPtr->ANM_Obj", b) val = read_int_and_print("Value", b) printdebug(b.tell()) nodename = read_string_until_none(b) printdebug(nodename) b.seek(val) read_int_and_print("ANM_Node->Custom", b) read_short_and_print("ANM_Node->Type", b) read_short_and_print("ANM_Node->XformType", b) nodeflags = read_int_and_print("ANM_Node->Flags", b) read_int_and_print("ANM_Node->pAnim", b) read_int_and_print("ANM_Node->pParent", b) read_int_and_print("ANM_Node->pTarget", b) read_int_and_print("ANM_Node->pUserCall", b) read_int_and_print("ANM_Node->pUserContext", b) stamp = read_int_and_print("ANM_Node->Stamp", b) printdebug("ANM_Node->Mat") read_int_and_print("GEO_Mat->Class", b) for _i in range(4): for _j in range(4): read_float_and_print("GEO_Mat->E", b) printdebug("ANM_Node->Transform") transformtime = read_int_and_print("ANM_Transform->Time", b) printdebug("ANM_Transform->Affine") read_float_and_print("GEO_Affine->Trans[x]", b) read_float_and_print("GEO_Affine->Trans[y]", b) read_float_and_print("GEO_Affine->Trans[z]", b) read_float_and_print("GEO_Affine->Quat[x]", b) read_float_and_print("GEO_Affine->Quat[y]", b) read_float_and_print("GEO_Affine->Quat[z]", b) read_float_and_print("GEO_Affine->Quat[w]", b) read_float_and_print("GEO_Affine->Scale[x]", b) read_float_and_print("GEO_Affine->Scale[y]", b) read_float_and_print("GEO_Affine->Scale[z]", b) read_int_and_print("GEO_Affine->Class", b) posKeys = read_int_and_print("ANM_Node->pPosKeys", b) rotKeys = read_int_and_print("ANM_Node->pRotKeys", b) sclKeys = read_int_and_print("ANM_Node->pSclKeys", b) printinfo("\t[%s] Animated:%s[!n]" % (nodename, bool(nodeflags & ANM_NODE_FLAG_ANIMATED))) if nodeflags & ANM_NODE_FLAG_POS_ANIMATED: printinfo(" PosAnimated:True[!n]") if nodeflags & ANM_NODE_FLAG_ROT_ANIMATED: printinfo(" RotAnimated:True[!n]") if nodeflags & ANM_NODE_FLAG_ROL_ANIMATED: printinfo(" RolAnimated:True[!n]") if nodeflags & ANM_NODE_FLAG_SCL_ANIMATED: printinfo(" SclAnimated:True[!n]") if nodeflags & ANM_NODE_FLAG_AFF_ANIMATED: printinfo(" AffAnimated:True[!n]") if nodeflags & ANM_NODE_FLAG_USR_ANIMATED: printinfo(" UsrAnimated:True[!n]") printinfo("") """ printinfo("\t[%s] Anim:%s Pos:%s Rot:%s Rol:%s Scl:%s Aff:%s Usr:%s" % ( nodename, tb(nodeflags & ANM_NODE_FLAG_ANIMATED), tb(nodeflags & ANM_NODE_FLAG_POS_ANIMATED), tb(nodeflags & ANM_NODE_FLAG_ROT_ANIMATED), tb(nodeflags & ANM_NODE_FLAG_ROL_ANIMATED), tb(nodeflags & ANM_NODE_FLAG_SCL_ANIMATED), tb(nodeflags & ANM_NODE_FLAG_AFF_ANIMATED), tb(nodeflags & ANM_NODE_FLAG_USR_ANIMATED))) """ if nodeflags & ANM_NODE_FLAG_POS_ANIMATED: b.seek(posKeys) read_byte_and_print("\t\tType", b) read_byte_and_print("\t\tORTBefore", b) read_byte_and_print("\t\tORTAfter", b) read_byte_and_print("\t\tFlags", b) read_int_and_print("\t\tpInterpolate", b) read_int_and_print("\t\tNumberOfKeys", b) read_int_and_print("\t\tpKeys", b) for p in range(totalmappings): showdictbyindex(p) def main(): #with open("/home/tasty/Projects/gck-map-extract-objects/anm_skn/sm_book.anm", "rb") as fp: # with open("/home/tasty/Projects/gck-map-extract-objects/anm_skn/vp_hit.anm", "rb") as fp: with open("/home/tasty/Projects/gck-map-extract-objects/anm_skn/Mc_salute.anm", "rb") as fp: ANM_Anim.parse(fp) if __name__ == "__main__": main()