Explorer
KNOW-PAT-097

FiveM - Media Streaming NUI + Routing Buckets : TVs instanciees, playback local/externe

Domaine
fivem
Type
pattern
Priorité
P3

Parent : [[INDEX-FIVEM-GAMEPLAY]]

FiveM - Media Streaming NUI + Routing Buckets : TVs instanciées, playback local/externe

Problème

Les TVs dans FiveM doivent synchroniser la vidéo entre joueurs proches, mais pas avec tout le monde sur le serveur. De plus, des appartements ou intérieurs nécessitent des instances séparées.

Solution

Système TV instancié par routing buckets, NUI media player avec sources locales (.mp3/.mp4) et externes (optionnel avec avertissement), target system, vehicle TV offsets.

-- Config
Config.EnableRoutingBucketTv = true -- Instanced TVs (apartments/interiors)
Config.EnableExternalSources = false -- Optional external media (use responsibly)
Config.EnableMediaFromFolder = true -- Local media from html/media folder
Config.VehicleTelevision = true -- TVs inside vehicles
Config.Target = true
Config.Targettype = "oxtarget" -- qtarget, qbtarget, oxtarget

-- Routing bucket TV logic (server-side)
local tvStates = {} -- [routingBucket] = { url, currentTime, playing }

RegisterNetEvent('rtx_tv:sync')
AddEventHandler('rtx_tv:sync', function(tvId, state)
    local src = source
    local bucket = GetPlayerRoutingBucket(src)
    
    tvStates[bucket] = tvStates[bucket] or {}
    tvStates[bucket][tvId] = {
        url = state.url,
        currentTime = state.currentTime,
        playing = state.playing,
        timestamp = os.time()
    }
    
    -- Broadcast uniquement aux joueurs du même bucket
    for _, playerId in ipairs(GetPlayers()) do
        if GetPlayerRoutingBucket(playerId) == bucket then
            TriggerClientEvent('rtx_tv:update', playerId, tvId, state)
        end
    end
end)

-- Client sync on bucket change
AddEventHandler('playerRoutingBucket', function(src, oldBucket, newBucket)
    if tvStates[newBucket] then
        for tvId, state in pairs(tvStates[newBucket]) do
            TriggerClientEvent('rtx_tv:update', src, tvId, state)
        end
    end
end)

Pourquoi

  • Routing buckets isolent les instances (appartements, intérieurs) sans conflit
  • Sources locales évitent les problèmes de copyright et de latence
  • Target system pour l'interaction (ox_target, qtarget)

Quand l'utiliser

  • Systèmes de TV dans les appartements, bars, cinémas
  • Playback synchronisé de musique/vidéo

Quand NE PAS l'utiliser

  • Streaming public de contenu copyrighté (risque légal)
  • Si les joueurs n'ont pas besoin d'instance séparée

Exemples

Correct

-- Local media avec fallback
local mediaUrl = 'nui://' .. GetCurrentResourceName() .. '/html/media/' .. filename
if Config.EnableExternalSources and isTrustedUrl(url) then
    mediaUrl = url
end
SendNUIMessage({
    action = 'play',
    url = mediaUrl,
    volume = 0.5
})

Incorrect

-- Broadcast global sans bucket → tout le monde voit la même TV
RegisterNetEvent('tv:play')
AddEventHandler('tv:play', function(url)
    TriggerClientEvent('tv:show', -1, url) -- Tous les joueurs, tous les buckets
end)

Références

  • rtx_tv/config.lua L69-79
  • CFX Docs : Routing Buckets