aether-admin: Netzwerk-Race beim Join beheben

Die Client-Threads (Positions-Meldung, Wetter/Zeit) liefen ab Resource-
Start ungebremst — also schon während Ladebildschirm/Charakterauswahl,
bevor der Spieler gespawnt ist. Zusammen mit den Server-Events der
Character-NUI (eigener Thread) führte das zu gleichzeitigen Netz-Sends:
"SendNetPacket called from multiple threads" -> Client-Crash.

Fix: Nichts Vernetztes vor 'aether:client:bereit' (Spieler geladen).
Weltzustand wird beim Spawn einmalig angewandt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jerrit Fritzsche 2026-07-27 19:36:38 +02:00
parent 800acf2117
commit 32879ac07b

View File

@ -9,6 +9,15 @@
local istOffen = false local istOffen = false
local darfPanel = false -- vom Server bestätigt local darfPanel = false -- vom Server bestätigt
local geladen = false -- Spieler ist fertig geladen und gespawnt
-- Erst wenn der Core den Spieler gespawnt hat, darf dieser Client etwas
-- Vernetztes tun. Vorher (Ladebildschirm/Charakterauswahl) würden Netz-
-- Sends aus Hintergrund-Threads mit dem Spawn kollidieren
-- ("SendNetPacket called from multiple threads").
AddEventHandler('aether:client:bereit', function()
geladen = true
end)
-- --------------------------------------------------------------------- -- ---------------------------------------------------------------------
-- Hilfen -- Hilfen
@ -239,24 +248,36 @@ end
local welt = { stunde = 12, minute = 0, wetter = 'CLEAR', local welt = { stunde = 12, minute = 0, wetter = 'CLEAR',
zeitFix = false, wetterFix = false, blackout = false } zeitFix = false, wetterFix = false, blackout = false }
--- Weltzustand merken. Angewandt wird er erst, wenn der Spieler im Spiel ist
--- (sonst kollidiert das Wetter-Native mit dem Spawn).
RegisterNetEvent('aether-admin:client:welt', function(neu) RegisterNetEvent('aether-admin:client:welt', function(neu)
if type(neu) ~= 'table' then return end if type(neu) ~= 'table' then return end
welt = neu welt = neu
if geladen then
SetWeatherTypeOverTime(welt.wetter, 15.0)
SetArtificialLightsState(welt.blackout and true or false)
end
end)
-- Beim Laden den zwischengespeicherten Weltzustand einmalig anwenden
AddEventHandler('aether:client:bereit', function()
SetWeatherTypeOverTime(welt.wetter, 15.0) SetWeatherTypeOverTime(welt.wetter, 15.0)
SetArtificialLightsState(welt.blackout and true or false) SetArtificialLightsState(welt.blackout and true or false)
end) end)
CreateThread(function() CreateThread(function()
while true do while true do
Wait(welt.zeitFix and 0 or 2000) Wait(geladen and welt.zeitFix and 0 or 2000)
if welt.zeitFix then if geladen then
NetworkOverrideClockTime(welt.stunde, welt.minute, 0) if welt.zeitFix then
end NetworkOverrideClockTime(welt.stunde, welt.minute, 0)
if welt.wetterFix then end
SetWeatherTypeNow(welt.wetter) if welt.wetterFix then
end SetWeatherTypeNow(welt.wetter)
if welt.blackout then end
SetArtificialLightsState(true) if welt.blackout then
SetArtificialLightsState(true)
end
end end
end end
end) end)
@ -267,8 +288,11 @@ end)
CreateThread(function() CreateThread(function()
while true do while true do
Wait(3000) Wait(3000)
local pos = GetEntityCoords(PlayerPedId()) -- Erst melden, wenn der Spieler wirklich im Spiel ist
TriggerServerEvent('aether-admin:pos', { x = pos.x, y = pos.y, z = pos.z }) if geladen then
local pos = GetEntityCoords(PlayerPedId())
TriggerServerEvent('aether-admin:pos', { x = pos.x, y = pos.y, z = pos.z })
end
end end
end) end)