Назад к блогу
Tutorial8 мин чтения

FiveM Пользовательские дополнения одежды: стримьте свои собственные дропы

Транслируйте свою собственную кастомную одежду в FiveM. Настройте аддоны, управляйте слотами, исправляйте конфликты и изучайте рабочий процесс создания эксклюзивных серверных дропов.

Agency Scripts

Основатель и ведущий разработчик Agency Scripts

Понимание системы одежды GTA V

В GTA V используется компонентная система одежды, где каждая часть одежды , это "drawable" в определенном компонентном слоте. На пешеходе 12 компонентных слотов, от головы (компонент 0) до обуви (компонент 6) и сумок с аксессуарами. Каждый слот может содержать несколько drawable, и каждый drawable может иметь несколько вариантов текстур. Например, компонент 11 (верхняя одежда) может иметь drawable 15 (кожаная куртка) с текстурами 0-3, представляющими черный, коричневый, красный и белый цвета. Понимание этой иерархии компонентов, drawable и текстур обязательно перед созданием кастомной одежды, так как каждая добавляемая вещь должна вписываться в существующую структуру. Модель пешехода для мультиплеера (MP) добавляет еще один уровень с собственной картой drawable, отличающейся от одиночного игрока, и FiveM серверы используют исключительно MP freemode модели.

Структура ресурса и стриминг

Пользовательская одежда в FiveM работает через систему стриминга. Вы создаёте ресурс, который указывает игре загружать дополнительные drawable и texture файлы вместе с базовыми игровыми ассетами. Структура ресурса следует строгим правилам именования, которые движок использует для определения, к какой модели педа, компоненту и индексу drawable принадлежит каждый файл. Неправильная структура папок , самая частая причина, по которой одежда не появляется в игре. Ваш ресурс должен содержать fxmanifest.lua которые объявляют файлы стриминга, а фактические данные одежды помещаются в stream каталог с правильной иерархией подпапок.

-- fxmanifest.lua for a clothing addon
fx_version 'cerulean'
game 'gta5'

-- The resource name matters: it determines load priority
-- Prefix with zzz_ to ensure it loads after base game assets
this_is_a_map 'yes'
lua54 'yes'

-- All streaming assets inside /stream/ are auto-detected
-- No need to list individual files

Папка stream следует точной иерархии. Для мужской одежды MP freemode файлы размещаются в stream/mp_m_freemode_01_mp_m_[dlcname]/. Для женского пола замените mp_m с mp_f. Внутри этой папки размещаются файлы YDD (drawable dictionary), YTD (texture dictionary) и YMT (metadata). Конвенция именования кодирует, какой компонент и индекс drawable представляет каждый файл. Файл с именем mp_m_freemode_01_mp_m_mypack_jbib_000_u.ydd является drawable 0 для компонента 11 (jbib = куртка/верх) на мужском freemode ped из DLC пакета "mypack".

-- Folder structure example
stream/
  mp_m_freemode_01_mp_m_mypack/
    mp_m_freemode_01_mp_m_mypack.ymt          -- metadata file
    mp_m_freemode_01_mp_m_mypack_jbib_000_u.ydd   -- tops drawable 0
    mp_m_freemode_01_mp_m_mypack_jbib_diff_000_a_uni.ytd  -- texture for tops 0
    mp_m_freemode_01_mp_m_mypack_jbib_001_u.ydd   -- tops drawable 1
    mp_m_freemode_01_mp_m_mypack_jbib_diff_001_a_uni.ytd  -- texture for tops 1
    mp_m_freemode_01_mp_m_mypack_lowr_000_u.ydd   -- pants drawable 0
    mp_m_freemode_01_mp_m_mypack_lowr_diff_000_a_uni.ytd  -- texture for pants 0

ID компонентов и соглашения по именованию

Каждый компонент одежды имеет определённое сокращение, используемое в именах файлов. Запомнить их критично, так как одна опечатка приведёт к тому, что игра не сможет найти ваш ресурс. Карта компонентов: голова (компонент 0, без одежды), berd (1, маски), волосы (2), uppr (3, руки/перчатки), lowr (4, штаны/ноги), рука (5, сумки/парашюты), футы (6, обувь), teef (7, аксессуары, такие как цепочки), аккаунты (8, нижние рубашки/аксессуары для тела), задача (9, бронежилеты), decl (10, наклейки/значки), и jbib (11, верхняя одежда/куртки). Для аксессуаров используется другая система: p_head (шляпы), p_eyes (очки), p_ears (серьги), и p_lwrist/p_rwrist (часы/браслеты).

