FiveM CreateThread ve Wait(0) açıklanmış: neden script'iniz ms tutuyor

CreateThread, Wait ve SetTimeout FiveM Lua'da nasıl çalışır, her döngüde Wait(0) neden resmon'da görünür ve Wait'siz while döngüsü neden oyunu donduruyor.

Bir şeyi kontrol etmek için bir döngü yazarsınız ve oyun cevap vermeyi durdurur veya resmon kaynağınızı hareketsizken birkaç ms'de gösterir:

lua
while true do
    -- no Wait here: the game never gets control back
    local ped = PlayerPedId()
end

Bu makale, FiveM Lua'da thread'ler ve Wait nasıl çalışır, Wait(0) gerçekten ne kadara mal olur ve ucuz kalan döngüler nasıl yazılır açıklar.

Thread'ler FiveM'de nasıl çalışır

FiveM'deki Lua işbirliğidir. Script'iniz oyun ile paralel olarak çalışmaz: runtime onu çağırdığında çalışır ve kontrol geri vermelidir. İki şey bunu mümkün kılar:

  • Event handler'ları ve geri çağrıları bir kez çalışır, baştan sonuna kadar, sonra geri döner.
  • Thread'ler CreateThread ile oluşturulan küçük coroutine'lerdir, scheduler bunları tekrar tekrar devam ettirir. Bir thread, Wait çağırdığında kontrol geri verir.
lua
CreateThread(function()
    while true do
        Wait(1000)
        print('one second later')
    end
end)

CreateThread ve Citizen.CreateThread aynı fonksiyon, Wait ve Citizen.Wait de öyle. Hangisini isterseniz kullanın, ama bir script'te tutarlı olun.

Wait'siz while döngüsü oyunu donduruyor

Bir thread asla Wait çağırmazsa, scheduler asla kontrol geri almaz. Client'ta oyun, döngü bitene kadar frame çizmeyi durdurur ve server'da diğer her script senininkini bekler.

lua
CreateThread(function()
    while true do
        -- missing Wait: this blocks the whole client
    end
end)

Aynı şey repeat … until veya ağır işleme yapan uzun for döngüsü ile de olur. Bir süre çalışabilen her döngünün içinde Wait gerekir. Script oyunu başlangıçta donduruyor sa, önce böyle bir döngü arayın.

Wait(0) ne kadara mal olur

Wait(0) anlamı: client'ta sonraki frame'e veya server'da sonraki tick'e kadar durakla, sonra devam et. Döngü her frame'de tekrar çalışır, bu nedenle 60 fps'de gövdesi saniyede 60 kez ödenir.

lua
CreateThread(function()
    while true do
        Wait(0)
        local coords = GetEntityCoords(PlayerPedId())
        local dist = #(coords - vector3(215.0, -810.0, 30.7))
        if dist < 3.0 then
            -- draw a marker, show text...
        end
    end
end)

Böyle bir döngü çok az mal olur. Otuz kaynak arasında on tanesi birkaç ms istemci zamanı ekler, bu tam olarak resmon yüksek ms olarak gösterir. Maliyet Wait(0) nin kendisi değil, her frame'de tekrarladığınız her şeydir.

Wait yalnızca ihtiyacınız kadar kısa

Çoğu kontrol her frame'de çalışması gerekmez. Döngü ne için sorun:

Döngü ne yapıyor Makul wait
Marker veya metin çiz, tuş basmasını işle 0 (yalnızca oyuncu yakın olduğu zaman)
Bir şeyin yakın olup olmadığını belirlemek için mesafeyi kontrol et 250 to 1000
Nadiren değişen bir durumu yokla (iş, araç) 1000 veya daha fazla, veya olay kullanın

Usual trick iki hızdır: mesafeyi kontrol eden yavaş döngü ve oyuncu bölgenin içinde olurken hızlı bir tane.

lua
local zone = vector3(215.0, -810.0, 30.7)

CreateThread(function()
    while true do
        local sleep = 1000
        local dist = #(GetEntityCoords(PlayerPedId()) - zone)

        if dist < 10.0 then
            sleep = 0
            DrawMarker(1, zone.x, zone.y, zone.z - 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                1.5, 1.5, 0.5, 255, 255, 255, 120, false, false, 2, false, nil, nil, false)
        end

        Wait(sleep)
    end
end)

