FiveM olayları: RegisterNetEvent, TriggerServerEvent, TriggerClientEvent
FiveM istemci ve sunucu olayları nasıl çalışır: RegisterNetEvent, AddEventHandler, TriggerServerEvent, TriggerClientEvent -1 ile, source değişkeni ve olay adlandırması.
Oyun ve sunucu arasındaki çoğu betik hatası olaylara indirgenir: hiçbir zaman çalışmayan bir işleyici, kimseye gönderilmeyen bir olay veya yanlış oyuncuya işaret eden bir source.
Bu makale ağ olaylarının nasıl çalıştığını, her iki yönde nasıl kaydedilecekleri ve tetiklenecekleri ve iki betiğin hiçbir zaman çarpışmayacağı şekilde adlandırılması açıklar.
İki taraf
FiveM kaynağı istemci (oyuncu başına bir kopya) ve sunucu (bir kopya) üzerinde kod olabilir. Olaylar aracılığıyla konuşurlar:
| From | To | Function |
|---|---|---|
| Client | Server | TriggerServerEvent |
| Server | One client | TriggerClientEvent(name, playerId, ...) |
| Server | All clients | TriggerClientEvent(name, -1, ...) |
| Same side | Same side | TriggerEvent |
Argümanlar serileştirilir, bu nedenle sayılar, dizeler, boolean'lar ve tablolar gönderebilirsiniz. İşlevleri gönderemezsiniz. Varlık tutamaçları her makineye yereldir, bu nedenle bunun yerine bir ağ kimliği (NetworkGetNetworkIdFromEntity) gönderin.
İşleyici kaydetme
İşleyici, olay geldiğinde çalışan bir işlevdir. Ağdan gelen bir olay için bunu da izin verilen olarak işaretlemeniz gerekir:
RegisterNetEvent('my_script:client:notify', function(message)
print(message)
end)Kısa form bu: RegisterNetEvent işlevi ikinci argüman olarak olayı kaydeder ve işleyiciyi ekler. Uzun form aynı iki adımda yapar:
RegisterNetEvent('my_script:client:notify')
AddEventHandler('my_script:client:notify', function(message)
print(message)
end)Yalnızca AddEventHandler kullanırsanız, işleyici yerel TriggerEvent çağrıları için çalışır, ancak diğer taraftan TriggerServerEvent veya TriggerClientEvent görmezden gelinir. Bu, hiçbir şey yapmayan bir olayın en yaygın nedenidir.
İstemciden sunucuya
-- client
TriggerServerEvent('my_script:server:buy', 'water', 2)-- server
RegisterNetEvent('my_script:server:buy', function(item, amount)
local src = source
print(('player %s wants %s x %s'):format(src, amount, item))
end)Sunucuda, global source olayı tetikleyen oyuncunun kimliğini tutar. İstemci bunu göndermez, bu nedenle argümanlarını değiştiren bir istemci tarafından sahte yapılamaz.
Sunucudan istemciye
-- server: to one player
TriggerClientEvent('my_script:client:notify', src, 'Purchase done')
-- server: to everyone
TriggerClientEvent('my_script:client:notify', -1, 'Server restart in 5 minutes')-- client
RegisterNetEvent('my_script:client:notify', function(message)
print(message)
end)TriggerClientEvent ikinci argümanı her zaman hedeftir. Unutursanız, ilk veri argümanınız oyuncu kimliği olarak okunur ve olay hiç yere gitmez.
Beklemeden önce source'u kaydedin
source sahip olduğunuz bir değer değildir, çalışan olay için runtime'ın ayarladığı globaldir. İşleyiciniz Wait çağırırsa veya MySQL.query.await gibi getiri veren bir şey çağırırsa, bu arada başka olay çalışabilir ve source değişir.
RegisterNetEvent('my_script:server:buy', function(item, amount)
local src = source -- copy it first
Wait(500) -- or any await
print(src) -- still the right player
print(source) -- may be someone else now
end)Her sunucu işleyicisinin ilk satırı local src = source yapın ve bundan sonra src kullanın. Aynı şey, bir işleve ilettiğiniz geri çağırı içinde de geçerlidir.
Olayları adlandırma
Olaylar tüm sunucuya globaldir: herhangi bir kaynak herhangi bir olay adını tetikleyebilir. İki betik de buy veya server:buy kaydederse, her iki işleyici de çalışır ve oyuncu ada göre tetikleyebilir.
Her olayın ön eki kaynağı ve tarafı:
'my_script:server:buy'
'my_script:client:updateJob'Diğer betiklerin olay adlarını yeniden kullanmayın ve olayınızı giveMoney gibi genel bir ad vermeyin. Okunabilir bir ad da konsolda hangi betiğin ne gönderdiğini açık yapar.
İstemciye asla güvenmeyin
TriggerServerEvent aracılığıyla gelen her şey bir hileci tarafından herhangi bir argümanla, herhangi bir zamanda tetiklenebilir. Sunucuda kontrol edin:
- oyuncunun bunu yapmasına izin verileceğini (iş, mesafe, soğuma),
- tutarlar ve öğe adlarının geçerli olduğunu,
- asla argümanlardan fiyat veya ödül almadığını.
RegisterNetEvent('my_script:server:buy', function(item, amount)
local src = source
if type(amount) ~= 'number' or amount < 1 or amount > 10 then return end
-- look the price up on the server, do not read it from the client
end)Tam liste sunucu olaylarını güvenli hale getirme kısmında. Arayanın geri dönmesi gereken sonuç için geri çağırı iki olaydan daha temiz: bkz. ESX, QBCore ve ox_lib'deki sunucu geri çağırıları.
Büyük veya sık olaylar
Her olay bir ağ mesajıdır. Her karede birini tetiklemeyín ve tüm oyunculara çok büyük bir tablo göndermeyín. Sunucu konsolu güvenilir olaylar taştığında söylerse, çok fazla, çok hızlı gönderiyorsunuz: bkz. güvenilir ağ olay taşması.
Kontrol Listesi
| Belirtisi | Düzeltme |
|---|---|
| İşleyici diğer taraftan hiçbir zaman çalışmaz | Yalnızca AddEventHandler değil RegisterNetEvent kullanın |
TriggerClientEvent kimseye ulaşmaz |
İkinci argüman olarak oyuncu kimliği veya -1 geçirin |
source nil veya yanlış oyuncu |
local src = source ilk satır, herhangi Wait den önce |
| İki betik aynı olaya tepki verir | Adları kaynağıyla önek verin: my_script:server:buy |
| İstemci kendisine öğe veya para verebilir | Sunucuda doğrulayın ve fiyatları orada arayın |
| Konsol veya gecikme olay spam'ı | Daha az, daha az sıklıkla gönderin: güvenilir ağ olay taşması bakın |
Kısa yanıtlar
RegisterNetEvent ile AddEventHandler arasındaki fark nedir?
RegisterNetEvent olayın ağın diğer tarafından tetiklenmesine izin verir. AddEventHandler sadece bir işlev ekler. Ağ olayı için bir işleyici her ikisine de ihtiyaç duyar veya işlevi ikinci argüman olarak RegisterNetEvent ile.
Her oyuncuya bir olay nasıl gönderilir?
Sunucuda, TriggerClientEvent('my_script:client:thing', -1, data). -1 tüm bağlı istemciler anlamına gelir.
Sunucu olayımda kaynak neden yanlış?
source geçerli olayı tetikleyen oyuncuyu tutan globaldir. Wait çağırırsanız ve bu arada başka olay çalışırsa değişir. Önce yerel olarak kopyalayın: local src = source.
Bu sorunu yaşatmayan scriptler
Advanced BoostingTabletten araç boosting: D’den S+ sınıfına kontratlar, ekipler ve canlı sıra.Scripti gör →
Drug Dealer Applb-phone uygulaması olarak sokak satışı: bölgeler, NPC alıcılar, seviyeler ve polis ihbarları.Scripti gör →
Shop CreatorBir dakikadan kısa sürede dükkân kurun — sahipler, çalışanlar, kasalar ve soygunlar dahil.Scripti gör →