Quick Reply
Search this Thread
Test Subject
Original Poster
#1 Old 16th Jan 2024 at 12:33 AM
Default Understanding the Block Signature for MLOD
Hi there,

I'm posting here for the first time, so let me know if I mess anything up!

I'm really interested in learning how to understand some of the binary representations of the sims 4 packages. Of special interest is the MLOD chunk. Over on this forum a treasure snippet was posted by the simgurumodsquad in response to Cmarinetti's request for a .bt file of the new MLOD chunk.

https://forums.thesims.com/en_US/di...mlod-0x01d10f34 (snippet follows)
```

//
// MLOD block
//

typedef struct
{
UINT32 mState;
UINT32 mStartIndex;
UINT32 mMinVertexIndex;
UINT32 mVertexCount;
UINT32 mPrimitiveCount;
} PrimitiveInfoForState;

typedef struct
{
FLOAT min[3];
FLOAT max[3];
} BoundingBox;

typedef struct(int version)
{
UINT32 mMeshLength;
local int nextBlock = FTell() + mMeshLength;

UINT32 mHashedName <format=hex>;
UINT32 mMaterialRef <format=hex>;
UINT32 mVertexFormatRef <format=hex>;
UINT32 mVertexBufferRef <format=hex>;
UINT32 mIndexBufferRef <format=hex>;
UINT32 mPrimitiveType : 8 <format=hex>;
UINT32 mMeshFlags : 24 <format=hex>;
UINT32 mStreamOffset;
UINT32 mStartVertex;
UINT32 mStartIndex;
UINT32 mMinVertexIndex;
UINT32 mVertexCount;
UINT32 mPrimitiveCount;
BoundingBox mBoundingBox;
INT32 mSkinRef;
UINT32 mBoneCount;

if (mBoneCount>0)
{
UINT32 mBoneHash[mBoneCount];
}

UINT32 mMeshMaterial <format=hex>;

UINT32 mNumPrimInfo;
if ( mNumPrimInfo > 0 )
{
PrimitiveInfoForState mPrimitiveInfoForState[mNumPrimInfo];
}
UINT32 mParentBone <format=hex>;
float mMirrorPlane[4];
UINT32 mSortOrderHint;

if (version >= 0x206 && (mMeshFlags & 0x4000) && mBoneCount > 0)
{
// Bone local bounding boxes
BoundingBox mBoundingBoxBones[mBoneCount];
}

if (FTell()!= nextBlock)
{
Warning("Not all data read from MLOD.");
return -1;
}

} MeshDiskFormat;

typedef struct
{
BlockSignature mMLODSignature; // MLOD
UINT32 mVersion <format=hex>;
UINT32 mMeshCount;
MeshDiskFormat mMeshData(mVersion)[mMeshCount] <optimize=false>;
} MLOD;
```
Almost everything works for me, except that they include this thing ` BlockSignature mMLODSignature; // MLOD` towards the bottom which doesn't appear to be defined anywhere in the file.

I followed as much of this as I could understand (https://modthesims.info/wiki.php?title=Sims_4:RCOL), but I think my imhex pattern showed I didn't have it quite right (see the imhex screenshot), and some things that should have non-zero chunksize were still 0 which was a pretty good indication I was on the wrong track.


Can anyone help me understand how the MLOD chunk header/signature is defined?

Thanks for any info that can be shared!
Screenshots
Test Subject
#2 Old 12th Mar 2025 at 8:57 PM Last edited by zmilla : 13th Mar 2025 at 12:55 AM.
I know this thread is old, but I have the answer! The RCOL header for the Sims 4 on the wiki is incorrect.

All RCOL resources have a header that defines what blocks are stored in that resource. These blocks, (MODL, VBUF, IBUF, etc), all start with a respective 4 letter signature (except swizzle), which is 4 bytes of ASCII characters. You can see the "MLOD" signature in the screenshot you posted in the ASCII view, you just haven't gotten to it because you didn't finish reading the header.

MLODs also sometimes contain additional information after SortOrderHint, but this is based on the flags. You can skip over it by seeking to nextBlock.

For anyone looking for binary templates, the original website is down, but they are still viewable on the internet archive.

Here's the Sims 4 RCOL header:
Code:
typedef struct
{
    UINT64 instance;
    UINT32 type;
    UINT32 group;
} ResourceKeyInstanceFirst;

typedef struct
{
    UINT32 position;
    UINT32 length;
} ObjectData;

typedef struct
{
    UINT32 mContextversion;
    UINT32 mPublicKeyCount;
    UINT32 mExternalKeyCount;
    UINT32 mDelayLoadKeyCount;
    UINT32 mObjectCount;
    
    if(mPublicKeyCount > 0)
    {
        ResourceKeyInstanceFirst mPublicObject[mPublicKeyCount];
    }
    if(mObjectCount-mPublicKeyCount > 0)
    {
        ResourceKeyInstanceFirst mPrivateObject[mObjectCount-mPublicKeyCount];
    }
    if(mExternalKeyCount > 0)
    {
        ResourceKeyInstanceFirst mExternalReferences[mExternalKeyCount];
    }
    if(mDelayLoadKeyCount > 0)
    {
        ResourceKeyInstanceFirst mDelayLoadReferences[mDelayLoadKeyCount];
    }
    if(mObjectCount > 0)
    {
        ObjectData mObjectData[mObjectCount];
    }
} ContextData;
Back to top