FiveM Müzik ve Radyo Çalar Scriptleri: xSound ve Daha Fazlası
Oyun içinde müziği doğru şekilde çalın. Partiler, barlar ve arabalar için xSound, radyo çalar uygulamaları, boombox prop'ları ve en iyi FiveM ses script'leri.
Agency Scripts
Agency Scripts Kurucusu ve Baş Geliştiricisi
Roleplay'de Özel Telsiz Neden Önemlidir?
Müzik ve radyo, bir FiveM rol yapma sunucusuna hayat veren vazgeçilmez atmosferik unsurlardır. GTA V kendi radyo istasyonlarıyla gelse de, özel radyo sistemleri sunucu sahiplerinin topluluk kimliklerine uygun temalı istasyonlar oluşturmasına, canlı DJ setleri yayınlamasına, topluluk tarafından seçilen çalma listelerini çalmasına ve hatta karakter içi haber bültenleri yayınlamasına olanak tanır. İyi yapılandırılmış bir müzik sistemi, basit bir ses çalmanın çok ötesine geçer. Aynı araçtaki oyuncular için senkronize dinleme deneyimleri, müzik kutularından ve kulüp hoparlörlerinden konumsal ses, oyuncuların bir telefon uygulaması üzerinden yönetebileceği kişisel çalma listeleri ve gece kulübü rolü için DJ kabini entegrasyonu sunar. Teknik altyapı, FiveM istemcisi içinde tarayıcı tabanlı ses API'lerinin tüm gücünden yararlanmanızı sağlayan NUI ses yeteneklerine dayanır.
Ses Mimarisi ve NUI Entegrasyonu
FiveM'in NUI katmanı, oyun istemcisine gömülü Chromium tabanlı bir tarayıcı çalıştırır; bu da Web Audio API, HTML5 ses ögeleri ve hatta uyarlanabilir akış için MediaSource API'ye erişiminiz olduğu anlamına gelir. Mimari üç bileşene ayrılır: Lua client scripti araçlara binme veya hoparlörlere yaklaşma gibi oyun dünyası etkileşimlerini yönetir, NUI HTML ve JavaScript katmanı asıl ses oynatmayı ve görselleştirmeyi yönetir, sunucu ise birden fazla istemci arasındaki senkronize oynatma durumlarını koordine eder. Bir oyuncu bir araca bindiğinde, client scripti mevcut istasyonu çalmaya başlamak için bir NUI mesajı gönderir. NUI katmanı bir ses ögesi oluşturur, kaynak URL'yi ayarlar ve oynatmayı başlatır. Ses düzeyi denetimleri, sorunsuz ses geçişleri için Web Audio API'nin GainNode'u kullanılarak tamamen NUI katmanında işlenir:
-- Client-side: Vehicle radio controller
local currentStation = nil
local radioActive = false
CreateThread(function()
while true do
Wait(500)
local ped = PlayerPedId()
if IsPedInAnyVehicle(ped, false) then
local vehicle = GetVehiclePedIsIn(ped, false)
if not radioActive then
radioActive = true
-- Disable default GTA radio
SetVehicleRadioEnabled(vehicle, false)
-- Load saved station preference
local savedStation = LocalPlayer.state.radioStation or 'station_1'
SetStation(savedStation)
end
elseif radioActive then
radioActive = false
SendNUIMessage({action = 'stopRadio'})
currentStation = nil
end
end
end)
function SetStation(stationId)
local station = Config.Stations[stationId]
if not station then return end
currentStation = stationId
SendNUIMessage({
action = 'playStation',
url = station.url,
name = station.name,
volume = LocalPlayer.state.radioVolume or 0.5,
})
end
NUI Ses Çalar Kurulumu
NUI tarafı akış bağlantılarını, arabelleğe almayı, hata kurtarmayı ve ses seviyesi yönetimini gerçekleştiren güçlü bir ses oynatıcıya ihtiyaç duyar. Basit HTML5 ses öğeleri yerine Web Audio API kullanın; çünkü bu API ses yönlendirmesi üzerinde kontrol sağlar, frekans verilerinden görselleştirmeler oluşturmanıza olanak tanır ve uzamsal ses işlemeyi destekler. Ses kontrolü için bir GainNode ve görselleştirme verileri için bir AnalyserNode içeren bir AudioContext oluşturun:
// NUI JavaScript: Audio engine
class RadioPlayer {
constructor() {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.gainNode = this.audioContext.createGain();
this.analyser = this.audioContext.createAnalyser();
this.analyser.fftSize = 256;
this.gainNode.connect(this.analyser);
this.analyser.connect(this.audioContext.destination);
this.audio = new Audio();
this.audio.crossOrigin = 'anonymous';
this.source = null;
this.isPlaying = false;
}
play(url, volume) {
this.stop();
this.audio = new Audio(url);
this.audio.crossOrigin = 'anonymous';
this.audio.volume = 1.0;
this.source = this.audioContext.createMediaElementSource(this.audio);
this.source.connect(this.gainNode);
this.gainNode.gain.value = volume;
this.audio.play().then(() => {
this.isPlaying = true;
}).catch(err => {
console.error('Radio playback failed:', err);
setTimeout(() => this.play(url, volume), 3000);
});
}
stop() {
if (this.audio) {
this.audio.pause();
this.audio.src = '';
this.isPlaying = false;
}
}
setVolume(vol) {
this.gainNode.gain.linearRampToValueAtTime(
vol, this.audioContext.currentTime + 0.1
);
}
getFrequencyData() {
const data = new Uint8Array(this.analyser.frequencyBinCount);
this.analyser.getByteFrequencyData(data);
return data;
}
}
const radio = new RadioPlayer();
İstasyon Yapılandırması ve Streaming
Radyo istasyonlarınızı yayın URL'leri, meta veriler ve tür kategorileriyle tanımlayın. Çoğu özel FiveM radyo sistemi, geniş çapta desteklendikleri ve kurulumları kolay olduğu için MP3 veya AAC formatındaki internet radyo yayınlarını kullanır. Tam kontrol için kendi Icecast veya Shoutcast sunucunuzu barındırabilir ya da herkese açık radyo yayını URL'lerini kullanabilirsiniz. Her istasyon için yayın URL'sini, bir görünen adı, bir tür etiketini ve isteğe bağlı olarak UI için bir logo görselini kaydedin. Proxy servisleri aracılığıyla YouTube ve SoundCloud URL'leri için destek eklemeyi değerlendirin, ancak hizmet şartlarına ve telif hakkı kısıtlamalarına dikkat edin. Canlı DJ işlevselliği için RTMP'den HTTP'ye yayın dönüştürme sağlayan hizmetlerle entegrasyon kurun; böylece DJ'ler OBS veya benzeri yazılımları kullanarak yayın yapabilir:
Config.Stations = {
['station_1'] = {
name = 'Agency Radio',
genre = 'Hip Hop',
url = 'https://stream.example.com/hiphop',
logo = 'station_hiphop.webp',
description = 'The freshest beats in Los Santos',
},
['station_2'] = {
name = 'LS Rock Radio',
genre = 'Rock',
url = 'https://stream.example.com/rock',
logo = 'station_rock.webp',
description = 'Classic and modern rock anthems',
},
['station_3'] = {
name = 'Vinewood Lounge',
genre = 'Jazz / Lofi',
url = 'https://stream.example.com/lofi',
logo = 'station_lofi.webp',
description = 'Smooth vibes for the night drive',
},
['station_live'] = {
name = 'Live DJ',
genre = 'Live',
url = 'https://stream.example.com/live',
logo = 'station_live.webp',
description = 'Live DJ sets from the community',
isLive = true,
},
}
Senkronize Araç Radyosu
Birden fazla oyuncu aynı araçta seyahat ettiğinde, hepsi aynı radyo istasyonunu duymalıdır. Bu, state bag'ler veya ağ etkinlikleri aracılığıyla sunucu tarafı koordinasyon gerektirir. Sürücü istasyonu değiştirdiğinde, sunucu yeni istasyonu tüm yolculara yayınlar. Manuel etkinlik yönetimi olmadan ağ replikasyonunu otomatik olarak işlediği için verimli senkronizasyon adına FiveM'in state bag sistemini kullanın. İstasyonu araç entity'sinin state bag'ine tanımlayın, böylece araca binen her oyuncu mevcut istasyonu otomatik olarak alır. Zaten bir istasyon çalan araca binen yolcular, yolcular içerideyken sürücünün ayrılması ve sürücü dışındakilerin kontrolüne izin veriyorsanız yolculardan gelen çakışan istasyon değişiklikleri gibi uç durumları yönetin:
-- Server-side: Sync radio state via state bags
RegisterNetEvent('radio:server:setStation', function(vehicleNet, stationId)
local src = source
local vehicle = NetworkGetEntityFromNetworkId(vehicleNet)
if not DoesEntityExist(vehicle) then return end
-- Verify player is the driver
local ped = GetPlayerPed(src)
if GetPedInVehicleSeat(vehicle, -1) ~= ped then return end
-- Set station on vehicle state bag
Entity(vehicle).state:set('radioStation', stationId, true)
end)
-- Client-side: Listen for state bag changes
AddStateBagChangeHandler('radioStation', nil, function(bagName, key, value)
if not value then return end
local entity = GetEntityFromStateBagName(bagName)
if not DoesEntityExist(entity) then return end
local ped = PlayerPedId()
if not IsPedInVehicle(ped, entity, false) then return end
SetStation(value)
end)
Mekansal Ses ve Boombox Sistemleri
Mekansal ses, düz ses çalmanın yakalayamayacağı bir derinlik katar. Boombox'lar, kulüp hoparlörleri ve araç teypleri, mesafeye bağlı olarak azalan ve dinleyicinin kaynağa olan konumuna göre yönlenen bir ses yaymalıdır. FiveM, şu gibi yerel ses fonksiyonları sunar: PlaySoundFromCoord basit konumsal sesler için, ancak ses akışı (streaming audio) için NUI katmanında mesafeye dayalı ses düzeyi ölçeklendirmesi uygulamanız gerekir. Her karede oyuncu ile ses kaynağı arasındaki mesafeyi hesaplayın, ardından bu mesafeyi bir ses düzeyi eğrisiyle eşleştirin. Yapılandırılabilir minimum ve maksimum duyma mesafeleriyle, gerçekçi ses zayıflaması için ters kare düşüşü (inverse-square falloff) kullanın. Oyuncuların dünyaya yerleştirebileceği boombox'lar için, oyuncunun konumunda bir prop oluşturan ve bunu ses kaynağı olarak kaydeden yerleştirilebilir bir eşya oluşturun. Menzildeki diğer oyuncular, boombox prop'una olan mesafelerine göre ölçeklenen ses düzeyiyle müziği otomatik olarak duymalıdır.
Oyuncu Çalma Listesi ve Telefon Entegrasyonu
Sunucunuzun telefon resource dosyası ile entegre bir çalma listesi sistemi aracılığıyla oyunculara müzik deneyimleri üzerinde kişisel kontrol sağlayın. Oyuncular tek tek parçalara URL ekleyerek özel çalma listeleri oluşturabilmeli, sürükle ve bırak ile şarkıları yeniden sıralayabilmeli, bir çalma listesini karışık veya tekrar moduna ayarlayabilmeli ve çalma listelerini diğer oyuncularla paylaşabilmelidir. Çalma listelerini oturumlar arasında korunması için oyuncunun identifier değerine bağlı olarak veritabanında saklayın. Telefon uygulaması arayüzü, sanatçı ve başlık meta verileriyle o an çalan parçayı, oynat, duraklat, atla ve önceki için oynatma kontrollerini, ses kaydırıcısını ve kayıtlı çalma listelerinin bir listesini göstermelidir. Oyuncu bir araçtayken, telefon oynatıcısı yolcuların müziği duyabilmesi için sesi otomatik olarak aracın radyo sistemi üzerinden yönlendirmelidir. Yürüyerek gezerken eşya olarak kulaklık takıldığında, müzik diğer oyuncuların duyamayacağı şekilde özel olarak çalar ve karakterin müzik dinlediğini diğer oyunculara gösteren küçük bir kulaklık simgesi görünür.
Görselleştirici ve Arayüz Tasarımı
Bir müzik çalar UI'ı, çalınan sese karşı canlı ve duyarlı hissettirmelidir. Gerçek zamanlı frekans verilerini ayıklamak ve bir ses görselleştiricisi oluşturmak için Web Audio API'deki AnalyserNode'u kullanın. UI estetiğinize bağlı olarak çubuk görselleştiriciler, dalga formu gösterimleri ve dairesel spektrum analizörlerinin tümü iyi sonuç verir. Performans için görselleştiriciyi bir canvas öğesi kullanarak işleyin ve görselleştirmenin karmaşıklığına bağlı olarak saniyede 30 veya 60 kare hızında güncelleyin. Radyo UI'ının kendisi minimal ve rahatsız etmeyen yapıda olmalı, ekranın köşesinde geçerli istasyon adını, yayın meta verilerinde mevcutsa parça adını ve temel oynatma kontrollerini gösteren küçük bir widget olarak görünmelidir. Oyuncu istasyonları değiştirmek için tam radyo menüsünü açtığında, mevcut istasyonların logolarını, türlerini ve dinleyici sayılarını içeren bir ızgara veya liste görüntüleyin. Çok sayıda istasyona sahip sunucular için bir arama çubuğu ve oyuncuların tüm listeyi kaydırmadan tercih ettikleri istasyonlara hızlıca erişebilmeleri için bir favoriler sistemi ekleyin.
Performans Hususları
Ses yayını bant genişliği ve client kaynaklarını tüketir, bu nedenle uygulamanızı dikkatlice optimize edin. Bellek sızıntılarını ve CPU yükselmelerini önlemek için client başına eşzamanlı ses yayını sayısını sınırlayın. Bir oyuncu araçta değilken ve yakınında boombox yokken, ses context'ini yalnızca duraklatmak yerine tamamen yok edin. Birden fazla boombox'tan gelen uzamsal ses için yalnızca duyma mesafesindeki kaynaklar için ses akışları oluşturun ve kaynaklar menzil dışına çıktıkça akışları temizleyin. Ortam arka plan müziği için düşük bit hızına sahip akışlar kullanın ve daha yüksek kaliteli akışları birincil dinleme deneyimine ayırın. Sunucu tarafında, akış URL'lerini doğrudan event'ler içinde göndermekten kaçının çünkü bunlar yakalanabilir ve kötüye kullanılabilir. Bunun yerine, client'ın belirli bir istasyon ID'si için akış URL'sini istediği ve sunucunun süre sınırlı imzalı bir URL ile yanıt verdiği bir callback sistemi kullanın. Client tarafından bildirilen oynatma hatalarını izleyin ve ağ sorunları nedeniyle kesilen akışları, zorlanan bir akış sunucusunu aşırı yüklememek için exponential backoff ile otomatik olarak yeniden bağlayın.