-- ===================================================================== -- Aether Character — Clientlogik -- Zeigt die Charakterauswahl, verwaltet die Kamera und meldet die -- Auswahl an den Server. Der Core uebernimmt danach das Spawnen. -- ===================================================================== -- Ist die Auswahl gerade offen? local auswahlOffen = false -- Ort, an dem der Spieler waehrend der Auswahl geparkt wird local PARKPLATZ = { x = -1037.7, y = -2737.6, z = 20.2 } -- --------------------------------------------------------------------- -- Auswahl oeffnen / schliessen -- --------------------------------------------------------------------- --- Oeffnet die Charakterauswahl mit der Liste vom Server --- @param charaktere table Liste der Charaktere --- @param maxSlots number Maximale Anzahl Charaktere local function OeffneAuswahl(charaktere, maxSlots) auswahlOffen = true -- Eigenen Spieler unsichtbar parken — sichtbar ist nur der Vorschau-Ped local ped = PlayerPedId() SetEntityVisible(ped, false, false) FreezeEntityPosition(ped, true) SetEntityCoordsNoOffset(ped, PARKPLATZ.x, PARKPLATZ.y, PARKPLATZ.z, false, false, false) -- 3D-Vorschau mit dem Aussehen des ersten Charakters starten local erstes = charaktere and charaktere[1] or nil Vorschau.Starten(erstes and erstes.aussehen or nil, 'koerper') -- Ladebildschirm beenden, damit die Auswahl sichtbar wird ShutdownLoadingScreen() ShutdownLoadingScreenNui() DoScreenFadeIn(800) SetNuiFocus(true, true) SendNuiMessage(json.encode({ aktion = 'oeffnen', charaktere = charaktere, maxSlots = maxSlots, })) end --- Schliesst die Auswahl und gibt die Steuerung frei local function SchliesseAuswahl() if not auswahlOffen then return end auswahlOffen = false SendNuiMessage(json.encode({ aktion = 'schliessen' })) SetNuiFocus(false, false) DoScreenFadeOut(400) Wait(400) Vorschau.Beenden() end -- --------------------------------------------------------------------- -- Ereignisse vom Server -- --------------------------------------------------------------------- --- Server fordert die Charakterauswahl an RegisterNetEvent('aether:character:zeigeAuswahl', function(charaktere, maxSlots) OeffneAuswahl(charaktere, maxSlots) end) --- Aktualisierte Liste nach Erstellen oder Loeschen RegisterNetEvent('aether:character:liste', function(charaktere, maxSlots, hinweis) SendNuiMessage(json.encode({ aktion = 'liste', charaktere = charaktere, maxSlots = maxSlots, hinweis = hinweis, })) end) --- Server lehnt eine Aktion ab (z. B. Slot voll, ungueltiger Name) RegisterNetEvent('aether:character:fehler', function(text) SendNuiMessage(json.encode({ aktion = 'fehler', text = text })) end) --- Charakter wurde gewaehlt: Auswahl sofort schliessen, damit der Core --- ungestoert spawnen kann (Netz-Event kommt gleichzeitig beim Core an) RegisterNetEvent('aether:client:spielerGeladen', function() if auswahlOffen then SchliesseAuswahl() end end) --- Der Core hat den Ped gesetzt und gespawnt: jetzt das Aussehen anwenden. --- Eigenes Event, damit wir nicht mit dem Modellwechsel des Cores kollidieren. AddEventHandler('aether:client:bereit', function(daten) if daten and daten.aussehen then AetherAussehen.Anwenden(PlayerPedId(), daten.aussehen) end local ped = PlayerPedId() FreezeEntityPosition(ped, false) SetEntityVisible(ped, true, false) end) -- --------------------------------------------------------------------- -- NUI-Callbacks (Aktionen aus der Oberflaeche) -- --------------------------------------------------------------------- --- Aussehen hat sich geaendert: sofort auf den Vorschau-Ped uebertragen RegisterNUICallback('vorschau', function(daten, rueckgabe) if daten.aussehen then Vorschau.Anwenden(daten.aussehen) end if daten.modus then Vorschau.SetzeModus(daten.modus) end rueckgabe({ ok = true }) end) --- Ansicht wechseln (Gesicht / Koerper) RegisterNUICallback('vorschauModus', function(daten, rueckgabe) Vorschau.SetzeModus(daten.modus or 'koerper') rueckgabe({ ok = true }) end) --- Vorschau-Ped drehen RegisterNUICallback('vorschauDrehen', function(daten, rueckgabe) Vorschau.Drehen(tonumber(daten.grad) or 0.0) rueckgabe({ ok = true }) end) --- Spieler waehlt einen Charakter zum Spielen RegisterNUICallback('spielen', function(daten, rueckgabe) TriggerServerEvent('aether:character:spielen', daten.charakterId) rueckgabe({ ok = true }) end) --- Spieler legt einen neuen Charakter an RegisterNUICallback('erstellen', function(daten, rueckgabe) TriggerServerEvent('aether:character:erstellen', daten) rueckgabe({ ok = true }) end) --- Spieler loescht einen Charakter RegisterNUICallback('loeschen', function(daten, rueckgabe) TriggerServerEvent('aether:character:loeschen', daten.charakterId) rueckgabe({ ok = true }) end) -- --------------------------------------------------------------------- -- Aufraeumen beim Stoppen der Ressource -- --------------------------------------------------------------------- AddEventHandler('onResourceStop', function(ressource) if ressource ~= GetCurrentResourceName() then return end SetNuiFocus(false, false) Vorschau.Beenden() FreezeEntityPosition(PlayerPedId(), false) SetEntityVisible(PlayerPedId(), true, false) end)