Assets 3D

Props personalizados FiveM: del modelo 3D al objeto en el juego

Cómo agregar props personalizados en FiveM: archivos ydr, ytd y ytyp, stream, spawn por script, ymap, ox_target y cómo generarlos al instante con BLDR.

· 11 min de lectura

Los props personalizados son esos detalles que hacen que un servidor de FiveM se sienta propio: un vaso de café con la marca de la cafetería, una mesa para el laboratorio de drogas, un trofeo para los ganadores de un evento, un letrero con el logo de tu server. GTA V trae miles de props, pero tarde o temprano vas a necesitar uno que no existe.

Esta guía cubre todo el camino, desde un modelo 3D hasta un objeto que los jugadores pueden ver, tocar y agarrar: qué archivos necesita un prop, las dos formas de hacerlos, cómo hacerles stream y cómo spawnearlos, colocarlos y usarlos desde scripts. Si buscabas cómo agregar props en FiveM, está todo aquí.

Versión corta: un prop de FiveM es un modelo .ydr, un diccionario de texturas .ytd y un archivo de archetypes .ytyp, opcionalmente con una collision .ybn. Ponlos en la carpeta stream/ de un resource, declara el .ytyp con data_file 'DLC_ITYP_REQUEST' en fxmanifest.lua y después spawnea el prop con RequestModel y CreateObject o colócalo de forma permanente con un .ymap.

De qué está hecho un prop de FiveM

Un prop no es un solo archivo. GTA V divide un objeto en varias piezas, cada una con su función:

De qué está hecho un prop personalizado

ArchivoQué contiene¿Obligatorio?
.ydrEl drawable: la malla, sus materiales y sus niveles de detalleSí
.ytdEl diccionario de texturas: las imágenes que usan los materiales del modeloSí, salvo que las texturas estén embebidas en el .ydr
.ytypLas definiciones de archetype: le dicen al juego que el modelo existe y cómo tratarloSí, para modelos personalizados
.ybnCollision estática: contra lo que chocan jugadores y vehículosOpcional, pero casi siempre la vas a querer

Para ver en detalle estos y los demás formatos de RAGE, mira Formatos de archivo de GTA V y FiveM.

Por qué importa el .ytyp

El .ydr es solo geometría. El juego no sabe que existe un objeto llamado myrp_coffee_cup hasta que un archetype lo dice. El archetype dentro de un .ytyp registra, entre otras cosas:

  • el nombre del modelo, que se convierte en su hash;
  • el diccionario de texturas del que tiene que cargar las texturas;
  • su bounding box y bounding sphere, que el motor usa para decidir cuándo el objeto está en pantalla;
  • su distancia de LOD, la distancia a la que el objeto deja de dibujarse;
  • flags que controlan la física y el renderizado.

Sin un archetype cargado, CreateObject no tiene nada que crear y los archivos de mapa no pueden colocar el objeto. Por eso un .ytyp que falta o que no está declarado es la razón más común de que un prop personalizado "no funcione".

Pipeline 1: la forma tradicional (Blender + Sollumz)

Las herramientas estándar de la comunidad son gratis:

  • Blender con el add-on Sollumz. Sollumz importa y exporta formatos de GTA V directo desde Blender, incluyendo .ydr, .ybn, .ytyp y, en las versiones recientes, diccionarios de texturas .ytd. Requiere Blender 4.0 o superior; en Blender 4.2+ se instala como extensión desde https://repo.sollumz.org/.
  • CodeWalker para explorar los archivos del juego, ver modelos en el mundo y crear archivos .ymap para colocar objetos en el mapa.
  • OpenIV se sigue usando mucho para explorar y extraer archivos del juego, pero no lo necesitas para armar un prop.

El flujo, a grandes rasgos:

  1. Modela el objeto en Blender o importa un modelo existente. Respeta la escala real: una unidad de Blender es un metro en el juego.
  2. Aplica los shaders de Sollumz a los materiales y convierte la malla en un drawable.
  3. Créale una collision, ya sea con primitivas simples (cajas, cilindros) o con una malla low-poly.
  4. Crea el archetype en las herramientas de .ytyp de Sollumz: define el nombre, el diccionario de texturas, la distancia de LOD y el tipo de asset.
  5. Exporta el .ydr, .ytd, .ybn y .ytyp.

Este camino te da control total y es el indicado para props detallados y protagonistas. El costo es el tiempo: modelado, UV unwrap, texturizado y aprender el flujo de Sollumz suman horas para un solo prop, y mucho más la primera vez.

Pipeline 2: generarlo con BLDR

La herramienta 3D de BLDR te ahorra la mayor parte de ese trabajo:

Herramienta 3D de BLDR: imagen a 3D, texto a 3D e importación de GLB con exportación a YDR

  1. Abre 3D y genera un modelo a partir de un prompt de texto o una imagen de referencia, o importa tu propio GLB.
  2. Edita el modelo y píntale las texturas hasta que quede como quieres.
  3. Exporta. La descarga es un zip que ya es un resource de FiveM, con el nombre de tu proyecto:
