UNPKG

source-mdl

Version:

This package can read source engines MDL files. To parse a model, it needs the VTX, VVD and MDL file.

470 lines (434 loc) 23.4 kB
const StudioStruct = require("structron"); /** * Structures based on /src/public/studio.h */ const MAX_NUM_LODS = 8; const MAX_NUM_BONES_PER_VERT = 3; const Vector = new StudioStruct() .addMember(StudioStruct.TYPES.FLOAT, "x") .addMember(StudioStruct.TYPES.FLOAT, "y") .addMember(StudioStruct.TYPES.FLOAT, "z"); const Vector2 = new StudioStruct() .addMember(StudioStruct.TYPES.FLOAT, "x") .addMember(StudioStruct.TYPES.FLOAT, "y"); const Quaternion = new StudioStruct() .addMember(StudioStruct.TYPES.FLOAT, "x") .addMember(StudioStruct.TYPES.FLOAT, "y") .addMember(StudioStruct.TYPES.FLOAT, "z") .addMember(StudioStruct.TYPES.FLOAT, "w"); const matrix3x4_t = new StudioStruct() .addMember(Vector, "col0") .addMember(Vector, "col1") .addMember(Vector, "col2") .addMember(Vector, "col3") const mstudiotexture_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "name_offset") .addMember(StudioStruct.TYPES.INT, "flags") .addMember(StudioStruct.TYPES.INT, "used") .addMember(StudioStruct.TYPES.INT, "unused") .addMember(StudioStruct.TYPES.INT, "material") .addMember(StudioStruct.TYPES.INT, "client_material") .addMember(StudioStruct.TYPES.SKIP(40), "unused2") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "name_offset", true); const mstudioboneweight_t = new StudioStruct() .addMember(StudioStruct.TYPES.FLOAT, "weight0") .addMember(StudioStruct.TYPES.FLOAT, "weight1") .addMember(StudioStruct.TYPES.FLOAT, "weight2") .addMember(StudioStruct.TYPES.BYTE, "BONE0") .addMember(StudioStruct.TYPES.BYTE, "BONE1") .addMember(StudioStruct.TYPES.BYTE, "BONE2") .addMember(StudioStruct.TYPES.BYTE, "numbones") const mstudiovertex_t = new StudioStruct() .addMember(mstudioboneweight_t, "m_BoneWeights") .addMember(Vector, "m_vecPosition") .addMember(Vector, "m_vecNormal") .addMember(Vector2, "m_vecTexCoord") const mstudio_meshvertexdata_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "modelvertexdata") .addMember(StudioStruct.TYPES.INT, "numLODVertexes0") .addMember(StudioStruct.TYPES.INT, "numLODVertexes1") .addMember(StudioStruct.TYPES.INT, "numLODVertexes2") .addMember(StudioStruct.TYPES.INT, "numLODVertexes3") .addMember(StudioStruct.TYPES.INT, "numLODVertexes4") .addMember(StudioStruct.TYPES.INT, "numLODVertexes5") .addMember(StudioStruct.TYPES.INT, "numLODVertexes6") .addMember(StudioStruct.TYPES.INT, "numLODVertexes7"); const mstudiomesh_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "material") .addMember(StudioStruct.TYPES.INT, "modelindex") .addMember(StudioStruct.TYPES.INT, "numvertices") .addMember(StudioStruct.TYPES.INT, "vertexoffset") .addMember(StudioStruct.TYPES.INT, "numflexes") .addMember(StudioStruct.TYPES.INT, "flexindex") .addMember(StudioStruct.TYPES.INT, "materialtype") .addMember(StudioStruct.TYPES.INT, "materialparam") .addMember(StudioStruct.TYPES.INT, "meshid") .addMember(Vector, "center") .addMember(mstudio_meshvertexdata_t, "vertexdata") .addMember(StudioStruct.TYPES.SKIP(32), "unused"); // Index of string array const stringIndex = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "name_offset") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "name_offset"); const mstudio_modelvertexdata_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "pVertexData") .addMember(StudioStruct.TYPES.INT, "pTangentData"); const mstudiomodel_t = new StudioStruct() .addMember(StudioStruct.TYPES.STRING(64), "name") .addMember(StudioStruct.TYPES.INT, "type") .addMember(StudioStruct.TYPES.FLOAT, "boundingradius") .addMember(StudioStruct.TYPES.INT, "nummeshes") .addMember(StudioStruct.TYPES.INT, "meshindex") .addMember(StudioStruct.TYPES.INT, "numvertices") .addMember(StudioStruct.TYPES.INT, "vertexindex") .addMember(StudioStruct.TYPES.INT, "tangentindex") .addMember(StudioStruct.TYPES.INT, "numattachments") .addMember(StudioStruct.TYPES.INT, "attachmentindex") .addMember(StudioStruct.TYPES.INT, "numeyeballs") .addMember(StudioStruct.TYPES.INT, "eyeballindex") .addMember(mstudio_modelvertexdata_t, "vertexdata") .addMember(StudioStruct.TYPES.SKIP(32), "unused") .addArray(mstudiomesh_t, "meshes", "meshindex", "nummeshes", true) const mstudiobodyparts_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "name_offset") .addMember(StudioStruct.TYPES.INT, "model_number") .addMember(StudioStruct.TYPES.INT, "base") .addMember(StudioStruct.TYPES.INT, "model_index") .addArray(mstudiomodel_t, "models", "model_index", "model_number", true) .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "name_offset", true) const mstudiobone_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "sznameindex") .addMember(StudioStruct.TYPES.INT, "parent") .addMember(StudioStruct.TYPES.INT, "bonecontroller0") .addMember(StudioStruct.TYPES.INT, "bonecontroller1") .addMember(StudioStruct.TYPES.INT, "bonecontroller2") .addMember(StudioStruct.TYPES.INT, "bonecontroller3") .addMember(StudioStruct.TYPES.INT, "bonecontroller4") .addMember(StudioStruct.TYPES.INT, "bonecontroller5") .addMember(Vector, "pos") .addMember(Quaternion, "quat") .addMember(Vector, "rot") .addMember(Vector, "posscale") .addMember(Vector, "rotscale") .addMember(matrix3x4_t, "poseToBone") .addMember(Quaternion, "qAlignment") .addMember(StudioStruct.TYPES.INT, "flags") .addMember(StudioStruct.TYPES.INT, "proctype") .addMember(StudioStruct.TYPES.INT, "procindex") .addMember(StudioStruct.TYPES.INT, "physicsbone") .addMember(StudioStruct.TYPES.INT, "surfacepropidx") .addMember(StudioStruct.TYPES.INT, "contents") .addMember(StudioStruct.TYPES.SKIP(32), "unused") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true) .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "surfaceprop", "surfacepropidx", true); const mstudiobbox_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "bone") .addMember(StudioStruct.TYPES.INT, "group") .addMember(Vector, "bbmin") .addMember(Vector, "bbmax") .addMember(StudioStruct.TYPES.INT, "szhitboxnameindex") .addMember(StudioStruct.TYPES.SKIP(32), "unused") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "szhitboxnameindex", true); const mstudiohitboxset_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "sznameindex") .addMember(StudioStruct.TYPES.INT, "numhitboxes") .addMember(StudioStruct.TYPES.INT, "hitboxindex") .addArray(mstudiobbox_t, "hitboxes", "hitboxindex", "numhitboxes", true) .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true); const mstudiobonecontroller_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "bone") .addMember(StudioStruct.TYPES.INT, "type") .addMember(StudioStruct.TYPES.FLOAT, "start") .addMember(StudioStruct.TYPES.FLOAT, "end") .addMember(StudioStruct.TYPES.INT, "rest") .addMember(StudioStruct.TYPES.INT, "inputfield") .addMember(StudioStruct.TYPES.SKIP(32), "unused"); const mstudiomovement_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "endframe") .addMember(StudioStruct.TYPES.INT, "motionflags") .addMember(StudioStruct.TYPES.FLOAT, "v0") .addMember(StudioStruct.TYPES.FLOAT, "v1") .addMember(StudioStruct.TYPES.FLOAT, "angle") .addMember(Vector, "vector") .addMember(Vector, "position") const mstudioikrule_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "index") .addMember(StudioStruct.TYPES.INT, "type") .addMember(StudioStruct.TYPES.INT, "chain") .addMember(StudioStruct.TYPES.INT, "bone") .addMember(StudioStruct.TYPES.INT, "slot") .addMember(StudioStruct.TYPES.FLOAT, "height") .addMember(StudioStruct.TYPES.FLOAT, "radius") .addMember(StudioStruct.TYPES.FLOAT, "floor") .addMember(Vector, "pos") .addMember(Quaternion, "q") .addMember(StudioStruct.TYPES.INT, "compressedikerrorindex") .addMember(StudioStruct.TYPES.INT, "unused2") .addMember(StudioStruct.TYPES.INT, "iStart") .addMember(StudioStruct.TYPES.INT, "ikerrorindex") .addMember(StudioStruct.TYPES.FLOAT, "start") .addMember(StudioStruct.TYPES.FLOAT, "peak") .addMember(StudioStruct.TYPES.FLOAT, "tail") .addMember(StudioStruct.TYPES.FLOAT, "end") .addMember(StudioStruct.TYPES.FLOAT, "unused3") .addMember(StudioStruct.TYPES.FLOAT, "contact") .addMember(StudioStruct.TYPES.FLOAT, "drop") .addMember(StudioStruct.TYPES.FLOAT, "top") .addMember(StudioStruct.TYPES.INT, "unused6") .addMember(StudioStruct.TYPES.INT, "unused7") .addMember(StudioStruct.TYPES.INT, "unused8") .addMember(StudioStruct.TYPES.INT, "szattachmentindex") .addMember(StudioStruct.TYPES.SKIP(7*4), "unused") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "worldAttachment", "szattachmentindex"); const mstudiolocalhierarchy_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "iBone") .addMember(StudioStruct.TYPES.INT, "iNewParent") .addMember(StudioStruct.TYPES.FLOAT, "start") .addMember(StudioStruct.TYPES.FLOAT, "peak") .addMember(StudioStruct.TYPES.FLOAT, "tail") .addMember(StudioStruct.TYPES.FLOAT, "end") .addMember(StudioStruct.TYPES.INT, "iStart") .addMember(StudioStruct.TYPES.INT, "localanimindex") .addMember(StudioStruct.TYPES.SKIP(32)); const mstudioanimsections_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "animblock") .addMember(StudioStruct.TYPES.INT, "animindex"); const mstudioanimdesc_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "baseptr") .addMember(StudioStruct.TYPES.INT, "sznameindex") .addMember(StudioStruct.TYPES.FLOAT, "fps") .addMember(StudioStruct.TYPES.INT, "flags") .addMember(StudioStruct.TYPES.INT, "numframes") .addMember(StudioStruct.TYPES.INT, "nummovements") .addMember(StudioStruct.TYPES.INT, "movementindex") .addMember(StudioStruct.TYPES.SKIP(24), "unused") .addMember(StudioStruct.TYPES.INT, "animblock") .addMember(StudioStruct.TYPES.INT, "animindex") .addMember(StudioStruct.TYPES.INT, "numikrules") .addMember(StudioStruct.TYPES.INT, "ikruleindex") .addMember(StudioStruct.TYPES.INT, "animblockikruleindex") .addMember(StudioStruct.TYPES.INT, "numlocalhierarchy") .addMember(StudioStruct.TYPES.INT, "localhierarchyindex") .addMember(StudioStruct.TYPES.INT, "sectionindex") .addMember(StudioStruct.TYPES.INT, "sectionframes") .addMember(StudioStruct.TYPES.SHORT, "zeroframespan") .addMember(StudioStruct.TYPES.SHORT, "zeroframecount") .addMember(StudioStruct.TYPES.INT, "zeroframeindex") .addMember(StudioStruct.TYPES.FLOAT, "zeroframestalltime") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true) .addArray(mstudiomovement_t, "movements", "movementindex", "nummovements", true) // Don't know if this is relative (Did not find a model to test with) .addArray(mstudioikrule_t, "ikrules", "ikruleindex", "numikrules", true) // Same. Don't know if index is offset .addArray(mstudiolocalhierarchy_t, "localhierarchy", "localhierarchyindex", "numlocalhierarchy", true) // Relative !? .addArray(mstudioanimsections_t, "sections", "sectionindex", "sectionframes", true); const mstudioevent_t = new StudioStruct() .addMember(StudioStruct.TYPES.FLOAT, "cycle") .addMember(StudioStruct.TYPES.INT, "event") .addMember(StudioStruct.TYPES.INT, "type") .addMember(StudioStruct.TYPES.SKIP(64), "options") .addMember(StudioStruct.TYPES.INT, "szeventindex") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "event", "szeventindex", true) .addArray(StudioStruct.TYPES.BYTE, "options", 12, 64, true); const mstudioautolayer_t = new StudioStruct() .addMember(StudioStruct.TYPES.SHORT, "iSequence") .addMember(StudioStruct.TYPES.SHORT, "iPose") .addMember(StudioStruct.TYPES.INT, "flags") .addMember(StudioStruct.TYPES.FLOAT, "start") .addMember(StudioStruct.TYPES.FLOAT, "peak") .addMember(StudioStruct.TYPES.FLOAT, "tail") .addMember(StudioStruct.TYPES.FLOAT, "end") const mstudioiklock_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "chain") .addMember(StudioStruct.TYPES.FLOAT, "flPosWeight") .addMember(StudioStruct.TYPES.FLOAT, "flLocalQWeight") .addMember(StudioStruct.TYPES.INT, "flags") .addMember(StudioStruct.TYPES.SKIP(32), "unused") const mstudioseqdesc_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "baseptr") .addMember(StudioStruct.TYPES.INT, "szlabelindex") .addMember(StudioStruct.TYPES.INT, "szactivitynameindex") .addMember(StudioStruct.TYPES.INT, "flags") .addMember(StudioStruct.TYPES.INT, "activity") .addMember(StudioStruct.TYPES.INT, "actweight") .addMember(StudioStruct.TYPES.INT, "numevents") .addMember(StudioStruct.TYPES.INT, "eventindex") .addMember(Vector, "bbmin") .addMember(Vector, "bbmax") .addMember(StudioStruct.TYPES.INT, "numblends") .addMember(StudioStruct.TYPES.INT, "animindexindex") .addMember(StudioStruct.TYPES.INT, "movementindex") .addMember(StudioStruct.TYPES.INT, "groupsize0") .addMember(StudioStruct.TYPES.INT, "groupsize1") .addMember(StudioStruct.TYPES.INT, "paramindex0") .addMember(StudioStruct.TYPES.INT, "paramindex1") .addMember(StudioStruct.TYPES.FLOAT, "paramstart0") .addMember(StudioStruct.TYPES.FLOAT, "paramstart1") .addMember(StudioStruct.TYPES.FLOAT, "paramend0") .addMember(StudioStruct.TYPES.FLOAT, "paramend1") .addMember(StudioStruct.TYPES.INT, "paramparent") .addMember(StudioStruct.TYPES.FLOAT, "fadeintime") .addMember(StudioStruct.TYPES.FLOAT, "fadeouttime") .addMember(StudioStruct.TYPES.INT, "localentrynode") .addMember(StudioStruct.TYPES.INT, "localexitnode") .addMember(StudioStruct.TYPES.INT, "nodeflags") .addMember(StudioStruct.TYPES.FLOAT, "entryphase") .addMember(StudioStruct.TYPES.FLOAT, "exitphase") .addMember(StudioStruct.TYPES.FLOAT, "lastframe") .addMember(StudioStruct.TYPES.INT, "nextseq") .addMember(StudioStruct.TYPES.INT, "pose") .addMember(StudioStruct.TYPES.INT, "numikrules") .addMember(StudioStruct.TYPES.INT, "numautolayers") .addMember(StudioStruct.TYPES.INT, "autolayerindex") .addMember(StudioStruct.TYPES.INT, "weightlistindex") .addMember(StudioStruct.TYPES.INT, "posekeyindex") .addMember(StudioStruct.TYPES.INT, "numiklocks") .addMember(StudioStruct.TYPES.INT, "iklockindex") .addMember(StudioStruct.TYPES.INT, "keyvalueindex") .addMember(StudioStruct.TYPES.INT, "keyvaluesize") .addMember(StudioStruct.TYPES.INT, "cycleposeindex") .addMember(StudioStruct.TYPES.SKIP(4*7), "unused") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "label", "szlabelindex", true) .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "activityname", "szactivitynameindex", true) .addArray(mstudioevent_t, "events", "eventindex", "numevents", true) .addArray(mstudioautolayer_t, "autolayer", "autolayerindex", "numautolayers", true) .addArray(mstudioiklock_t, "iklockindex", "numiklocks"); /** * @todo Allow functions in array parameters */ //.addArray(StudioStruct.TYPES.SHORT, "anims", "animindex", data => data.groupsize[0] * data.groupsize[1]) const mstudioattachment_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "sznameindex") .addMember(StudioStruct.TYPES.UINT, "flags") .addMember(StudioStruct.TYPES.INT, "localbone") .addMember(matrix3x4_t, "local") .addMember(StudioStruct.TYPES.SKIP(32), "unused") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true); const mstudiomodelgroup_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "szlabelindex") .addMember(StudioStruct.TYPES.INT, "sznameindex") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "label", "szlabelindex", true) .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true); const mstudioposeparamdesc_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "sznameindex") .addMember(StudioStruct.TYPES.UINT, "flags") .addMember(StudioStruct.TYPES.FLOAT, "start") .addMember(StudioStruct.TYPES.FLOAT, "end") .addMember(StudioStruct.TYPES.FLOAT, "loop") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true); const studiohdr_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "id") .addMember(StudioStruct.TYPES.INT, "version") .addMember(StudioStruct.TYPES.INT, "checksum") .addMember(StudioStruct.TYPES.STRING(64), "name") .addMember(StudioStruct.TYPES.INT, "dataLength") .addMember(Vector, "eyeposition") .addMember(Vector, "illumposition") .addMember(Vector, "hull_min") .addMember(Vector, "hull_max") .addMember(Vector, "view_bbmin") .addMember(Vector, "view_bbmax") .addMember(StudioStruct.TYPES.INT, "flags") .addMember(StudioStruct.TYPES.INT, "bone_count") .addMember(StudioStruct.TYPES.INT, "bone_index") .addMember(StudioStruct.TYPES.INT, "bonecontroller_count") .addMember(StudioStruct.TYPES.INT, "bonecontroller_offset") .addMember(StudioStruct.TYPES.INT, "hitbox_count") .addMember(StudioStruct.TYPES.INT, "hitbox_offset") .addMember(StudioStruct.TYPES.INT, "localanim_count") .addMember(StudioStruct.TYPES.INT, "localanim_offset") .addMember(StudioStruct.TYPES.INT, "localseq_count") .addMember(StudioStruct.TYPES.INT, "localseq_offset") .addMember(StudioStruct.TYPES.INT, "activitylistversion") .addMember(StudioStruct.TYPES.INT, "eventsindexed") .addMember(StudioStruct.TYPES.INT, "texture_count") .addMember(StudioStruct.TYPES.INT, "texture_offset") .addMember(StudioStruct.TYPES.INT, "texturedir_count") .addMember(StudioStruct.TYPES.INT, "texturedir_offset") .addMember(StudioStruct.TYPES.INT, "skinreference_count") .addMember(StudioStruct.TYPES.INT, "skinfamily_count") .addMember(StudioStruct.TYPES.INT, "skinreference_index") .addMember(StudioStruct.TYPES.INT, "bodypart_count") .addMember(StudioStruct.TYPES.INT, "bodypart_offset") .addMember(StudioStruct.TYPES.INT, "attachment_count") .addMember(StudioStruct.TYPES.INT, "attachment_offset") .addMember(StudioStruct.TYPES.INT, "localnode_count") .addMember(StudioStruct.TYPES.INT, "localnode_index") .addMember(StudioStruct.TYPES.INT, "localnode_name_index") .addMember(StudioStruct.TYPES.INT, "flexdesc_count") .addMember(StudioStruct.TYPES.INT, "flexdesc_index") .addMember(StudioStruct.TYPES.INT, "flexcontroller_count") .addMember(StudioStruct.TYPES.INT, "flexcontroller_index") .addMember(StudioStruct.TYPES.INT, "flexrules_count") .addMember(StudioStruct.TYPES.INT, "flexrules_index") .addMember(StudioStruct.TYPES.INT, "ikchain_count") .addMember(StudioStruct.TYPES.INT, "ikchain_index") .addMember(StudioStruct.TYPES.INT, "mouths_count") .addMember(StudioStruct.TYPES.INT, "mouths_index") .addMember(StudioStruct.TYPES.INT, "localposeparam_count") .addMember(StudioStruct.TYPES.INT, "localposeparam_offset") .addMember(StudioStruct.TYPES.INT, "surfaceprop_index") .addMember(StudioStruct.TYPES.INT, "keyvalue_index") .addMember(StudioStruct.TYPES.INT, "keyvalue_count") .addMember(StudioStruct.TYPES.INT, "ikblock_count") .addMember(StudioStruct.TYPES.INT, "ikblock_index") .addMember(StudioStruct.TYPES.FLOAT, "mass") .addMember(StudioStruct.TYPES.INT, "contents") .addMember(StudioStruct.TYPES.INT, "includemodel_count") .addMember(StudioStruct.TYPES.INT, "includemodel_index") .addMember(StudioStruct.TYPES.INT, "virtualModel") .addMember(StudioStruct.TYPES.INT, "animblocks_name_index") .addMember(StudioStruct.TYPES.INT, "animblocks_count") .addMember(StudioStruct.TYPES.INT, "animblocks_index") .addMember(StudioStruct.TYPES.INT, "animblockModel") .addMember(StudioStruct.TYPES.INT, "bonetable_index") .addMember(StudioStruct.TYPES.INT, "vertex_base") .addMember(StudioStruct.TYPES.INT, "offset_base") .addMember(StudioStruct.TYPES.BYTE, "directionaldotproduct") .addMember(StudioStruct.TYPES.BYTE, "rootLod") .addMember(StudioStruct.TYPES.BYTE, "numAllowedRootLods") .addMember(StudioStruct.TYPES.SKIP(5), "unused") .addMember(StudioStruct.TYPES.INT, "flexcontrollerui_count") .addMember(StudioStruct.TYPES.INT, "flexcontrollerui_index") .addMember(StudioStruct.TYPES.INT, "studiohdr2index") .addMember(StudioStruct.TYPES.INT, "unused") .addArray(mstudiotexture_t, "textures", "texture_offset", "texture_count") .addArray(stringIndex, "texturedirs", "texturedir_offset", "texturedir_count") .addArray(mstudiobodyparts_t, "bodyparts", "bodypart_offset", "bodypart_count") .addArray(mstudiobone_t, "bones", "bone_index", "bone_count") //.addArray(mstudiohitboxset_t, "hitboxes", "hitbox_offset", "hitbox_count") // Crashed on some files .addArray(mstudiobonecontroller_t, "bonecontroller", "bonecontroller_offset", "bonecontroller_count") .addArray(mstudioanimdesc_t, "localanims", "localanim_offset", "localanim_count") .addArray(mstudioseqdesc_t, "sequences", "localseq_offset", "localseq_count") .addArray(mstudioattachment_t, "attachments", "attachment_offset", "attachment_count") .addArray(mstudioiklock_t, "iklocks", "iklock_index", "iklock_count") .addArray(mstudiomodelgroup_t, "includemodel_index", "animblocks_count") .addArray(StudioStruct.TYPES.SHORT, "skinreferences", "skinreference_index", "skinreference_count") .addArray(mstudioposeparamdesc_t, "localposeparams", "localposeparam_offset", "localposeparam_count") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "surfaceProp", "surfaceprop_index") .addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "keyvalue", "keyvalue_index"); const vertexFileFixup_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "lod") .addMember(StudioStruct.TYPES.INT, "sourceVertexId") .addMember(StudioStruct.TYPES.INT, "numVertexes"); const vertexFileHeader_t = new StudioStruct() .addMember(StudioStruct.TYPES.INT, "id") .addMember(StudioStruct.TYPES.INT, "version") .addMember(StudioStruct.TYPES.INT, "checksum") .addMember(StudioStruct.TYPES.INT, "numLODs") .addMember(StudioStruct.TYPES.INT, "numLODVertexes0") .addMember(StudioStruct.TYPES.INT, "numLODVertexes1") .addMember(StudioStruct.TYPES.INT, "numLODVertexes2") .addMember(StudioStruct.TYPES.INT, "numLODVertexes3") .addMember(StudioStruct.TYPES.INT, "numLODVertexes4") .addMember(StudioStruct.TYPES.INT, "numLODVertexes5") .addMember(StudioStruct.TYPES.INT, "numLODVertexes6") .addMember(StudioStruct.TYPES.INT, "numLODVertexes7") .addMember(StudioStruct.TYPES.INT, "numFixups") .addMember(StudioStruct.TYPES.INT, "fixupTableStart") .addMember(StudioStruct.TYPES.INT, "vertexDataStart") .addMember(StudioStruct.TYPES.INT, "tangentDataStart") .addArray(vertexFileFixup_t, "fixups", "fixupTableStart", "numFixups"); module.exports = { studiohdr_t, vertexFileHeader_t, mstudiovertex_t }