-- client.lua local QBCore = exports['qb-core']:GetCoreObject() local activeZones = {} local spawnedProps = {} local processedVehicles = {} local menu = false -- Debug Funktion function DebugPrint(text) if Config.Debug then print('[Traffic Control] ' .. tostring(text)) end end -- Hotkey Registration RegisterKeyMapping('trafficmenu', 'Öffne Verkehrssteuerung', 'keyboard', Config.Hotkey) RegisterCommand('trafficmenu', function() local job = QBCore.Functions.GetPlayerData().job if Config.AllowedJobs[job.name] then ToggleMenu() end end) function ToggleMenu() if menu then CloseMenu() else OpenMenu() end end function OpenMenu() if menu then return end local job = QBCore.Functions.GetPlayerData().job if not Config.AllowedJobs[job.name] then DebugPrint('Keine Berechtigung für Job: ' .. job.name) return end menu = true SendNUIMessage({ action = "open", items = Config.Items }) SetNuiFocus(true, true) DebugPrint('Menü geöffnet') end function CloseMenu() menu = false SetNuiFocus(false, false) SendNUIMessage({ action = "close" }) DebugPrint('Menü geschlossen') end RegisterNUICallback('closeMenu', function(data, cb) CloseMenu() cb('ok') end) RegisterNUICallback('setPoint', function(data, cb) local coords = GetEntityCoords(PlayerPedId()) local radius = tonumber(data.radius) or 30.0 local zone = { coords = coords, radius = radius } table.insert(activeZones, zone) spawnBarrier(coords, data.item) CloseMenu() DebugPrint('Punkt gesetzt bei ' .. vec3(coords.x, coords.y, coords.z)) cb('ok') end) function spawnBarrier(coords, itemModel) DebugPrint('Versuche Barriere zu spawnen: ' .. itemModel) local prop = CreateObject(GetHashKey(itemModel), coords.x, coords.y, coords.z - 1.0, true, false, false) if prop and DoesEntityExist(prop) then PlaceObjectOnGroundProperly(prop) FreezeEntityPosition(prop, true) table.insert(spawnedProps, prop) DebugPrint('Barriere erfolgreich gespawnt') else DebugPrint('Fehler beim Spawnen der Barriere') end end -- NPC Steuerung Citizen.CreateThread(function() while true do Citizen.Wait(100) if #activeZones == 0 then Citizen.Wait(1000) goto continue end for _, zone in pairs(activeZones) do local vehicles = GetGamePool('CVehicle') for _, vehicle in pairs(vehicles) do if DoesEntityExist(vehicle) then local vehicleCoords = GetEntityCoords(vehicle) local distance = #(vehicleCoords - zone.coords) local detectionRange = zone.radius + 30.0 -- Erkennung 30 Meter vor der Zone if distance <= detectionRange and not processedVehicles[vehicle] then local driver = GetPedInVehicleSeat(vehicle, -1) if DoesEntityExist(driver) and not IsPedAPlayer(driver) then processedVehicles[vehicle] = true -- Bremse das Fahrzeug SetVehicleForwardSpeed(vehicle, 0.0) TaskVehicleTempAction(driver, vehicle, 27, 1000) -- Bremsaktion -- Warte kurz Citizen.Wait(1000) -- Hole aktuelle Position und Heading local currentHeading = GetEntityHeading(vehicle) -- Drehe um 180 Grad local newHeading = currentHeading + 180.0 if newHeading > 360.0 then newHeading = newHeading - 360.0 end -- Führe die Drehung aus TaskVehicleTempAction(driver, vehicle, 6, 2000) -- Drehe nach links -- Warte auf Drehung Citizen.Wait(2000) -- Fahre weg local escapePoint = vector3( vehicleCoords.x - (math.cos(math.rad(currentHeading)) * 100.0), vehicleCoords.y - (math.sin(math.rad(currentHeading)) * 100.0), vehicleCoords.z ) TaskVehicleDriveToCoordLongrange( driver, vehicle, escapePoint.x, escapePoint.y, escapePoint.z, 20.0, -- Geschwindigkeit 786603, -- Driving Style 20.0 -- Stopping Range ) -- Lösche Fahrzeug nach Entfernung Citizen.SetTimeout(8000, function() if DoesEntityExist(vehicle) then local newDist = #(GetEntityCoords(vehicle) - zone.coords) if newDist > detectionRange * 2 then DeleteEntity(vehicle) processedVehicles[vehicle] = nil end end end) end end end end end ::continue:: end end) -- Cleanup Thread für processedVehicles Citizen.CreateThread(function() while true do Citizen.Wait(30000) for vehicle, _ in pairs(processedVehicles) do if not DoesEntityExist(vehicle) then processedVehicles[vehicle] = nil end end end end) -- Zusätzlicher Thread für Fußgänger Citizen.CreateThread(function() while true do Citizen.Wait(500) if #activeZones == 0 then Citizen.Wait(1000) goto continue end for _, zone in pairs(activeZones) do local peds = GetGamePool('CPed') for _, ped in pairs(peds) do if DoesEntityExist(ped) and not IsPedAPlayer(ped) and not IsPedInAnyVehicle(ped, false) then local pedCoords = GetEntityCoords(ped) local distance = #(pedCoords - zone.coords) if distance <= (zone.radius + 10.0) then -- Berechne Fluchtrichtung local awayVector = vector3( pedCoords.x - zone.coords.x, pedCoords.y - zone.coords.y, 0.0 ) local escapePoint = vector3( pedCoords.x + (awayVector.x * 2), pedCoords.y + (awayVector.y * 2), pedCoords.z ) -- Lasse Ped weglaufen ClearPedTasks(ped) TaskGoStraightToCoord(ped, escapePoint.x, escapePoint.y, escapePoint.z, 2.0, -1, 0.0, 0.0) -- Lösche Ped nach einer Weile Citizen.SetTimeout(8000, function() if DoesEntityExist(ped) then DeleteEntity(ped) end end) end end end end ::continue:: end end) -- Cleanup Thread Citizen.CreateThread(function() while true do Citizen.Wait(30000) for vehicle, _ in pairs(processedVehicles) do if not DoesEntityExist(vehicle) then processedVehicles[vehicle] = nil end end end end) -- Cleanup Command und Event RegisterCommand('trafficclean', function() local job = QBCore.Functions.GetPlayerData().job if Config.AllowedJobs[job.name] then TriggerEvent('traffic:cleanup') QBCore.Functions.Notify('Verkehrssteuerung zurückgesetzt', 'success') end end) RegisterNetEvent('traffic:cleanup') AddEventHandler('traffic:cleanup', function() for _, prop in pairs(spawnedProps) do if DoesEntityExist(prop) then DeleteEntity(prop) end end spawnedProps = {} activeZones = {} processedVehicles = {} DebugPrint('Aufräumen abgeschlossen') end)