From a5c517ff659b70499afaf9a5319a7e524feff66d Mon Sep 17 00:00:00 2001 From: Jerrit Fritzsche Date: Mon, 27 Jul 2026 19:55:06 +0200 Subject: [PATCH] aether-core: Netzwerk-Race beim Spawn beheben (Charakterauswahl-Crash) Der Core schaltete Auto-Spawn ab, erzwang aber keinen kontrollierten Spawn und fasste den Ped sofort an. Dadurch lief die unkontrollierte Spawn-Erzeugung des spawnmanagers parallel zur Ped-Manipulation von Core/Character -> zwei Threads schrieben gleichzeitig Netz-State: "SendNetPacket called from multiple threads" -> Client-Crash beim Charaktermenue (schwarzer Bildschirm, dann Absturz). Fix: Auto-Spawn aus, EINMAL kontrolliert via spawnPlayer spawnen, auf den Callback warten und den Ped erst danach unsichtbar/geparkt setzen. Co-Authored-By: Claude Opus 4.8 --- .../[aether]/aether-core/client/main.lua | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/resources/[aether]/aether-core/client/main.lua b/resources/[aether]/aether-core/client/main.lua index db26895..8069dfa 100644 --- a/resources/[aether]/aether-core/client/main.lua +++ b/resources/[aether]/aether-core/client/main.lua @@ -19,18 +19,48 @@ CreateThread(function() Wait(100) end - -- Standard-Spawnverhalten von FiveM unterbinden. - -- Abgesichert, falls spawnmanager nicht laeuft (dann uebernimmt der Core allein). - local erfolg = pcall(function() + -- Bildschirm sofort schwarz halten, bevor irgendetwas spawnt + DoScreenFadeOut(0) + + -- WICHTIG: den Spawn deterministisch selbst steuern. + -- Ohne einen kontrollierten Spawn liefert der spawnmanager den Ped + -- unkontrolliert (Auto-Spawn) — dann fasst der Core/Character-Flow den + -- Ped an, WÄHREND die Netzwerk-Erzeugung noch läuft. Zwei Threads + -- schreiben dann gleichzeitig Netz-State: + -- "SendNetPacket ... called from multiple threads" -> Client-Crash. + -- Lösung: Auto-Spawn AUS, EINMAL kontrolliert spawnen, und den Ped erst + -- NACH dem Spawn-Callback anfassen. + local spawnFertig = false + local hatSpawnmanager = pcall(function() exports.spawnmanager:setAutoSpawn(false) + exports.spawnmanager:spawnPlayer({ + x = Config.SpawnPunkt.x, + y = Config.SpawnPunkt.y, + z = Config.SpawnPunkt.z, + heading = Config.SpawnPunkt.heading or 0.0, + model = 'mp_m_freemode_01', + skipFade = true, -- wir steuern den Fade selbst + }, function() + spawnFertig = true + end) end) - if not erfolg then + + if hatSpawnmanager then + -- Auf den Spawn-Callback warten (mit Sicherheitslimit ~5 s) + local versuche = 0 + while not spawnFertig and versuche < 100 do + Wait(50) + versuche = versuche + 1 + end + else Aether.Debug('spawnmanager nicht verfuegbar — Core spawnt eigenstaendig.') end - -- Bildschirm schwarz halten, bis der Charakter geladen ist - DoScreenFadeOut(0) - SetEntityVisible(PlayerPedId(), false, false) + -- Jetzt existiert ein gültiger, gestreamter Ped. Erst JETZT anfassen: + -- unsichtbar und geparkt halten, bis der Charakter gewählt ist. + local ped = PlayerPedId() + SetEntityVisible(ped, false, false) + FreezeEntityPosition(ped, true) Aether.Debug('Client bereit — fordere Spielerdaten an.') TriggerServerEvent('aether:server:spielerBereit')