From cad096e7a679c08ab53418b5cb4cb5644f3824fe Mon Sep 17 00:00:00 2001 From: Jerrit Fritzsche Date: Mon, 27 Jul 2026 20:30:45 +0200 Subject: [PATCH] aether-core: Spawn-Race praeziser beheben (Charakterauswahl-Crash) Der vorige spawnPlayer-Ansatz fixte nur den Direkt-Spawn-Weg (AutoCharakter=true), verschaerfte aber den Auswahl-Weg: OeffneAuswahl teleportiert/versteckt den Ped, waehrend der erzwungene Spawn noch synchronisiert -> zwei Threads schreiben Netz-State -> Crash. Neuer Ansatz: Auto-Spawn so frueh wie moeglich (ab Resource-Start, Retry-Schleife) abschalten und KEINEN eigenen Spawn erzwingen. Der vorhandene GTA-Standard-Ped bleibt in Ruhe; die Charakterauswahl fasst einen fertigen Ped an. Kein zweiter Spawn-Thread -> kein Race. Co-Authored-By: Claude Opus 4.8 --- .../[aether]/aether-core/client/main.lua | 62 +++++++------------ 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/resources/[aether]/aether-core/client/main.lua b/resources/[aether]/aether-core/client/main.lua index 8069dfa..bb24632 100644 --- a/resources/[aether]/aether-core/client/main.lua +++ b/resources/[aether]/aether-core/client/main.lua @@ -13,54 +13,34 @@ Aether.IstGeladen = false -- --------------------------------------------------------------------- -- Startvorgang -- --------------------------------------------------------------------- +-- WICHTIG: Auto-Spawn des spawnmanagers so FRÜH wie möglich abschalten — +-- bevor er den Spieler von sich aus spawnt. Genau dieser unkontrollierte +-- Spawn läuft parallel zur Charakterauswahl (die den Ped teleportiert/ +-- versteckt): zwei Threads schreiben gleichzeitig Netz-State -> +-- "SendNetPacket ... called from multiple threads" -> Client-Crash. +-- Wir spawnen NICHT selbst — GTA hat ohnehin einen Standard-Ped. Der bleibt +-- in Ruhe, und die Charakterauswahl fasst einen fertigen, ruhenden Ped an. +CreateThread(function() + for _ = 1, 100 do + if pcall(function() exports.spawnmanager:setAutoSpawn(false) end) then break end + Wait(0) + end +end) + CreateThread(function() -- Warten, bis die Spielwelt bereit ist while not NetworkIsSessionStarted() do Wait(100) end - -- Bildschirm sofort schwarz halten, bevor irgendetwas spawnt + -- Sicherheitshalber erneut abschalten, falls der spawnmanager eben erst + -- bereit wurde (verhindert einen späten Auto-Spawn). + pcall(function() exports.spawnmanager:setAutoSpawn(false) end) + + -- Bildschirm schwarz halten und den Ped verstecken, bis der Charakter + -- geladen ist. KEIN eigener Spawn -> kein zweiter Spawn-Thread. 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 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 - - -- 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) + SetEntityVisible(PlayerPedId(), false, false) Aether.Debug('Client bereit — fordere Spielerdaten an.') TriggerServerEvent('aether:server:spielerBereit')