-- ===================================================================== -- aether-admin — Clientlogik -- -- Öffnet das Panel und führt die Eingriffe aus, die nur am Client -- möglich sind (Teleport, Heilen, Spectate, Fahrzeug spawnen …). Der -- Client entscheidet nichts selbst — er tut, was der (rechteprüfende) -- Server ihm aufträgt. -- ===================================================================== local istOffen = false local darfPanel = false -- vom Server bestätigt -- --------------------------------------------------------------------- -- Hilfen -- --------------------------------------------------------------------- local function SendeAnNui(nachricht) SendNuiMessage(json.encode(nachricht)) end local function Meldung(text) if not text or text == '' then return end BeginTextCommandThefeedPost('STRING') AddTextComponentSubstringPlayerName(text) EndTextCommandThefeedPostTicker(false, true) end local function Schliessen() if not istOffen then return end istOffen = false SetNuiFocus(false, false) SendeAnNui({ aktion = 'schliessen' }) end -- --------------------------------------------------------------------- -- Panel öffnen / schließen -- --------------------------------------------------------------------- RegisterNetEvent('aether-admin:zeige', function(daten) darfPanel = true istOffen = true SetNuiFocus(true, true) daten.aktion = 'oeffnen' SendeAnNui(daten) end) RegisterNetEvent('aether-admin:verweigert', function(text) Meldung('~r~' .. (text or 'Kein Zugriff.')) end) RegisterNetEvent('aether-admin:antwort', function(ruf, ergebnis, fehler) SendeAnNui({ aktion = 'antwort', ruf = ruf, ergebnis = ergebnis, fehler = fehler }) end) RegisterCommand('adminpanel', function() TriggerServerEvent('aether-admin:oeffnen') end, false) RegisterKeyMapping('adminpanel', 'Admin-Panel öffnen', 'keyboard', 'F9') -- Melder aus dem Spiel: /report RegisterCommand('report', function(source, args) local text = table.concat(args, ' ') if #text < 2 then Meldung('~y~Nutzung: /report ') return end TriggerServerEvent('aether-admin:report', text:sub(1, 120), text) end, false) -- --------------------------------------------------------------------- -- NUI-Callbacks -- --------------------------------------------------------------------- RegisterNUICallback('schliessen', function(_, cb) Schliessen() cb({ ok = true }) end) --- Zentraler Aufruf: Oberfläche → Server → Antwort RegisterNUICallback('aufruf', function(daten, cb) TriggerServerEvent('aether-admin:aufruf', tostring(daten.modul or ''), tostring(daten.aktion or ''), daten.daten or {}, daten.ruf) cb({ ok = true }) end) --- Wegpunkt setzen (aus Weltkarte / Spieleraktionen) RegisterNUICallback('wegpunkt', function(daten, cb) if daten.x and daten.y then SetNewWaypoint(daten.x + 0.0, daten.y + 0.0) end cb({ ok = true }) end) -- --------------------------------------------------------------------- -- Zustands-Eingriffe am eigenen Ped (vom Server ausgelöst) -- --------------------------------------------------------------------- RegisterNetEvent('aether-admin:client:heal', function() local ped = PlayerPedId() SetEntityHealth(ped, GetEntityMaxHealth(ped)) ClearPedBloodDamage(ped) ClearPedWetness(ped) Meldung('~g~Du wurdest geheilt.') end) RegisterNetEvent('aether-admin:client:revive', function() local ped = PlayerPedId() local erledigt = pcall(function() exports['aether-death']:Wiederbeleben() end) if not erledigt then local pos = GetEntityCoords(ped) NetworkResurrectLocalPlayer(pos.x, pos.y, pos.z, GetEntityHeading(ped), true, false) SetEntityHealth(ped, GetEntityMaxHealth(ped)) end Meldung('~g~Du wurdest wiederbelebt.') end) RegisterNetEvent('aether-admin:client:armor', function() SetPedArmour(PlayerPedId(), 100) Meldung('~g~Rüstung aufgefüllt.') end) RegisterNetEvent('aether-admin:client:freeze', function(an) local ped = PlayerPedId() FreezeEntityPosition(ped, an and true or false) Meldung(an and '~b~Du wurdest eingefroren.' or '~g~Du wurdest aufgetaut.') end) RegisterNetEvent('aether-admin:client:god', function(an) local ped = PlayerPedId() SetEntityInvincible(ped, an and true or false) SetPlayerInvincible(PlayerId(), an and true or false) end) RegisterNetEvent('aether-admin:client:teleport', function(pos) if not pos or not pos.x then return end local ped = PlayerPedId() SetEntityCoords(ped, pos.x + 0.0, pos.y + 0.0, pos.z + 0.0, false, false, false, false) end) RegisterNetEvent('aether-admin:client:hinweis', function(text) Meldung('~y~' .. tostring(text)) end) RegisterNetEvent('aether-admin:client:broadcast', function(daten) local farbe = daten.typ == 'Warnung' and '~r~' or daten.typ == 'Neustart' and '~o~' or '~b~' Meldung(('%s[%s] ~s~%s'):format(farbe, daten.typ or 'Info', daten.text or '')) PlaySoundFrontend(-1, 'Menu_Accept', 'Phone_SoundSet_Default', true) end) -- --------------------------------------------------------------------- -- Fahrzeug spawnen (am eigenen Ped) -- --------------------------------------------------------------------- RegisterNetEvent('aether-admin:client:fahrzeug', function(modell) local hash = GetHashKey(modell) if not IsModelInCdimage(hash) or not IsModelAVehicle(hash) then Meldung('~r~Unbekanntes Fahrzeugmodell: ' .. tostring(modell)) return end RequestModel(hash) local zeit = GetGameTimer() while not HasModelLoaded(hash) and GetGameTimer() - zeit < 5000 do Wait(10) end if not HasModelLoaded(hash) then return end local ped = PlayerPedId() local pos = GetEntityCoords(ped) local heading = GetEntityHeading(ped) local veh = CreateVehicle(hash, pos.x + 2.5, pos.y, pos.z, heading, true, false) SetVehicleNumberPlateText(veh, 'ADMIN') SetPedIntoVehicle(ped, veh, -1) SetModelAsNoLongerNeeded(hash) Meldung('~g~Fahrzeug gespawnt: ' .. modell) end) RegisterNetEvent('aether-admin:client:fahrzeugFix', function(netId) local veh = NetworkGetEntityFromNetworkId(netId) if veh and veh ~= 0 and DoesEntityExist(veh) then SetVehicleFixed(veh); SetVehicleDeformationFixed(veh) SetVehicleEngineHealth(veh, 1000.0); SetVehicleBodyHealth(veh, 1000.0) SetVehicleDirtLevel(veh, 0.0) Meldung('~g~Fahrzeug repariert.') else Meldung('~y~Fahrzeug nicht in Reichweite — bitte näher heranfahren.') end end) RegisterNetEvent('aether-admin:client:fahrzeugHer', function(netId) local veh = NetworkGetEntityFromNetworkId(netId) if veh and veh ~= 0 and DoesEntityExist(veh) then local pos = GetEntityCoords(PlayerPedId()) local heading = GetEntityHeading(PlayerPedId()) SetEntityCoords(veh, pos.x + 3.0, pos.y, pos.z, false, false, false, false) SetEntityHeading(veh, heading) Meldung('~g~Fahrzeug hergeholt.') else Meldung('~y~Fahrzeug nicht in Reichweite.') end end) -- --------------------------------------------------------------------- -- Beobachten (native Spectate) — zusätzlich zur WebRTC-Kamera -- --------------------------------------------------------------------- local beobachtet = false RegisterNetEvent('aether-admin:client:spectate', function(daten) if beobachtet then StoppeSpectate(); return end local zielSpieler = GetPlayerFromServerId(daten.ziel) -- Ohne Ziel in Reichweite zuerst zur letzten bekannten Position if daten.pos then SetEntityCoords(PlayerPedId(), daten.pos.x + 0.0, daten.pos.y + 0.0, daten.pos.z + 30.0, false, false, false, false) Wait(600) end local zielPed = GetPlayerFromServerId(daten.ziel) ~= -1 and GetPlayerPed(GetPlayerFromServerId(daten.ziel)) or 0 if zielPed == 0 or not DoesEntityExist(zielPed) then Meldung('~y~Ziel nicht erreichbar (zu weit weg?).') return end NetworkSetInSpectatorMode(true, zielPed) beobachtet = true Meldung('~b~Beobachtungsmodus — [Rücktaste] beendet ihn.') CreateThread(function() while beobachtet do Wait(0) if IsControlJustReleased(0, 194) then StoppeSpectate() end -- Backspace end end) end) function StoppeSpectate() if not beobachtet then return end NetworkSetInSpectatorMode(false, PlayerPedId()) beobachtet = false Meldung('~g~Beobachtung beendet.') end -- --------------------------------------------------------------------- -- Weltzustand anwenden (Zeit / Wetter / Blackout) -- --------------------------------------------------------------------- local welt = { stunde = 12, minute = 0, wetter = 'CLEAR', zeitFix = false, wetterFix = false, blackout = false } RegisterNetEvent('aether-admin:client:welt', function(neu) if type(neu) ~= 'table' then return end welt = neu SetWeatherTypeOverTime(welt.wetter, 15.0) SetArtificialLightsState(welt.blackout and true or false) end) CreateThread(function() while true do Wait(welt.zeitFix and 0 or 2000) if welt.zeitFix then NetworkOverrideClockTime(welt.stunde, welt.minute, 0) end if welt.wetterFix then SetWeatherTypeNow(welt.wetter) end if welt.blackout then SetArtificialLightsState(true) end end end) -- --------------------------------------------------------------------- -- Positions-Cache füttern (Weltkarte, Teleport, Spectate) -- --------------------------------------------------------------------- CreateThread(function() while true do Wait(3000) local pos = GetEntityCoords(PlayerPedId()) TriggerServerEvent('aether-admin:pos', { x = pos.x, y = pos.y, z = pos.z }) end end) -- --------------------------------------------------------------------- -- Aufräumen -- --------------------------------------------------------------------- AddEventHandler('onResourceStop', function(ressource) if ressource ~= GetCurrentResourceName() then return end SetNuiFocus(false, false) if beobachtet then NetworkSetInSpectatorMode(false, PlayerPedId()) end end)