Bölgeden uzakta, thread saniyede bir kez uyanır. Yakınında, her frame'de çizer. Resmon çoğu oyuncu için neredeyse hiçbir şeye düşer.

İpucu: daha hızlı bir döngüye ulaşmadan önce, bir olay veya state bag değer değiştiğinde sizi söyleyip söyleyemeyeceğini sorun. Hiçbir döngü hiçbir Wait'den daha ucuzdur.

SetTimeout: bir şeyi sonra bir kez çalıştır

Yalnızca gecikmeden sonra bir kez bir şey yapmanız gerekiyorsa, bir thread'e Wait gerekli değildir:

lua
SetTimeout(5000, function()
    print('five seconds later')
end)

SetTimeout(ms, callback) geri çağrıyı gecikmeden sonra bir kez çalıştırır ve hiçbir şeyi engel olmez. Server'da da var. Tekrarlayan bir görev için, SetTimeout kendiliğinden tekrarlama olmadığından Wait ile bir thread doğru araçtır.

Event handler'lar içinde bekleme

Bir event handler da Wait çağırabilir, çünkü FiveM onu kendi coroutine'inde çalıştırır. Server'da dikkatli olun: Wait sonra, global source artık olayı tetikleyen oyuncuya işaret etmez. Önce kaydedin (client ve server olaylarına bakın):

lua
RegisterNetEvent('my_script:server:buy', function()
    local src = source
    Wait(500)
    print(('player %s bought something'):format(src))
end)

Thread'i durdurma

Bir thread, fonksiyonu geri döndüğünde biter. Bir döngüyü dışarıdan durdurmak için, döngünün kontrol ettiği bir bayrak kullanın:

lua
local running = true

CreateThread(function()
    while running do
        Wait(500)
        -- work
    end
end)

AddEventHandler('onResourceStop', function(resource)
    if resource == GetCurrentResourceName() then
        running = false
    end
end)

Bir kaynağın tüm thread'leri, kaynak durdurulduğunda kendi kendine durur, bu nedenle kaynak çalışmaya devam ederken bir döngüyü durdurmak için buna ihtiyacınız var.

Kontrol listesi

Belirti Fix
Script başladığında oyun donuyor while true do döngüsünün Wait yok: bir tane ekleyin
Kaynak hareketsizken resmon'da sabit ms gösteriyor Wait(0) yerine mesafe kontrol ve daha uzun bekleme ile değiştirin
Gecikmeden sonra bir şey bir kez çalıştırması gerekir Thread yerine SetTimeout(ms, fn)
Server'da Wait sonra source yanlış Wait öncesinde local src = source kaydedin
Nadiren değişen bir değeri yoklama Döngü yerine olay veya state bag kullanın
Citizen.Wait veya Wait? Aynı fonksiyon, bir stil seçin

Kısa yanıtlar

FiveM'de Wait(0) ne yapar?

Mevcut thread'i client'ta sonraki frame'e veya server'da sonraki tick'e kadar duraklatır. Döngü daha sonra her frame'de tekrar çalışır, bu nedenle içindeki her şey saniyede 60 veya daha fazla kez ödenir.

Citizen.Wait, Wait'ten farklı mı?

Hayır. Wait ve Citizen.Wait aynı fonksiyon, CreateThread ve Citizen.CreateThread de öyle. Kısa adlar sadece takma adlar.

Wait tüm oyunu durdurur mu?

Hayır. Yalnızca onu çağıran thread'i duraklatır ve diğer thread'ler ve oyun çalışmaya devam eder. Asla Wait çağırmayan bir döngü, her şeyi engeller.

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 →CCTV Security CamerasYerleştirilebilir kameralar, canlı çoklu görüntü tableti ve basılı delil fotoğrafları.Scripti gör →Mic PhoneTablete dönüşen katlanabilir bir telefon; oyuncunun gerçek telefonuna da taşınır.Scripti gör →

Okumaya devam edin