Work with drawable components and props using collections

Inside the GTAV Ped drawable components and props are stored in named groups called collections. However, collections were previously unavailable for FiveM users. The drawable components and props were indexed through global index. On every TU (Title Update) the global index of custom drawable components and props would change (see below for more details on why it happens). This complicates migration to the latest game build.

The new set of natives allows accessing drawable components and props through collections. The collection-based indexes remain stable after TUs. So using these natives will simplify all future TU updates for a server.

Note: The new natives are currently available for GTAV and on client side only.

How drawable components and props indexing works

Note: Drawable components and props are stored in Ped in the same way. Below we will refer to drawable components / drawables only.

You can think of collections in Ped as list of buckets placed one after another. Each collection is named and contains multiple drawables.

Global index is an index of drawable starting from the beginning of the set. Local index is an index of drawable starting from the beginning of each collection.

E.g.:

Official GTAV collections Custom collections
Collection names "" "female_freemode_beach" "female_xmas" "custom_collection_1" "custom_collection_2"
Local indexes 0 1 0 1 2 3 0 1 2 0 1 2 0 1
Global indexes 0 1 2 3 4 5 6 7 8 9 10 11 12 13

The first collection corresponds to the base game (without any DLCs). After the base game collection follow collection that correspond to official DLCs. Custom collections are added to the end.

After TU is released and new official DLC collection is added - all custom collections are shifted. So, the global indexes that correspond to custom collections shift and must be updated on every TU. While the indexes that are relative to the beginning of a collection will remain stable after TU.

Where collection name is set

The base game name collection is an empty string. Names of other collections are set by <CPedVariationInfo name="..."> tag of the corresponding .ymt file. E.g. see Grand Theft Auto V\update\x64\dlcpacks\mp2024_01\dlc.rpf\x64\models\cdimages\mp2024_01_female.rpf\mp_f_freemode_01_mp_f_2024_01.ymt base game file.

New natives

There are three groups of new natives:

  • Natives to get general information about collections
  • Natives to convert between global and local indexes.
  • Natives that are analogues to the existing natives that work with drawable components and props. But instead of working with global indexes thy work with collection names and local indexes.

General info natives

Conversion between global and local indexing

Analogues to existing natives

Old (global index based) nativeNew (collection-based) native
SET_PED_COMPONENT_VARIATIONSET_PED_COLLECTION_COMPONENT_VARIATION
SET_PED_PROP_INDEXSET_PED_COLLECTION_PROP_INDEX
SET_PED_PRELOAD_VARIATION_DATASET_PED_COLLECTION_PRELOAD_VARIATION_DATA
SET_PED_PRELOAD_PROP_DATASET_PED_COLLECTION_PRELOAD_PROP_DATA
GET_NUMBER_OF_PED_DRAWABLE_VARIATIONSGET_NUMBER_OF_PED_COLLECTION_DRAWABLE_VARIATIONS
GET_NUMBER_OF_PED_PROP_DRAWABLE_VARIATIONSGET_NUMBER_OF_PED_COLLECTION_PROP_DRAWABLE_VARIATIONS
GET_NUMBER_OF_PED_TEXTURE_VARIATIONSGET_NUMBER_OF_PED_COLLECTION_TEXTURE_VARIATIONS
GET_NUMBER_OF_PED_PROP_TEXTURE_VARIATIONSGET_NUMBER_OF_PED_COLLECTION_PROP_TEXTURE_VARIATIONS
IS_PED_COMPONENT_VARIATION_VALIDIS_PED_COLLECTION_COMPONENT_VARIATION_VALID
IS_PED_COMPONENT_VARIATION_GEN9_EXCLUSIVEIS_PED_COLLECTION_COMPONENT_VARIATION_GEN9_EXCLUSIVE
GET_PED_DRAWABLE_VARIATIONGET_PED_DRAWABLE_VARIATION_COLLECTION_LOCAL_INDEX
GET_PED_DRAWABLE_VARIATIONGET_PED_DRAWABLE_VARIATION_COLLECTION_NAME

Examples

Below are some example lua scripts that illustrate usage of the new natives.

Listing all collections available for ped and number of component and prop drawable variations available in each collection:

function printFullCollectionInfo(ped, collectionName)
    print(string.format("   Name: \"%s\"", collectionName))

    print("   Number of drawable variations per component number:")
    -- See https://docs.fivem.net/natives/?_0x262B14F48D29DE80 for the list of all components.
    for i = 0, 12 do
        local drawableVariationsCount = GetNumberOfPedCollectionDrawableVariations(ped, i, collectionName)
        print(string.format("       For component %d: %d", i, drawableVariationsCount))
    end

    print("   Number of drawable variations per anchor point:")
    -- See https://docs.fivem.net/natives/?_0x93376B65A266EB5F for the list of all anchor points.
    for i = 0, 12 do
        local drawablePropVariationsCount = GetNumberOfPedCollectionPropDrawableVariations(ped, i, collectionName)
        print(string.format("       For anchor %d: %d", i, drawablePropVariationsCount))
    end
end

function printFullCollectionsInfo(ped)
    local collectionsCount = GetPedCollectionsCount(ped)
    print(string.format("Found %d collections", collectionsCount))
    for i = 0, collectionsCount - 1 do
        local collectionName = GetPedCollectionName(ped, i)

        print(string.format("Collection %d", i))
        printFullCollectionInfo(ped, collectionName)
    end
end

RegisterCommand('PrintFullPlayerPedCollectionsInfo', function(source)
    local playerPed = PlayerPedId()
    printFullCollectionsInfo(playerPed)
end, true)

Set new ped look (for mp_f_freemode_01 ped model, see https://docs.fivem.net/docs/game-references/ped-models/, other models may have less drawable variations available):

function setLook(ped)
    -- Use head (component id 0) from base game collection (empty string) and local index 27.
    -- Base game collection indexes and global indexes are the same (see documentation above).
    -- Same as SetPedComponentVariation(ped, 0, 27, 0, 0)
    SetPedCollectionComponentVariation(ped, 0, '', 27, 0, 0)

    -- Use pants (component id 4) from mpHeist DLC collection ("female_heist"), local index 9 and texture number 3.
    -- Same as SetPedComponentVariation(ped, 4, 41, 3, 0)
    SetPedCollectionComponentVariation(ped, 4, 'female_heist', 9, 3, 0)

    -- Use hat (anchor point 0) from mpBiker DLC collection ("mp_f_bikerdlc_01"), local index 0 and texture number 0.
    -- Same as SetPedPropIndex(ped, 0, 82, 0, 0)
    SetPedCollectionPropIndex(ped, 0, 'mp_f_bikerdlc_01', 0, 0, false)
end

function testInvalidComponentVariation(ped)
    -- Attempt to set shirt (component id 11) from mpBeach DLC collection ("female_freemode_beach") but invalid (out of bounds) local index 999999.
    -- The component drawable variation will not be set since the variation is invalid.
    SetPedCollectionComponentVariation(ped, 11, 'female_freemode_beach', 999999, 0, 0)

    -- Confirm that previously requested drawable variation is indeed invalid.
    -- Same as IsPedComponentVariationValid(ped, 11, 999999 + 16, 0, 0)
    -- +16 because there are 16 drawable variations in the base game collection that go before the mpBeach DLC collection.
    if not IsPedCollectionComponentVariationValid(ped, 11, 'female_freemode_beach', 999999, 0, 0) then
        print("Invalid component drawable variation was requested.")
    end
end

RegisterCommand('SetPlayerPedLook', function(source)
    local playerPed = PlayerPedId()
    setLook(playerPed)
    testInvalidComponentVariation(playerPed)
end, true)

Print information about drawable variations that are set for the ped:

function printPedLookInfo(ped, componentId)
    print(string.format("For component id %d, the following drawable is used:", componentId))

    local collectionName = GetPedDrawableVariationCollectionName(ped, componentId)
    local collectionLocalIndex = GetPedDrawableVariationCollectionLocalIndex(ped, componentId)

    print(string.format("   Collection name: \"%s\"", collectionName))
    print(string.format("   Local drawable index: %d", collectionLocalIndex))

    -- Will get the same result as if we called GetPedDrawableVariation(ped, componentId)
    local globalDrawableIndex = GetPedDrawableGlobalIndexFromCollection(ped, componentId, collectionName, collectionLocalIndex)

    print(string.format("   Which corresponds to global drawable index: %d", globalDrawableIndex))
end

RegisterCommand('PrintPlayerPantsInfo', function(source)
    local playerPed = PlayerPedId()
    -- Print info about drawable variation that is set as pants (component id 4).
    printPedLookInfo(playerPed, 4)
end, true)