-- Component ID reference for scripting
local ComponentNames = {
    [0]  = 'head',   -- Face (not clothing)
    [1]  = 'berd',   -- Masks
    [2]  = 'hair',   -- Hair styles
    [3]  = 'uppr',   -- Arms / Gloves
    [4]  = 'lowr',   -- Pants / Legs
    [5]  = 'hand',   -- Bags / Parachutes
    [6]  = 'feet',   -- Shoes
    [7]  = 'teef',   -- Accessories (chains, ties)
    [8]  = 'accs',   -- Undershirts
    [9]  = 'task',   -- Body Armor
    [10] = 'decl',   -- Decals / Badges
    [11] = 'jbib',   -- Tops / Jackets
}

-- Get total drawables for a component (useful for clothing menus)
local function GetMaxDrawables(ped, componentId)
    return GetNumberOfPedDrawableVariations(ped, componentId)
end

-- Get texture count for a specific drawable
local function GetMaxTextures(ped, componentId, drawableId)
    return GetNumberOfPedTextureVariations(ped, componentId, drawableId)
end

-- Apply clothing to ped
local function SetClothing(ped, componentId, drawableId, textureId)
    SetPedComponentVariation(ped, componentId, drawableId, textureId, 0)
end

Понимание файлов YMT

Файл YMT (Ped Metadata) , это связующее звено, которое удерживает комплект одежды вместе. Это XML-файл, который сообщает игровому движку, сколько drawable-объектов существует в каждом компоненте, сколько текстур у каждого drawable, какой звук воспроизводить при движении одежды и различные свойства рендеринга. Без правильно настроенного YMT игра не распознает ваши drawable, даже если файлы YDD и YTD идеально созданы. YMT должен перечислять каждую комбинацию drawable и текстуры в вашем паке. Отсутствие хотя бы одной записи означает, что этот элемент будет невидим. Редактирование файлов YMT вручную подвержено ошибкам, поэтому большинство создателей используют инструменты, такие как CodeWalker или специализированные генераторы YMT, которые автоматически создают файл из содержимого вашей папки с ресурсами.

<!-- Simplified YMT structure (XML representation) -->
<CPedVariationInfo>
  <availComp>
    <!-- Bitfield indicating which components have data -->
    <Item value="2048" />  <!-- Only jbib (component 11) -->
  </availComp>
  <compInfos>
    <Item> <!-- Component 11 (jbib / tops) -->
      <drawblDict>
        <Item>  <!-- Drawable 0 -->
          <numAlternatives value="0" />
          <numTexVariations value="3" />  <!-- 3 color variants -->
          <clothData>
            <ownsCloth value="false" />
          </clothData>
        </Item>
        <Item>  <!-- Drawable 1 -->
          <numAlternatives value="0" />
          <numTexVariations value="2" />  <!-- 2 color variants -->
          <clothData>
            <ownsCloth value="false" />
          </clothData>
        </Item>
      </drawblDict>
    </Item>
  </compInfos>
</CPedVariationInfo>

Вариации текстур и качество

Каждый drawable может иметь несколько вариантов текстур, которые представляют разные цвета или узоры одной и той же модели одежды. Базовый файл текстуры использует шаблон именования [pack]_[component]_diff_[drawableIndex]_[textureIndex]_uni.ytd. Текстуры должны создаваться с размерами степеней двойки (512x512, 1024x1024, 2048x2048) для оптимальной совместимости с GPU. Текстуры более высокого разрешения выглядят лучше, но потребляют больше VRAM, который является ограниченным ресурсом, особенно на серверах, где игроки одновременно загружают десятки паков одежды. Практическое правило , использовать 1024x1024 для большинства предметов одежды и резервировать 2048x2048 для предметов с тонкими деталями, такими как вышитые логотипы или сложные узоры. Каждый файл YTD может содержать несколько слоёв текстур, включая diffuse (цвет), normal (детали поверхности) и specular (блеск), хотя большинство паков одежды FiveM используют только слой diffuse для уменьшения размера файлов.

Создание скрипта меню одежды

После запуска вашего стримингового ресурса вам нужен способ для игроков просматривать и применять одежду. Скрипт меню одежды перебирает все доступные drawables по компонентам и позволяет игрокам в реальном времени примерять их на персонажа. Основная логика использует GetNumberOfPedDrawableVariations определять, сколько drawable-элементов существует для каждого компонента, затем SetPedComponentVariation применить выбранный вариант. Оберните это в меню ox_lib или NUI для более качественного пользовательского опыта. Сложная часть , это обработка превью от первого лица и углов камеры, чтобы игроки могли видеть, что они примеряют, без неудобных обрезаний или проблем с зумом.

