FiveM CreateThread und Wait(0) erklärt: Warum dein Skript ms kostet
Wie CreateThread, Wait und SetTimeout in FiveM Lua funktionieren, warum Wait(0) in jeder Schleife in resmon angezeigt wird und warum eine While-Schleife ohne Wait das Spiel einfriert.
Du schreibst eine Schleife, um etwas zu überprüfen, und das Spiel hört auf zu antworten, oder resmon zeigt deine Ressource bei ein paar ms, während du still stehst:
while true do
-- no Wait here: the game never gets control back
local ped = PlayerPedId()
endDieser Artikel erklärt, wie Threads und Wait in FiveM Lua funktionieren, was Wait(0) wirklich kostet und wie man Schleifen schreibt, die billig bleiben.
Wie Threads in FiveM funktionieren
Lua in FiveM ist kooperativ. Dein Skript läuft nicht parallel mit dem Spiel: Es läuft, wenn die Runtime es aufruft, und es muss die Kontrolle zurückgeben. Zwei Dinge machen das möglich:
- Event-Handler und Callbacks laufen einmal, von Anfang bis Ende, dann kehren zurück.
- Threads, die mit
CreateThreaderstellt werden, sind kleine Coroutines, die der Scheduler immer wieder aufnimmt. Ein Thread gibt die Kontrolle zurück, wenn erWaitaufruft.
CreateThread(function()
while true do
Wait(1000)
print('one second later')
end
end)CreateThread und Citizen.CreateThread sind die gleiche Funktion, ebenso wie Wait und Citizen.Wait. Verwende, welche du magst, aber sei in einem Skript konsistent.
Eine While-Schleife ohne Wait friert das Spiel ein
Wenn ein Thread niemals Wait aufruft, gibt der Scheduler nie die Kontrolle zurück. Auf dem Client stoppt das Spiel das Zeichnen von Frames bis die Schleife endet, und auf dem Server warten alle anderen Skripte auf deines.
CreateThread(function()
while true do
-- missing Wait: this blocks the whole client
end
end)Das gleiche passiert mit einer repeat … until oder einer langen for-Schleife, die schwere Arbeit tut. Jede Schleife, die eine Weile laufen kann, braucht ein Wait darin. Wenn ein Skript das Spiel beim Start aufhängt, schau zuerst nach einer Schleife wie dieser.
Was Wait(0) kostet
Wait(0) bedeutet: Pause bis zum nächsten Frame (Client) oder zum nächsten Tick (Server), dann weiter. Die Schleife läuft wieder auf jedem Frame, sodass bei 60 fps sein Körper 60 Mal pro Sekunde bezahlt wird.
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)Eine Schleife wie diese kostet wenig. Zehn von ihnen, über dreißig Ressourcen verteilt, summieren sich auf mehrere ms an Client-Zeit, was genau das ist, das resmon als hohe ms zeigt. Die Kosten sind nicht Wait(0) selbst, es ist alles, das du jeden Frame wiederholst.
Warte nur so kurz, wie du brauchst
Die meisten Überprüfungen brauchen nicht auf jedem Frame zu laufen. Frag dich, wofür die Schleife ist:
| Was die Schleife macht | Angemessenes Warten |
|---|---|
| Zeichne einen Marker oder Text, verwalte einen Tastendruck | 0 (nur wenn der Spieler nah ist) |
| Überprüfe eine Entfernung, um zu entscheiden, ob etwas nah ist | 250 bis 1000 |
| Frage einen Zustand ab, der sich selten ändert (Job, Fahrzeug) | 1000 oder mehr, oder verwende ein Event |
Der übliche Trick ist zwei Geschwindigkeiten: eine langsame Schleife, die die Entfernung überprüft, und eine schnelle nur, während der Spieler im Gebiet ist.
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)Weit weg von der Zone wacht der Thread einmal pro Sekunde auf. In der Nähe zeichnet er auf jedem Frame. Resmon fällt für die meisten Spieler auf fast nichts.
Tipp: Bevor du nach einer schnelleren Schleife greifst, frag dich, ob ein Event oder ein State Bag dir mitteilen kann, wenn sich der Wert ändert. Gar keine Schleife ist billiger als jedes Wait.
SetTimeout: Etwas einmal, später ausführen
Wenn du nur etwas einmal nach einer Verzögerung tun musst, brauchst du keinen Thread mit einem Wait:
SetTimeout(5000, function()
print('five seconds later')
end)SetTimeout(ms, callback) führt den Callback einmal nach der Verzögerung aus und blockiert nichts. Es existiert auch auf dem Server. Für eine wiederholte Aufgabe ist ein Thread mit Wait das richtige Werkzeug, da SetTimeout nicht von allein wiederholt.
Warten innerhalb von Event-Handlern
Ein Event-Handler kann auch Wait aufrufen, weil FiveM ihn in seiner eigenen Coroutine ausführt. Seien Sie vorsichtig auf dem Server: Nach einem Wait zeigt die globale source nicht mehr auf den Spieler, der das Event ausgelöst hat. Speichern Sie es zuerst (siehe Client und Server Events):
RegisterNetEvent('my_script:server:buy', function()
local src = source
Wait(500)
print(('player %s bought something'):format(src))
end)Einen Thread stoppen
Ein Thread endet, wenn seine Funktion zurückkehrt. Um eine Schleife von außen zu stoppen, verwende eine Flagge, die die Schleife überprüft:
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)Alle Threads einer Ressource stoppen von allein, wenn die Ressource stoppt, daher brauchst du das nur, um eine Schleife zu stoppen, während die Ressource weiterlauft.
Checkliste
| Symptom | Behebung |
|---|---|
| Spiel friert ein, wenn ein Skript startet | Eine while true do-Schleife hat kein Wait: Füge einen hinzu |
| Ressource zeigt konstante ms in resmon im Leerlauf | Ersetze Wait(0) durch eine Entfernungsprüfung und ein längeres Warten |
| Brauche, etwas einmal nach einer Verzögerung auszuführen | SetTimeout(ms, fn) anstelle eines Threads |
source ist nach einem Wait auf dem Server falsch |
Speichere local src = source vor dem Wait |
| Polling eines Wertes, der sich selten ändert | Verwende ein Event oder einen State Bag anstelle einer Schleife |
Citizen.Wait oder Wait? |
Die gleiche Funktion, wähle einen Stil |
Kurze Antworten
Was macht Wait(0) in FiveM?
Es pausiert den aktuellen Thread bis zum nächsten Frame auf dem Client oder zum nächsten Server-Tick. Die Schleife läuft dann auf jedem Frame erneut, sodass alles darin 60 oder mehr Mal pro Sekunde bezahlt wird.
Ist Citizen.Wait anders als Wait?
Nein. Wait und Citizen.Wait sind die gleiche Funktion, ebenso wie CreateThread und Citizen.CreateThread. Die Kurznamen sind nur Aliase.
Friert Wait das ganze Spiel ein?
Nein. Es pausiert nur den Thread, der es aufruft, und die anderen Threads und das Spiel laufen weiter. Eine Schleife, die niemals Wait aufruft, ist das, was alles blockiert.
Scripts ohne dieses Problem
Advanced BoostingFahrzeug-Boosting per Tablet: Aufträge von Klasse D bis S+, Crews und eine Live-Warteschlange.Script ansehen →
CCTV Security CamerasPlatzierbare Kameras, ein Live-Tablet mit Multi-View und ausgedruckte Beweisfotos.Script ansehen →
Mic PhoneEin faltbares Handy, das sich zum Tablet aufklappt und bis aufs echte Handy des Spielers reicht.Script ansehen →