nil değerine erişme denemesi (yerel 'xPlayer'): ESX düzeltmesi
xPlayer ESX betiğinizde nil mi? ESX.GetPlayerFromId(source) neden nil döndürüyor: oyuncu yüklenmedi, source Wait'ten sonra kayboldu, string kimlikleri, playerDropped. Koruma desenleriyle.
Sunucu konsolunda gösterilir:
SCRIPT ERROR: @my_script/server/main.lua:23: attempt to index a nil value (local 'xPlayer')local xPlayer = ESX.GetPlayerFromId(source)
xPlayer.addMoney(100) -- xPlayer is nilESX.GetPlayerFromId o kimlik için hiçbir oyuncu bulamadı ve nil döndürdü, ve sonraki satır buna erişmeye çalıştı. Çağrı sorun değildir. Verdiğiniz kimlik yüklü bir ESX oyuncusu ile eşleşmiyor. İşte yaygın nedenler ve her birine karşı nasıl korunacağı.
1. Oyuncu henüz yüklenmedi
Oyuncu ESX karakterini yüklemeyi bitirmeden önce sunucuya bağlanır. O ara sırada ve çok karakterli ekran açık iken, ESX.GetPlayerFromId(source) nil döndürür.
Bu, playerJoining veya playerConnecting gibi genel FiveM olayları veya kaynağınız başladığı andan itibaren başlayan bir iş parçacığı gibi erken çalışan kodu etkiler.
Oyuncu hazır olduğunda sunucuda tetiklenen ESX olayını kullanın:
AddEventHandler('esx:playerLoaded', function(playerId, xPlayer, isNew)
print(('%s is loaded'):format(xPlayer.getName()))
end)İstemci tarafında, aynı olay adı istemci betiğinize oyuncunun kullanılabileceğini söyler:
RegisterNetEvent('esx:playerLoaded', function(xPlayer)
PlayerLoaded = true
end)Betiğiniz oyuncular çevrimiçi iken yeniden başlatılabilirse, o olay onlar için zaten tetiklenmişdir. Başlangıçta, ESX'in zaten sahip olduğu oyuncular üzerinde döngü kurun:
CreateThread(function()
for _, playerId in ipairs(GetPlayers()) do
local xPlayer = ESX.GetPlayerFromId(tonumber(playerId))
if xPlayer then
-- set up the player
end
end
end)2. Source Wait'ten sonra değişti
source FiveM'in çalışan olay için ayarladığı özel bir globaldir. İşleyici içinde beklemeye koyarsanız, bu arada başka bir olay çalışabilir ve source artık oyuncunuza ait olmaz.
RegisterNetEvent('my_script:buy', function(item)
Wait(500)
local xPlayer = ESX.GetPlayerFromId(source) -- source may be someone else, or invalid
end)Başka bir şey olmadan önce bunu yerel olarak depolayın:
RegisterNetEvent('my_script:buy', function(item)
local src = source
Wait(500)
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
end)Aynı şey bir geri çağırı içinde veya source ilettiğiniz bir işlev içinde geçerlidir: global değil depolanan değeri iletin.
3. Kimlik yanlış
ESX.GetPlayerFromId çevrimiçi olan bir oyuncunun sunucu kimliğine numara olarak ihtiyaç duyar.
- Bir string kimlik. Komut argümanları metindir.
ESX.GetPlayerFromId(args[1])nil döndürebilir,ESX.GetPlayerFromId(tonumber(args[1]))işe yarar. - İstemciden yanlış kimlik. İstemci tarafında,
PlayerId()yerel bir indeks, sunucu kimliği değil. Sunucu kimliğiGetPlayerServerId(PlayerId())dir. Yanlışını göndermek var olmayan bir oyuncu veya yanlış oyuncu verir. - Konsol. Sunucu konsolunda yazılan bir komutun
sourcedeğeri0dir, bu bir oyuncu değildir. - Kimlik araması aracılığıyla bir kimlik.
ESX.GetPlayerFromIdentifier(identifier)sadece çevrimiçi oyuncuları bulur. Çevrimdışı bir oyuncu için, bunun yerine veritabanını okuyun, bkz. oxmysql sorguları rehberi.
RegisterCommand('givecash', function(source, args)
local target = tonumber(args[1])
local amount = tonumber(args[2])
if not target or not amount then
return print('Usage: /givecash [id] [amount]')
end
local xTarget = ESX.GetPlayerFromId(target)
if not xTarget then
return print('Player not found or not loaded')
end
xTarget.addMoney(amount)
end, true)Önemli bir şey için istemciden gönderilen bir kimliğe güvenmeyin. source kullanın, bu sunucu olaylarını güvenli hale getirme kısmında açıklandığı üzere sahte yapılamaz.
4. Oyuncu ayrıldı
Oyuncu kodunuz beklerken ayrılırsa, örneğin uzun bir döngü veya zamanlayıcı içinde, GetPlayerFromId sonunda çalıştığında nil döndürür. Bu normal bir durumdur, bir hata değildir ve aynı korumaya ihtiyaç duyar.
playerDropped içinde durum daha az açıktır, çünkü ESX da bu olayı işleyip oyuncuyu kaydetmek ve kaldırmak için işler ve işleyicilerin sırası güvenilecek bir şey değildir. ESX Legacy da kendi esx:playerDropped olayını tetikler, ancak sürümünüzün bunu içerip içermediğini kontrol edin. En sağlam yaklaşım, oyuncu çevrimiçi iken verileri kendiniz tutmaktır:
local sessions = {}
AddEventHandler('esx:playerLoaded', function(playerId, xPlayer)
sessions[playerId] = {
identifier = xPlayer.identifier,
job = xPlayer.job.name,
}
end)
AddEventHandler('playerDropped', function()
local data = sessions[source]
if data then
print(('%s left, job %s'):format(data.identifier, data.job))
sessions[source] = nil
end
end)Koruma deseni
Bir oyuncu kullanan her sunucu işleyiciyi aynı şekilde başlatın:
RegisterNetEvent('my_script:sell', function(item, count)
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
-- from here xPlayer is safe to use
xPlayer.addMoney(100)
end)Aynı kontrol ESX.RegisterServerCallback ile kaydedilen sunucu geri çağırıları içine gider, ilk argüman oyuncunun kaynağıdır:
ESX.RegisterServerCallback('my_script:getJob', function(source, cb)
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return cb(nil) end
cb(xPlayer.job.name)
end)İstemci tarafını da kontrol edin: geri çağırıdan nil cevabını kabul etmelidir.
İpucu: hata bunun yerine
attempt to index a nil value (global 'ESX')ise, sorun ESX nesnesidir, oyuncu değil. Bkz. ESX nil: esx:getSharedObject düzeltme.
Kontrol Listesi
| Belirtisi | Düzeltme |
|---|---|
| Oyuncu katılır katılmaz nil | playerJoining yerine esx:playerLoaded beklemeyi yapın |
Wait den sonra nil |
Önce local src = source depolayın ve src kullanın |
| Komuttan nil | Argümanı tonumber ile dönüştürün; source konsolda 0 dir |
| İstemci tarafından gönderilen kimlikle nil | source kullanın; istemci tarafında sunucu kimliği GetPlayerServerId(PlayerId()) |
playerDropped içinde nil |
Oyuncu çevrimiçi iken ihtiyaç duyduğunuz verileri kendi tablonuzda tutun |
| Çevrimdışı oyuncu için nil | GetPlayerFromId sadece çevrimiçi oyuncuları bulur; veritabanını sorgulayın |
| Herhangi bir nil | İşleyicinin üstüne if not xPlayer then return end ekleyin |
Kısa yanıtlar
xPlayer neden ESX'de nil?
ESX.GetPlayerFromId(source) ESX'in o kimlik için yüklü oyuncu olmadığında nil döndürür. Oyuncu henüz yüklenmemiş olabilir, kimlik yanlış veya string olabilir veya oyuncu zaten ayrılmış olabilir.
Her olayda xPlayer kontrol etmeliyim?
Evet. Herhangi bir sunucu olayı yüklenmemiş bir oyuncu tarafından tetiklenebilir, bu nedenle işleyiciyi if not xPlayer then return end ile başlatın. Hiçbir şeye mal olmaz ve hatayı engeller.
playerDropped içinde xPlayer kullanabilir miyim?
Buna güvenmek güvenli değildir, çünkü ESX oyuncuyu zaten kaldırmış olabilir. Oyuncu çevrimiçi iken ihtiyaç duyduğunuz verileri kendi tablonuzda tutun ve oradan okuyun.
Bu sorunu yaşatmayan scriptler
Shop CreatorBir dakikadan kısa sürede dükkân kurun — sahipler, çalışanlar, kasalar ve soygunlar dahil.Scripti gör →
Pawn Shop Applb-phone içinde oyuncudan oyuncuya rehin pazarı.Scripti gör →
Drug Dealer Applb-phone uygulaması olarak sokak satışı: bölgeler, NPC alıcılar, seviyeler ve polis ihbarları.Scripti gör →