FiveM sunucu geliştirmede istemci (client) ile sunucu (server) arasındaki veri iletişimi, script mimarinizin kalbini oluşturur. Yıllarca kullanılan eski usul ESX.TriggerServerCallback veya QBCore.Functions.TriggerCallback yapıları, iç içe geçmiş fonksiyon blokları (callback hell) oluşturmakla kalmaz; ağ gecikmelerinde istemci tarafını kilitleyebilir veya yanıt beklerken bellek şişmesine yol açabilir.
2026 yılı FiveM standartlarında ise asenkron Promise mimarisi ve modern callback kütüphaneleri (özellikle ox_lib callback entegrasyonu) devreye giriyor. Bu rehberde, sunucu ve istemci arasındaki veri transferini nasıl temiz, hataya dayanıklı ve ultra hızlı bir hale getireceğinizi adım adım inceliyoruz.
1. Neden Eski Callback Yapılarını Bırakmalısınız?
Geleneksel callback sistemlerinde en büyük problem, kodun okunabilirliğini ve hata yönetimini zorlaştırmasıdır:
- Callback Hell: Bir veriyi alıp ardından başka bir sorgu yapmak istediğinizde 3-4 katmanlı iç içe fonksiyonlar oluşur.
- Zaman Aşımı (Timeout) Eksikliği: Sunucu çökerse veya yanıt gecikirse istemci sonsuza kadar yanıt bekleyebilir ve NUI/arayüz donabilir.
- Thread Bloklama: Eski
Citizen.Waitdöngüleriyle veri beklemek istemci resmon değerlerini gereksiz yere artırır.
Modern Promise / Await yaklaşımı sayesinde kodlarınızı senkron gibi okunaklı yazar, arka planda ise tamamen asenkron ve non-blocking (iş parçacığını tıkamayan) bir performans elde edersiniz.
2. Modern Asenkron Callback Mimarisi: Adım Adım Kurulum
Modern mimaride en yaygın ve stabil yöntem lib.callback kütüphanesidir. Hem istemciden sunucuya hem de sunucudan istemciye çift yönlü veri akışını destekler.
Adım 1: fxmanifest.lua Yapılandırması
Öncelikle scriptinizin manifest dosyasına modern kütüphane desteğini dahil edin:
fx_version 'cerulean'
game 'gta5'
lua54 'yes' -- 2026 standartlarında Lua 5.4 zorunludur
shared_scripts {
'@ox_lib/init.lua'
}
client_scripts {
'client/main.lua'
}
server_scripts {
'server/main.lua'
}lua54 'yes' direktifi, modern çöp toplayıcı (GC) optimizasyonlarını ve gelişmiş coroutine/promise desteğini aktif eder. Eski scriptlerinizi de bu standarda yükseltmeyi unutmayın.Adım 2: Sunucu Tarafında Callback Tanımlama (server/main.lua)
Sunucuda oyuncunun banka bakiyesini ve rütbesini kontrol eden güvenli bir callback tanımlayalım:
-- Sunucu tarafı veri sağlayıcı callback
lib.callback.register('dexta:server:getUserData', function(source, accountType)
local src = source
-- Güvenlik doğrulaması
if not accountType or (accountType ~= 'bank' and accountType ~= 'cash') then
return { success = false, message = 'Geçersiz hesap tipi!' }
end
-- Örnek veri çekme işlemi (oxmysql veya framework entegrasyonu)
-- Bu işlem asenkron çalışır ve sunucu ana döngüsünü kilitlemez
local balance = exports.oxmysql:scalarSync('SELECT money FROM users WHERE identifier = ?', { GetPlayerIdentifierByType(src, 'license') }) or 0
return {
success = true,
balance = balance,
timestamp = os.time()
}
end)Adım 3: İstemci Tarafında 'Await' ile Çağırma (client/main.lua)
İç içe fonksiyonlar yerine, await kullanarak sanki yerel bir değişken okur gibi temiz bir çağrı yapabilirsiniz:
RegisterCommand('bakiyebak', function()
-- Callback çağrılırken UI donmaz, thread bloke olmaz
local response = lib.callback.await('dexta:server:getUserData', false, 'bank')
if response and response.success then
lib.notify({
title = 'Banka Bilgisi',
description = ('Mevcut Bakiyeniz: $%s'):format(response.balance),
type = 'success'
})
else
lib.notify({
title = 'Hata',
description = response and response.message or 'Sunucuya ulaşılamadı.',
type = 'error'
})
end
end, false)lib.callback.await fonksiyonunun ikinci parametresi delay (varsayılan timeout) süresidir. false girildiğinde varsayılan koruma süresi kullanılır. Sunucudan asla cevap gelmeme riskine karşı sonsuz döngü engellenmiş olur.3. Doğrudan Lua Promise Mimarisi ile Kendi Callback Sisteminizi Yazma
Eğer harici bir kütüphaneye bağımlı kalmadan kendi özel mekanizmanızı kurmak istiyorsanız, FiveM'in yerleşik promise nesnesini kullanabilirsiniz:
-- Client Tarafında Yerel Promise Kullanımı
function FetchServerData(endpoint, data)
local p = promise.new()
local ticket = math.random(10000, 99999)
-- Yanıtı dinleyecek geçici tek seferlik event
local handler
handler = AddEventHandler(('customCallback:%s:%s'):format(endpoint, ticket), function(result)
RemoveEventHandler(handler)
p:resolve(result)
end)
-- Sunucuya isteği gönder
TriggerServerEvent('customCallback:request', endpoint, ticket, data)
-- Zaman aşımı koruması (5 saniye)
SetTimeout(5000, function()
if p.state == 0 then -- 0: pending
RemoveEventHandler(handler)
p:resolve({ success = false, message = 'Zaman aşımı (Timeout)' })
end
end)
return Citizen.Await(p)
endBu yapı, framework bağımsız çalışan özel sistemler (örneğin özel galeri, garaj veya admin panelleri) tasarlarken tam kontrol sağlar.
4. Güvenlik ve Hız İçin Kritik İpuçları
- 1İstemci Verisine Asla Güvenmeyin: Callback ile istemciden gelen parametreleri (
accountType,itemId,targetId) mutlaka sunucudatype()venilkontrolünden geçirin. - 2Rate-Limiting Uygulayın: Kötü niyetli kullanıcılar callback tetikleyen komutları veya NUI butonlarını makro ile saniyede yüzlerce kez tetikleyebilir. Sunucu tarafında son istek zamanını kontrol eden bir tablo tutun.
- 3Büyük Veri Paketlerinden Kaçının: Callback üzerinden tek seferde 5.000 satırlık envanter geçmişi göndermek yerine, sayfalanmış (pagination) veri transferi yapın.
Eğer sunucunuzdaki eski altyapıyı modernize etmek, sıfırdan optimize sistemler kurdurmak veya performans sorunlarını kökten çözmek isterseniz profesyonel Developerlik Hizmeti çözümlerimizden yararlanabilir ya da baştan sona modern mimariyle kodlanmış DxAV1 - Roleplay Paketi sistemimize göz atabilirsiniz.
Sıkça Sorulan Sorular (SSS)
lib.callback.await ile klasik TriggerServerCallback arasındaki performans farkı nedir?
Klasik callback sistemleri her istek için bellek üzerinde kalıcı tablolar ve listener'lar bırakabilir. Modern await mimarisi ise Lua coroutine havuzunu kullanır, gereksiz bellek harcamaz ve yanıt geldiği anda belleği temizler (zero memory leak).
Sunucu tarafından istemciye doğru callback yapılabilir mi?
Evet! Modern callback kütüphanelerinde lib.callback.await(source, 'eventName') şeklinde sunucudan belirli bir oyuncunun istemcisine sorgu atıp veri (örneğin oyuncunun anlık koordinatı veya NUI durumu) çekebilirsiniz.
Eski bir ESX veya QBCore scriptini bu mimariye dönüştürmek zor mu?
Hayır. Yalnızca server.lua dosyasındaki event dinleyiciyi lib.callback.register yapısına, client.lua içindeki tetikleyiciyi ise lib.callback.await yapısına çevirmeniz yeterlidir.