myrp_coffee_cup/ ├── fxmanifest.lua ├── cl_spawn.lua ← optional test command └── stream/ ├── myrp_coffee_cup.ydr ├── myrp_coffee_cup.ytd └── myrp_coffee_cup.ytyp

El manifest ya declara el archivo de archetypes, y el cl_spawn.lua opcional registra un comando /spawn_<model> que pone el prop frente a ti para probarlo. Exportar requiere un plan pago.

Uses el pipeline que uses, el resultado es el mismo conjunto de archivos, y todo lo que sigue aplica a los dos.

Hacer stream del prop desde un resource

Pon los archivos en la carpeta de un resource y avísale a FXServer del .ytyp:

fx_version 'cerulean'
game 'gta5'

data_file 'DLC_ITYP_REQUEST' 'stream/myrp_coffee_cup.ytyp'

Todo lo que está dentro de stream/ se envía a los jugadores automáticamente. La línea data_file es la que hace que el juego registre de verdad los archetypes del .ytyp; hacer stream del archivo solo no alcanza.

Después inicia el resource en server.cfg:

ensure myrp_coffee_cup

Si tienes muchos props, ponlos todos en un mismo resource con un solo .ytyp que contenga todos los archetypes, o agrega varias líneas data_file. Pocos resources bien organizados son más fáciles de mantener que cincuenta chiquitos. ¿Recién empiezas con resources? Cómo crear un servidor de FiveM explica la estructura de carpetas.

Spawnear un prop desde un script

Para crear un prop en tiempo de ejecución, carga su modelo, crea el objeto y después libera el modelo:

local function spawnProp(modelName, coords)
    local model = joaat(modelName)

    if not IsModelInCdimage(model) then
        print(('Model %s does not exist'):format(modelName))
        return
    end

    RequestModel(model)
    while not HasModelLoaded(model) do
        Wait(0)
    end

    local obj = CreateObject(model, coords.x, coords.y, coords.z, true, true, false)
    PlaceObjectOnGroundProperly(obj)
    FreezeEntityPosition(obj, true)
    SetModelAsNoLongerNeeded(model)

    return obj
end

RegisterCommand('coffeecup', function()
    local coords = GetOffsetFromEntityInWorldCoords(PlayerPedId(), 0.0, 1.5, 0.0)
    spawnProp('myrp_coffee_cup', coords)
end, false)

Qué hace cada parte:

  • RequestModel / HasModelLoaded – CreateObject espera que el modelo ya esté cargado. Si te saltas esto, la creación falla.
  • CreateObject(model, x, y, z, isNetwork, netMissionEntity, doorFlag) – el cuarto argumento decide si los demás jugadores ven el objeto. false crea un objeto solo del lado del cliente.
  • PlaceObjectOnGroundProperly – pega el objeto al suelo que tiene debajo.
  • FreezeEntityPosition – evita que el objeto se mueva al empujarlo o que se caiga. Úsalo para muebles y decoración.
  • SetModelAsNoLongerNeeded – libera el modelo de tu script una vez que el objeto ya existe.

Borra los objetos que ya no necesitas con DeleteEntity, o se quedan en el mundo hasta que se detenga el resource. Cuando el objeto tiene que ser del servidor, CreateObject y CreateObjectNoOffset también están disponibles en scripts de servidor.

Colocar props permanentes con un .ymap

Para props que son parte del mapa, como un letrero en un edificio o los muebles de una tienda, los scripts no son la herramienta correcta. Usa un .ymap, el archivo que GTA V usa para colocar entidades en el mundo.

  1. Abre CodeWalker y crea un proyecto nuevo.
  2. Agrega los archivos de tu prop al proyecto para que CodeWalker conozca tu archetype.
  3. Crea un .ymap nuevo en el proyecto, agrega entidades con el nombre de tu modelo y muévelas a su lugar en la vista del mundo.
  4. Guarda el .ymap y ponlo en la carpeta stream/ de tu resource junto al prop.

Los props de mapa colocados así cargan y descargan junto con el mundo, no consumen tiempo de script y sobreviven a los reinicios sin nada de código. El mismo método escala a interiores completos; mira MLOs de FiveM para armar edificios enteros.

Hacer props interactivos

Targetear un prop con ox_target

Con ox_target puedes agregar opciones de interacción a todas las instancias de tu modelo, ya sea que se hayan spawneado por script o colocado con un .ymap:

exports.ox_target:addModel('myrp_coffee_cup', {
    {
        name = 'myrp_drink_coffee',
        icon = 'fa-solid fa-mug-hot',
        label = 'Drink coffee',
        distance = 2.0,
        onSelect = function(data)
            print(('Drinking from entity %s'):format(data.entity))
        end,
    },
})

Para un solo objeto spawneado en vez de todas las copias del modelo, usa exports.ox_target:addLocalEntity(entity, options). Ojo: el repositorio original de overextended está archivado; el fork mantenido vive en CommunityOx.

Sostener un prop en la mano

Los props también sirven como objetos en la mano: un celular, un vaso, una carpeta. Pega el objeto a un hueso del ped con AttachEntityToEntity:

