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 <noreply@anthropic.com>
This commit is contained in:
Jerrit Fritzsche 2026-07-27 20:30:45 +02:00
parent 0440de16e5
commit cad096e7a6

View File

@ -13,54 +13,34 @@ Aether.IstGeladen = false
-- --------------------------------------------------------------------- -- ---------------------------------------------------------------------
-- Startvorgang -- 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() CreateThread(function()
-- Warten, bis die Spielwelt bereit ist -- Warten, bis die Spielwelt bereit ist
while not NetworkIsSessionStarted() do while not NetworkIsSessionStarted() do
Wait(100) Wait(100)
end 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) DoScreenFadeOut(0)
SetEntityVisible(PlayerPedId(), false, false)
-- 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)
Aether.Debug('Client bereit — fordere Spielerdaten an.') Aether.Debug('Client bereit — fordere Spielerdaten an.')
TriggerServerEvent('aether:server:spielerBereit') TriggerServerEvent('aether:server:spielerBereit')