-- client/clothing_menu.lua
local function OpenClothingMenu()
    local ped = PlayerPedId()
    local components = {}

    for compId = 0, 11 do
        local maxDrawables = GetNumberOfPedDrawableVariations(ped, compId)
        if maxDrawables > 0 then
            local currentDrawable = GetPedDrawableVariation(ped, compId)
            local currentTexture = GetPedTextureVariation(ped, compId)
            local maxTextures = GetNumberOfPedTextureVariations(ped, compId, currentDrawable)

            table.insert(components, {
                id = compId,
                label = ComponentNames[compId] or ('Component ' .. compId),
                drawable = currentDrawable,
                texture = currentTexture,
                maxDrawable = maxDrawables - 1,
                maxTexture = maxTextures - 1,
            })
        end
    end

    -- Build menu options
    local options = {}
    for _, comp in ipairs(components) do
        options[#options + 1] = {
            title = comp.label,
            description = ('Drawable: %d/%d | Texture: %d/%d'):format(
                comp.drawable, comp.maxDrawable, comp.texture, comp.maxTexture),
            onSelect = function()
                OpenComponentEditor(comp.id)
            end
        }
    end

    lib.registerContext({ id = 'clothing_menu', title = 'Wardrobe', options = options })
    lib.showContext('clothing_menu')
end

local function OpenComponentEditor(componentId)
    local ped = PlayerPedId()
    local maxDraw = GetNumberOfPedDrawableVariations(ped, componentId) - 1

    -- Interactive drawable browser with live preview
    local input = lib.inputDialog('Select Clothing', {
        { type = 'slider', label = 'Style', min = 0, max = maxDraw, default = GetPedDrawableVariation(ped, componentId) },
    })

    if input then
        local drawableId = input[1]
        local maxTex = GetNumberOfPedTextureVariations(ped, componentId, drawableId) - 1
        SetPedComponentVariation(ped, componentId, drawableId, 0, 0)

        if maxTex > 0 then
            local texInput = lib.inputDialog('Select Color', {
                { type = 'slider', label = 'Variant', min = 0, max = maxTex, default = 0 },
            })
            if texInput then
                SetPedComponentVariation(ped, componentId, drawableId, texInput[1], 0)
            end
        end
    end
end

Распространённые проблемы и устранение неполадок

Самая частая проблема , одежда отображается невидимой или как неправильный предмет. Это почти всегда связано с неправильным YMT-файлом, который некорректно указывает количество drawable и texture. Проверьте, что ваш YMT содержит точное число drawable и texture, соответствующее содержимому папки stream. Ещё одна распространённая проблема , порядок загрузки ресурсов: если ваш пакет одежды загружается раньше базовых игровых ресурсов, индексы drawable могут конфликтовать и перезаписывать ванильную одежду. Добавьте префикс к имени ресурса zzz_ обеспечить загрузку последним. Размытие текстур обычно указывает на то, что YTD использует слишком низкое разрешение или mipmaps сгенерированы неправильно. Всегда генерируйте mipmaps при экспорте ваших YTD-файлов в CodeWalker. Наконец, если одежда отображается на мужских моделях, но не на женских, или наоборот, дважды проверьте, что у вас есть отдельные папки для mp_m_freemode_01 и mp_f_freemode_01 с правильно подобранными по полу файлами мешей, так как мужские и женские модели педов имеют разные скелетные риги и требуют отдельной геометрии.

Оптимизация производительности сервера

Пользовательские наборы одежды являются одним из крупнейших факторов, влияющих на размер загрузки сервера и использование VRAM клиентом. Один плохо оптимизированный набор с 100 высококачественными предметами может добавить гигабайты к требованиям загрузки сервера. Чтобы сохранить управляемость, сжимайте ваши YTD текстуры с помощью форматов DXT5 или BC7, которые обеспечивают хорошее качество изображения при значительно меньшем размере файла. Ограничьте каждый набор разумным количеством предметов, обычно от 20 до 50 штук, и разделяйте большие коллекции на несколько ресурсов, которые можно загружать независимо. Рассмотрите возможность предоставления «лайт» версии популярных наборов с текстурами 512x512 для игроков с менее мощным оборудованием. В скриптах избегайте повторных вызовов SetPedComponentVariation в цикле, так как каждый вызов вызывает обновление модели. Группируйте изменения одежды, собирая все обновления компонентов и применяя их последовательно в одном кадре, чтобы минимизировать визуальные скачки и нагрузку на рендеринг.

Готовы начать?

Возьмите скрипты в нашем магазине или заходите в Discord за поддержкой, обновлениями и анонсами.