local function holdProp(modelName)
    local ped = PlayerPedId()
    local model = joaat(modelName)

    RequestModel(model)
    while not HasModelLoaded(model) do
        Wait(0)
    end

    local coords = GetEntityCoords(ped)
    local obj = CreateObject(model, coords.x, coords.y, coords.z, true, true, false)
    local boneIndex = GetPedBoneIndex(ped, 57005) -- SKEL_R_Hand (mano derecha)

    AttachEntityToEntity(obj, ped, boneIndex,
        0.12, 0.0, -0.03,   -- offset de posición
        -80.0, 0.0, 0.0,    -- rotación
        true, true, false, true, 1, true)

    SetModelAsNoLongerNeeded(model)
    return obj
end

Fíjate que GetPedBoneIndex convierte el ID del hueso (57005 es la mano derecha) en el índice del hueso que espera el native de attach. Los valores de offset y rotación dependen de dónde esté el origen de tu modelo, así que cuenta con ajustarlos en el juego. Combina el prop con una animación para que la pose se vea natural; Emotes personalizados para FiveM muestra cómo hacer los tuyos. Para convertir el prop en un ítem usable del inventario, mira Ítems personalizados en ox_inventory.

Cantidad de polígonos y presupuesto de texturas

Cada prop con stream les cuesta memoria y tiempo de descarga a los jugadores. Algunas reglas prácticas:

  • Ajusta el detalle al tamaño. Un vaso sobre una mesa no necesita los mismos polígonos que un auto. Si nadie lo va a ver de cerca, simplifícalo.
  • Usa LODs y una distancia de LOD razonable. Un prop chico no necesita renderizarse desde cientos de metros. Distancias de LOD más bajas significan menos objetos dibujados a la vez.
  • Mantén las texturas chicas. 512×512 o 1024×1024 alcanza para la mayoría de los props. Una textura 4K en un objeto chico desperdicia memoria sin ninguna mejora visible.
  • Usa tamaños en potencia de dos y formatos comprimidos (DXT/BC) para que el juego pueda generar mipmaps y hacer stream de forma eficiente.
  • Comparte diccionarios de texturas entre props relacionados en vez de duplicar la misma textura de madera o metal en cada .ytd.
  • Mantén la collision simple. Unas pocas cajas suelen colisionar mejor y más barato que una copia de la malla visual.

FiveM avisa en la consola del cliente cuando un asset es demasiado pesado. Trata esos avisos como bugs que hay que arreglar, no como ruido. Optimizar assets de FiveM profundiza en los presupuestos.

Problemas comunes

El prop es invisible o CreateObject devuelve 0. El archetype no está cargado. Revisa que el .ytyp esté en stream/, que la ruta de data_file 'DLC_ITYP_REQUEST' coincida exactamente con el nombre del archivo y que el resource esté iniciado. Si el objeto existe (chocas con él) pero no lo ves, revisa que el .ytd tenga stream y que el nombre del diccionario de texturas del archetype coincida con él.

El prop atraviesa el suelo o los jugadores pasan a través de él. No tiene collision. Agrega un .ybn (o bounds embebidos) y vuelve a exportar. En props spawneados, FreezeEntityPosition también evita que se hundan o se vuelquen.

HasModelLoaded nunca devuelve true. Casi siempre es un error de tipeo en el hash del modelo. El hash sale del nombre del archetype, no del nombre del resource. joaat('myrp_coffee_cup') y `myrp_coffee_cup` funcionan los dos, pero solo si el nombre coincide exactamente con el .ytyp. Usa IsModelInCdimage para comprobar si el juego conoce el modelo.

El prop aparece y desaparece a distancia. La distancia de LOD en el .ytyp es muy baja, o el bounding box no coincide con el modelo. Vuelve a exportar con los valores correctos.

El prop reemplazó a otro objeto. El nombre de tu modelo choca con uno del juego base o con otro modelo personalizado. Ponle a cada modelo un prefijo con el nombre de tu servidor.

Preguntas frecuentes

¿Los jugadores tienen que descargar algo para ver los props personalizados?

No. Los archivos de la carpeta stream/ de un resource se envían a los jugadores automáticamente cuando entran, igual que los autos y la ropa personalizados.

¿Puedo spawnear props del juego base de GTA V de la misma forma?

Sí. Los props que vienen con el juego, como prop_weed_01, ya tienen archetypes, así que te saltas los archivos y la línea data_file y vas directo a RequestModel y CreateObject.

¿Necesito un archivo de collision .ybn?

No para que el prop aparezca, pero sin collision los jugadores y vehículos lo atraviesan, y los objetos sin freeze se caen a través del piso. Para cualquier cosa con la que los jugadores puedan chocar, inclúyelo.

¿Conviene spawnear los props con scripts o colocarlos en un .ymap?

Usa un .ymap para todo lo que sea parte permanente del mapa. Usa scripts para props que aparecen y desaparecen: objetos en la mano, muebles que se pueden colocar, equipo de trabajo y objetos de eventos.

¿Puedo hacer props sin aprender Blender?

Sí. La herramienta 3D de BLDR genera un modelo a partir de un prompt o una imagen de referencia y exporta un resource listo para stream con el .ydr, el .ytd y el .ytyp ya configurados.

Sigue leyendo