FiveM Bildirim Sistemi: Toast Bildirimleri, Uyarılar ve ox_lib
Gelişmiş bir FiveM bildirim sistemi oluşturun. Toast bildirimleri, ilerleme çubukları, radial menüler ve ox_lib ile önde gelen scriptlerin istemci arayüz geri bildirimlerini nasıl işlediği.
Agency Scripts
Agency Scripts Kurucusu ve Baş Geliştiricisi
Neden Özel Bir Bildirim Sistemi Geliştirilmeli?
Varsayılan FiveM bildirimleri işlevseldir ancak görsel şıklıktan ve esneklikten yoksundur. Çoğu rol yapma sunucusu, birbirinin aynısı görünen genel metin açılır pencerelerine dayanır; bu da oyuncuların bir hatayı, bir başarı onayını veya bir bilgilendirme uyarısını ayırt etmesini zorlaştırır. NUI ile oluşturulan özel bir bildirim sistemi; stil, animasyonlar, konumlandırma, ses efektleri ve kuyruk davranışı üzerinde tam kontrol sahibi olmanızı sağlar. Temel bir UI öğesini, sunucunuzun marka kimliğiyle eşleşen ve oyuncu deneyimini önemli ölçüde geliştiren bir yapıya dönüştürür. Bu eğitimde, sunucu ve istemci tarafında Lua kullanarak, NUI arayüzünü ise HTML, CSS ve JavaScript ile güçlendirerek sıfırdan eksiksiz bir toast bildirim sistemi geliştireceğiz.
NUI Katmanını Kurma
FiveM'deki herhangi bir özel bildirim sisteminin temeli NUI (New UI) katmanıdır. NUI, HTML içeriğini oyunun üzerinde bir katman olarak işlemenize olanak tanır, bu da modern web teknolojilerinin tüm gücünün elinizin altında olduğu anlamına gelir. Kaynak yapınızı şununla oluşturarak başlayın: fxmanifest.lua, client taraflı bir Lua scripti ve bir html klasörü UI dosyalarınızı içerir. Lua scriptlerinizin frontend ile iletişim kurabilmesi için manifest dosyasının NUI sayfanızı tanımlaması ve mesaj işleyicilerini kaydetmesi gerekir.
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
ui_page 'html/index.html'
files {
'html/index.html',
'html/style.css',
'html/script.js',
'html/sounds/*.ogg'
}
client_script 'client.lua'
server_script 'server.lua'
Sizin html/index.html dosyası minimal olmalıdır. Yalnızca bildirimlerin JavaScript tarafından dinamik olarak enjekte edileceği bir kapsayıcı div'e ihtiyaç duyar. HTML'i yalın tutun, çünkü her bildirim öğesi programatik olarak oluşturulur ve yok edilir. Stil sayfanızı ve script'inizi bağlayın ve bildirimlerinizin arkasında oyun dünyasının görünür kalması için body öğesinin şeffaf bir arka plana sahip olduğundan emin olun.
<!-- html/index.html -->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="notification-container"></div>
<script src="script.js"></script>
</body>
</html>
Toast Bildirimi CSS Tasarımı
Toast bildirimleri türlerine göre görsel olarak ayırt edilebilir olmalıdır. Şunlar için ayrı renk şemaları tanımlayın: başarılı, hata, bilgi, ve uyarı bildirimler. Kapsayıcıyı sabit konumlandırma kullanarak ekranın sağ üst köşesine yerleştirin ve bildirimleri aralarında küçük bir boşluk olacak şekilde dikey olarak üst üste dizin. Her toast bildirimi arka plan bulanıklığına sahip zarif bir cam benzeri efektine, türünü belirten renkli bir sol kenarlığa ve akıcı giriş ile çıkış animasyonlarına sahip olmalıdır. Sağdan kayma ve bildirimin süresi dolduğunda kaybolma için CSS keyframes kullanın.
/* html/style.css */
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: transparent; font-family: 'Segoe UI', sans-serif; overflow: hidden; }
#notification-container {
position: fixed;
top: 20px;
right: 20px;
display: flex;
flex-direction: column;
gap: 10px;
z-index: 9999;
max-width: 380px;
width: 100%;
}
.toast {
background: rgba(15, 15, 25, 0.85);
backdrop-filter: blur(12px);
border-radius: 10px;
padding: 14px 18px;
border-left: 4px solid #3b82f6;
color: #e2e8f0;
animation: slideIn 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
display: flex;
align-items: flex-start;
gap: 12px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
.toast.success { border-left-color: #22c55e; }
.toast.error { border-left-color: #ef4444; }
.toast.warning { border-left-color: #f59e0b; }
.toast.info { border-left-color: #3b82f6; }
.toast-icon { font-size: 20px; flex-shrink: 0; margin-top: 2px; }
.toast-body { flex: 1; }
.toast-title { font-weight: 700; font-size: 14px; margin-bottom: 4px; }
.toast-msg { font-size: 13px; color: #94a3b8; line-height: 1.5; }
.toast-progress {
position: absolute;
bottom: 0; left: 0;
height: 3px;
background: currentColor;
border-radius: 0 0 0 10px;
animation: progress linear forwards;
}
@keyframes slideIn {
from { opacity: 0; transform: translateX(100px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes slideOut {
from { opacity: 1; transform: translateX(0); }
to { opacity: 0; transform: translateX(100px); }
}
@keyframes progress {
from { width: 100%; }
to { width: 0%; }
}
JavaScript Bildirim Kuyruğunu Geliştirme
JavaScript katmanı Lua'dan gelen mesajları işler, DOM öğelerini oluşturur, kuyruğu yönetir ve otomatik kapatmayı gerçekleştirir. Bildirim kuyruğu şarttır çünkü ekranda aynı anda on bildirimin üst üste binmesini istemezsiniz. Görünür sayıyı en fazla beş ile sınırlayın ve taşan bildirimleri kuyruğa alarak öncekilerin süresi doldukça görünmelerini sağlayın. Her bildirimin yapılandırılabilir bir süresi olmalı ve bir bildirime tıklandığında anında kapanmalıdır. Her toast bildiriminin altındaki ilerleme çubuğu, bildirimin ekranda ne kadar kalacağına dair oyunculara görsel bir gösterge sunar.
// html/script.js
const container = document.getElementById('notification-container');
const MAX_VISIBLE = 5;
const queue = [];
let activeCount = 0;
const icons = {
success: '✔',
error: '✖',
warning: '⚠',
info: 'ℹ'
};
const sounds = {
success: new Audio('sounds/success.ogg'),
error: new Audio('sounds/error.ogg'),
warning: new Audio('sounds/warning.ogg'),
info: new Audio('sounds/info.ogg')
};
window.addEventListener('message', (event) => {
if (event.data.type === 'showNotification') {
addNotification(event.data);
}
});
function addNotification(data) {
if (activeCount >= MAX_VISIBLE) {
queue.push(data);
return;
}
createToast(data);
}
function createToast(data) {
activeCount++;
const duration = data.duration || 5000;
const toast = document.createElement('div');
toast.className = `toast ${data.style || 'info'}`;
toast.style.position = 'relative';
toast.innerHTML = `
<div class="toast-icon">${icons[data.style] || icons.info}</div>
<div class="toast-body">
<div class="toast-title">${data.title || ''}</div>
<div class="toast-msg">${data.message}</div>
</div>
<div class="toast-progress" style="animation-duration:${duration}ms"></div>
`;
toast.addEventListener('click', () => dismissToast(toast));
container.appendChild(toast);
if (data.sound !== false && sounds[data.style]) {
sounds[data.style].currentTime = 0;
sounds[data.style].play().catch(() => {});
}
setTimeout(() => dismissToast(toast), duration);
}
function dismissToast(toast) {
if (toast.dataset.dismissed) return;
toast.dataset.dismissed = 'true';
toast.style.animation = 'slideOut 0.3s ease forwards';
setTimeout(() => {
toast.remove();
activeCount--;
if (queue.length > 0) {
createToast(queue.shift());
}
}, 300);
}
Client Tarafı Lua Entegrasyonu
Client tarafında, HTML katmanınıza NUI mesajları gönderen bir fonksiyona ve diğer resource'ların doğrudan script'inizin dahili yapısına bağımlı olmadan bildirim tetikleyebilmesi için bir export'a ihtiyacınız vardır. Gerekli SendNUIMessage native, verileri JavaScript kodunuzun yakaladığı tarayıcı bağlamına aktarır. Bunu başlık, mesaj, tür ve isteğe bağlı süre kabul eden temiz bir API işleviyle sarmalayın. Bildirimlerin hem sunucu tarafı komut dosyalarından hem de diğer istemci kaynaklarından tetiklenebilmesi için hem bir client event hem de bir export kaydedin. Bu ikili yaklaşım, herhangi bir framework ile maksimum uyumluluk sağlar.
-- client.lua
local function ShowNotification(title, message, style, duration, sound)
SendNUIMessage({
type = 'showNotification',
title = title or '',
message = message or '',
style = style or 'info',
duration = duration or 5000,
sound = sound ~= false
})
end
-- Export for other resources
exports('ShowNotification', ShowNotification)
-- Event-based trigger from server
RegisterNetEvent('notifications:show', function(title, message, style, duration)
ShowNotification(title, message, style, duration)
end)
-- Convenience commands for testing
RegisterCommand('testnotify', function()
ShowNotification('Success', 'Your item has been saved.', 'success', 4000)
Wait(500)
ShowNotification('Error', 'Insufficient funds for this purchase.', 'error', 5000)
Wait(500)
ShowNotification('Warning', 'Your vehicle is low on fuel.', 'warning', 4000)
Wait(500)
ShowNotification('Info', 'Press E to interact with the NPC.', 'info', 3000)
end, false)
Sunucu Taraflı Event Dağıtımı
Sunucu tarafı script'i: belirli oyunculara, tüm oyunculara veya oyuncu gruplarına bildirim göndermek için yardımcı fonksiyonlar sunar. Duyuruları yayınlama, işlem onayları gönderme veya şüpheli etkinlikler hakkında admin'leri uyarma gibi kullanım senaryolarını burada yönetirsiniz. Gönderim mantığını sunucuda merkezileştirerek, bildirim iletimi üzerinde tek bir kontrol noktası sağlarsınız. Kötü amaçlı veya hatalı client script'lerinden kaynaklanan bildirim spam'ini önlemek için buraya rate limiting de ekleyebilirsiniz. Sunucu, özel olarak hazırlanmış mesajlar yoluyla NUI injection yapılmasını önlemek için iletmeden önce bildirim parametrelerini doğrulamalıdır.
-- server.lua
local function NotifyPlayer(source, title, message, style, duration)
if not source or source <= 0 then return end
title = tostring(title or '')
message = tostring(message or '')
style = style or 'info'
TriggerClientEvent('notifications:show', source, title, message, style, duration)
end
local function NotifyAll(title, message, style, duration)
TriggerClientEvent('notifications:show', -1, title, message, style, duration)
end
exports('NotifyPlayer', NotifyPlayer)
exports('NotifyAll', NotifyAll)
-- Example: welcome notification
AddEventHandler('playerJoining', function()
local src = source
Wait(3000)
NotifyPlayer(src, 'Welcome', 'Welcome to the server! Have fun.', 'success', 6000)
end)
-- Admin broadcast command
RegisterCommand('broadcast', function(source, args)
if source > 0 and not IsPlayerAceAllowed(source, 'command.broadcast') then return end
local msg = table.concat(args, ' ')
NotifyAll('Announcement', msg, 'info', 8000)
end, true)
Ses Efektleri ve İnce Ayarlar Ekleme
Ses efektleri, bildirimleri yalnızca görsel bir unsur olmaktan çıkarıp çok duyulu bir geri bildirim mekanizmasına dönüştürür. Oyuncular genellikle oyunu arka planda tutar veya araç kullanmaya odaklanır, bu nedenle sessiz bir bildirimi gözden kaçırabilirler. Başarı bildirimleri için kısa ve hafif bir zil sesi, hatalar için boğuk bir uyarı sesi ve bilgi uyarıları için nazik bir ping, oyuncuların bildirim alanına bakmadıklarında bile önemli bilgileri fark etmelerini sağlar. Ses dosyalarınızı 500 milisaniyenin altında tutun ve tarayıcı uyumluluğu için OGG formatını kullanın. Oyun sesini bastırmak yerine onunla uyum sağlaması için ses seviyesini yaklaşık yüzde 30'a ayarlayın. Ses dosyalarınızı şurada saklayın: html/sounds dizini ve ilk bildirimde oynatma gecikmelerini önlemek için bunları JavaScript içinde önceden yükleyin.
Gelişmiş Özellikler ve Özelleştirme
Temel sistemi çalışır hale getirdikten sonra sunucunuzu farklılaştırmak için gelişmiş özellikler eklemeyi düşünün. Oyuncu açıkça tıklayana kadar ekranda kalan kalıcı bildirimler, bekleyen telefon aramaları veya hapis sayaçları gibi önemli uyarılar için kullanışlıdır. Bildirimlerin içindeki işlem butonları, oyuncuların ayrı bir menü açmadan doğrudan yanıt vermesini sağlar; örneğin bir ticaret isteğini kabul etmek gibi. Ayrıca yinelenen aynı bildirimlerin, tekrarlanma sayısını gösteren bir sayaç rozetiyle tek bir bildirime daraltıldığı bildirim gruplandırmasını da uygulayabilirsiniz. Framework entegrasyonu için QBCore veya ESX içindeki varsayılan bildirim fonksiyonlarını geçersiz kılan köprü dosyaları oluşturun; böylece sunucunuzdaki her resource herhangi bir kod değişikliği olmadan otomatik olarak özel sisteminizi kullanır. Framework varsayılanlarını kendi uygulamanızla değiştirme yöntemi, tüm sunucunun arayüzünü tek adımda yükseltmenin temiz bir yoludur.