Documentación Técnica para Desarrolladores — ZerØ Target
Versión: 1.0.0 | Autor: ZerØ Network (Core Overextended) | Frameworks: QBCore, ESX Legacy, OX Core, Standalone
Consumo Resmon: 0.00 ms (Reposo) / 0.01 ms (Escaneo Activo) | Motor: Lua 5.4 / Cerulean
1. Arquitectura y Filosofía de Diseño
ZerØ Target ha sido desarrollado para resolver de manera definitiva la fragmentación del ecosistema de FiveM en lo relativo a sistemas de interacción ocular (targeting). Tradicionalmente, los servidores se ven forzados a elegir entre qb-target u ox_target, provocando incompatibilidades cuando se integran recursos de terceros con diferentes dependencias.
El diseño de zero_target se fundamenta en cuatro pilares:
- Unificación Transparente: Atrapa dinámicamente las llamadas a exports de
ox_target,qb-targetyqtargeta nivel de runtime mediante metatablas y manejadores__cfx_export_*. - Preservación de Tipos y Seguridad de Invocación: Normaliza las discrepancias de firma entre APIs (por ejemplo, adaptando los callbacks
action(entity)deqb-targetpara que no reciban tablas de respuesta no deseadas, evitando caídas en nativas de GTA V). - Optimización Adaptativa del Ciclo de Renderizado: El raycast principal de la cámara aplica un retardo dinámico (de 25 ms a 200 ms) cuando la retícula apunta al entorno inerte (asfalto, cielo, muros) y entra en 0 ms exclusivamente al detectar entidades con opciones válidas.
- Independencia del Framework (Puente Modular): El archivo
framework/bridge.luaaísla toda la lógica de permisos, trabajos, bandas e inventarios, permitiendo que el motor funcione idénticamente en QBCore, ESX o Standalone sin código espagueti.
2. Estructura del Proyecto
zero_target/
├── fxmanifest.lua
├── shared/
│ ├── config.lua
│ └── config_locales.lua
├── framework/
│ └── bridge.lua
├── server/
│ ├── main.lua
│ └── version.lua
├── client/
│ ├── main.lua
│ ├── api.lua
│ ├── utils.lua
│ ├── state.lua
│ ├── defaults.lua
│ ├── debug.lua
│ └── compat/
│ ├── qb-target.lua
│ ├── ox_target.lua
│ └── qtarget.lua
├── ui/
│ ├── index.html
│ ├── style.css
│ ├── js/
│ └── sprite/
│ └── pin.png
└── readme/
├── Documentacion_ES.md
├── Documentation_EN.md
├── Instrucciones_ES.md
└── Instructions_EN.md
3. Capa de Abstracción de Frameworks (framework/bridge.lua)
El puente detecta automáticamente el entorno del servidor o utiliza el valor forzado en Config.Framework.
Sincronización en Tiempo Real
- Qbox (
qbx_core):- Detecta automáticamente el framework nativo
qbx_coreo medianteConfig.Framework = "qbox". - Escucha
qbx_core:client:playerLoaded,qbx_core:client:setPlayerData,qbx_core:client:onJobUpdate,qbx_core:client:onGangUpdateyqbx_core:client:onPlayerUnload. - Sincroniza
PlayerData.groups,PlayerData.job,PlayerData.gangyPlayerData.citizenid. - Soporta la API nativa de permisos
exports.qbx_core:HasGroup(filter).
- Detecta automáticamente el framework nativo
- QBCore (
qb-core):- Escucha
QBCore:Player:SetPlayerData,QBCore:Client:OnJobUpdateyQBCore:Client:OnGangUpdate. - Escucha
QBCore:Client:OnPlayerLoadedpara inicializar el estado del personaje tras la selección de multicharacter. - Escucha
QBCore:Client:OnPlayerUnloadpara purgar la caché de trabajos e ítems en memoria al desconectarse o cambiar de personaje.
- Escucha
- ESX Legacy (
es_extended):- Escucha
esx:playerLoadedyesx:onPlayerLogoutpara el ciclo de vida del personaje. - Escucha
esx:setJob,esx:setJob2(bandas/segundo trabajo),esx:setPlayerData,esx:addInventoryItemyesx:removeInventoryItem.
- Escucha
- Inventarios Soportados:
ox_inventory: Búsquedas reactivas directas medianteexports.ox_inventory:Search('count', item)y sincronización por eventoox_inventory:itemCount.qb-inventory: Sincronización instantánea mediante el eventoQBCore:Client:OnPlayerUpdated(clave'items') y fallback directo mediante el exportexports['qb-inventory']:HasItem(items, amount).- Inventarios por Defecto: Extracción protegida de conteos sobre
PlayerData.itemsoPlayerData.inventoryen una caché interna indexada.
Métodos del Puente
-- Verifica si el jugador posee un grupo o trabajo con el grado requerido
Bridge.HasGroup(filter)
-- Verifica si el jugador posee los ítems requeridos (admite modo 'anyItem' o todos)
Bridge.HasItem(filter, hasAny)
4. Motor de Escaneo y Optimización de Resmon
El hilo principal de escaneo se aloja en client/main.lua y opera con la siguiente lógica:
[Inicio de Ciclo]
│
▼
¿Modo Activo? (Continuo = true ó Tecla presionada = true)
├── NO ──► Sleep = 200 ms (Resmon 0.00 ms)
│
└── SÍ
│
▼
Raycast desde Cámara (Flag 511)
│
▼
¿Impacto dentro de DrawDistance (7.0m)?
├── NO ──► Sleep = 100 ms a 150 ms
│
└── SÍ
│
▼
Evaluar opciones de entidad y zonas cercanas
│
▼
¿Existen opciones visibles tras filtrar permisos/distancias?
├── SÍ ──► Sleep = 0 ms (Renderizado inmediato a 60 FPS)
└── NO ──► Sleep = 60 ms (Sin opciones: CPU descansa)
Gracias a este esquema de espera adaptativa, el consumo medido en resmon es de:
- 0.00 ms en reposo (conducir, caminar o modo tecla inactivo).
- 0.01 ms en modo continuo apuntando al suelo o paredes vacías.
- 0.03 ms - 0.05 ms únicamente durante la fracción de segundo en que se interactúa activamente con el menú desplegado.
5. Capa de Compatibilidad Universal (client/compat/)
5.1. qb-target.lua
Transforma la estructura de opciones de qb-target al formato estándar de zero_target:
- Resolución de la Incompatibilidad de
action: Enqb-target, la firma del callback de acción es tradicionalmenteaction(entity). En motores derivados de ox, se envía un objeto compuestoresponse = { entity = ..., coords = ... }.
Para evitar que scripts antiguos pasen una tabla a nativas comoDeleteEntity(entity)oNetworkGetNetworkIdFromEntity(entity),zero_targetenvuelve la función:local action = v.action if action then v.onSelect = function(data) return action(data and data.entity or data, data) end end - Normalización de Grupos y Bandas:
Traduce campos heterogéneos como
v.job,v.gangyv.citizenid(admitiendo tanto cadenas de texto como arrays o tablas indexadas por grados) en una tabla única compatible conBridge.HasGroup. - Aliases Plurales:
Registra variantes singulares y plurales de todas las funciones comunes:
AddTargetBone/AddTargetBonesAddTargetEntity/AddTargetEntities/RemoveTargetEntity/RemoveTargetEntitiesAddTargetModel/AddTargetModels/RemoveTargetModel/RemoveTargetModelsRemoveBoxZone/RemovePolyZone/RemoveCircleZone->RemoveZone
- Manejadores de Red:
Captura eventos legacy del tipo
AddEventHandler('qb-target:client:AddBoxZone', ...).
5.2. qtarget.lua
Proporciona la interfaz simplificada de qtarget:
exports.qtarget:Ped(options)exports.qtarget:Vehicle(options)exports.qtarget:Object(options)exports.qtarget:Player(options)- Y sus correspondientes métodos de retirada
RemovePed,RemoveVehicle, etc.
6. Referencia de la API Central (client/api.lua)
Cualquier recurso moderno puede interactuar directamente con zero_target (o mediante ox_target):
6.1. Creación de Zonas
-- Box Zone (Zona Cúbica)
local zoneId = exports.zero_target:addBoxZone({
coords = vec3(x, y, z),
size = vec3(2.0, 2.0, 2.0),
rotation = 45.0,
debug = false,
options = {
{
name = 'mi_opcion',
icon = 'fas fa-box',
label = 'Abrir Caja',
groups = 'police',
onSelect = function(data)
print("Caja abierta en", data.coords)
end
}
}
})
-- Poly Zone (Zona Poligonal)
local zoneId = exports.zero_target:addPolyZone({
points = { vec3(x1, y1, z), vec3(x2, y2, z), vec3(x3, y3, z) },
thickness = 3.0,
options = { ... }
})
-- Sphere Zone (Zona Esférica)
local zoneId = exports.zero_target:addSphereZone({
coords = vec3(x, y, z),
radius = 2.5,
options = { ... }
})
-- Eliminar cualquier zona por ID o nombre
exports.zero_target:removeZone(zoneId)
6.2. Modelos, Entidades y Globales
-- Añadir opciones a uno o varios modelos (hash o nombre)
exports.zero_target:addModel({'prop_atm_01', 'prop_atm_02'}, {
{
name = 'cajero_usar',
icon = 'fas fa-credit-card',
label = 'Utilizar Cajero',
distance = 1.5,
onSelect = function(data)
-- Lógica del cajero
end
}
})
-- Opciones Globales por Tipo
exports.zero_target:addGlobalPed(options)
exports.zero_target:addGlobalVehicle(options)
exports.zero_target:addGlobalObject(options)
exports.zero_target:addGlobalPlayer(options)
-- Retirada selectiva por label/name o total
exports.zero_target:removeGlobalVehicle({'nombre_opcion'})
exports.zero_target:removeModel('prop_atm_01', {'cajero_usar'})
7. Módulo Servidor y Control de Versiones
server/main.lua
- Mantiene sincronizado el estado de entidades con target (
ox_target:setEntityHasOptions). - Dispone de un hilo de recolección de basura cada 10 segundos para desregistrar entidades que hayan sido eliminadas de la memoria del servidor (
ox_target:removeEntity). - Sincroniza la apertura y cierre de compuertas/puertas de vehículos entre el cliente solicitante y el dueño de la entidad en red (
ox_target:toggleEntityDoor).
server/version.lua
- Cumple estrictamente con los estándares corporativos de ZerØ Network:
- Comprueba el manifiesto remoto en GitHub en segundo plano sin interrumpir el arranque del servidor.
- Valida el esquema semántico del JSON (
schema == 1). - Muestra un banner informativo limpio con el framework detectado, versión instalada y resmon objetivo (0.00 ms).
- Gestiona automáticamente la limpieza de temporizadores al detener el recurso (
onResourceStop).
8. Modos de Interacción y Selección (Config.InteractionType)
El recurso soporta tres modalidades de confirmación de opciones administradas centralmente por el servidor en shared/config.lua:
| Modo | Clave | Icono en Pantalla | Mecánica de Confirmación |
|---|---|---|---|
| Mantener (E) | 'hold' |
Letra E estática con onda radar |
El usuario mantiene presionada la tecla E durante 800ms mientras el borde radial se completa al 100%. |
| Al Tacto (E) | 'press' |
Letra E estática con onda radar |
Una sola pulsación rápida de la tecla E ejecuta la acción inmediatamente sin tiempo de espera. |
| Clic (Ratón) | 'click' |
Mano con dedo índice (fa-hand-pointer) |
Se muestra la mano con su onda radar y la acción se confirma al presionar el Clic Izquierdo del ratón (o tecla E). |
[!IMPORTANT] El modo de interacción es definido exclusivamente por los programadores en el servidor (
Config.InteractionType). En la interfaz de usuario (/targetmenu), los jugadores tienen restringida la personalización únicamente a su estilo visual personal: Color de Acento, Tipografía y Forma del Ojo, las cuales se persisten en KVP local (zero_target_shape,zero_target_color,zero_target_font).