2025-08-05 00:18:35 +02:00
|
|
|
local QBCore = exports['qb-core']:GetCoreObject()
|
2025-08-05 09:48:15 +02:00
|
|
|
local activeTrackings = {}
|
|
|
|
local trackingBlips = {}
|
|
|
|
local inTrackingZone = false
|
|
|
|
local currentLocation = nil
|
|
|
|
|
2025-08-05 09:56:00 +02:00
|
|
|
-- Safety check for Config
|
|
|
|
if not Config then
|
|
|
|
Config = {}
|
|
|
|
Config.TrackingLocations = {
|
|
|
|
{
|
|
|
|
coords = vector3(369.79, -1588.01, 29.43),
|
|
|
|
radius = 2.0,
|
|
|
|
job = {"police"},
|
|
|
|
label = "Polizei Tracking System"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Config.EnableCommand = true
|
|
|
|
Config.Command = "tracking"
|
|
|
|
Config.InteractKey = 38
|
|
|
|
print("^1Warning: Config not loaded properly, using default values^7")
|
|
|
|
end
|
|
|
|
|
2025-08-05 09:48:15 +02:00
|
|
|
-- Command to open tracking menu (if enabled in config)
|
|
|
|
if Config.EnableCommand then
|
|
|
|
RegisterCommand(Config.Command, function()
|
|
|
|
local PlayerData = QBCore.Functions.GetPlayerData()
|
|
|
|
local job = PlayerData.job.name
|
|
|
|
|
|
|
|
-- Überprüfe ob Job berechtigt ist
|
|
|
|
local allowedJobs = {'police', 'ambulance', 'mechanic'} -- Füge hier weitere Jobs hinzu
|
|
|
|
local hasPermission = false
|
|
|
|
|
|
|
|
for _, allowedJob in pairs(allowedJobs) do
|
|
|
|
if job == allowedJob then
|
|
|
|
hasPermission = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if not hasPermission then
|
|
|
|
QBCore.Functions.Notify('Du hast keine Berechtigung für das Tracking-System!', 'error')
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
OpenTrackingMenu()
|
|
|
|
end)
|
|
|
|
end
|
2025-08-05 00:18:35 +02:00
|
|
|
|
2025-08-05 09:56:00 +02:00
|
|
|
-- Rest of your client.lua code...
|
|
|
|
|
|
|
|
|
2025-08-05 09:48:15 +02:00
|
|
|
-- Check if player is near a tracking location
|
|
|
|
CreateThread(function()
|
|
|
|
while true do
|
|
|
|
local playerPed = PlayerPedId()
|
|
|
|
local playerCoords = GetEntityCoords(playerPed)
|
|
|
|
local sleep = 1000
|
|
|
|
local isInZone = false
|
|
|
|
local currentLocationData = nil
|
|
|
|
|
|
|
|
for _, location in pairs(Config.TrackingLocations) do
|
|
|
|
local distance = #(playerCoords - location.coords)
|
|
|
|
|
|
|
|
if distance < location.radius then
|
|
|
|
sleep = 0
|
|
|
|
isInZone = true
|
|
|
|
currentLocationData = location
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if isInZone and not inTrackingZone then
|
|
|
|
inTrackingZone = true
|
|
|
|
currentLocation = currentLocationData
|
|
|
|
-- Check if player has the required job for this location
|
|
|
|
local PlayerData = QBCore.Functions.GetPlayerData()
|
|
|
|
local hasRequiredJob = false
|
|
|
|
|
|
|
|
for _, jobName in pairs(currentLocation.job) do
|
|
|
|
if PlayerData.job.name == jobName then
|
|
|
|
hasRequiredJob = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if hasRequiredJob then
|
|
|
|
-- Show DrawText UI
|
|
|
|
exports['qb-core']:DrawText(currentLocation.label, 'left')
|
|
|
|
end
|
|
|
|
elseif not isInZone and inTrackingZone then
|
|
|
|
inTrackingZone = false
|
|
|
|
currentLocation = nil
|
|
|
|
exports['qb-core']:HideText()
|
2025-08-05 00:18:35 +02:00
|
|
|
end
|
2025-08-05 09:48:15 +02:00
|
|
|
|
|
|
|
Wait(sleep)
|
2025-08-05 00:18:35 +02:00
|
|
|
end
|
2025-08-05 09:48:15 +02:00
|
|
|
end)
|
|
|
|
|
|
|
|
-- Key press detection for tracking locations
|
|
|
|
CreateThread(function()
|
|
|
|
while true do
|
|
|
|
local sleep = 1000
|
|
|
|
|
|
|
|
if inTrackingZone and currentLocation then
|
|
|
|
sleep = 0
|
|
|
|
-- Check if player has the required job for this location
|
|
|
|
local PlayerData = QBCore.Functions.GetPlayerData()
|
|
|
|
local hasRequiredJob = false
|
|
|
|
|
|
|
|
for _, jobName in pairs(currentLocation.job) do
|
|
|
|
if PlayerData.job.name == jobName then
|
|
|
|
hasRequiredJob = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if hasRequiredJob and IsControlJustPressed(0, Config.InteractKey) then
|
|
|
|
exports['qb-core']:HideText()
|
|
|
|
OpenTrackingMenu()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Wait(sleep)
|
2025-08-05 00:18:35 +02:00
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
function OpenTrackingMenu()
|
|
|
|
local options = {
|
|
|
|
{
|
|
|
|
title = 'Fahrzeug orten',
|
|
|
|
description = 'Fahrzeug über Kennzeichen orten',
|
|
|
|
icon = 'fas fa-search',
|
|
|
|
onSelect = function()
|
|
|
|
TrackVehicle()
|
|
|
|
end
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title = 'Aktive Trackings',
|
|
|
|
description = 'Zeige alle aktiven Trackings',
|
|
|
|
icon = 'fas fa-list',
|
|
|
|
onSelect = function()
|
|
|
|
ShowActiveTrackings()
|
|
|
|
end
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title = 'Tracking beenden',
|
|
|
|
description = 'Beende ein aktives Tracking',
|
|
|
|
icon = 'fas fa-times',
|
|
|
|
onSelect = function()
|
|
|
|
StopTracking()
|
|
|
|
end
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lib.registerContext({
|
|
|
|
id = 'tracking_menu',
|
|
|
|
title = 'Fahrzeug Tracking System',
|
|
|
|
options = options
|
|
|
|
})
|
|
|
|
|
|
|
|
lib.showContext('tracking_menu')
|
|
|
|
end
|
|
|
|
|
|
|
|
function TrackVehicle()
|
|
|
|
local input = lib.inputDialog('Fahrzeug Tracking', {
|
|
|
|
{
|
|
|
|
type = 'input',
|
|
|
|
label = 'Kennzeichen',
|
|
|
|
description = 'Gib das Kennzeichen des Fahrzeugs ein',
|
|
|
|
required = true,
|
|
|
|
max = 8
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
if not input then return end
|
|
|
|
|
|
|
|
local plate = string.upper(input[1])
|
|
|
|
|
|
|
|
QBCore.Functions.TriggerCallback('tracking:server:trackVehicle', function(success, message, vehicleData)
|
|
|
|
if success then
|
|
|
|
QBCore.Functions.Notify('Fahrzeug wird getrackt!', 'success')
|
|
|
|
StartTracking(plate, vehicleData)
|
|
|
|
else
|
|
|
|
QBCore.Functions.Notify(message, 'error')
|
|
|
|
end
|
|
|
|
end, plate)
|
|
|
|
end
|
|
|
|
|
|
|
|
function StartTracking(plate, vehicleData)
|
|
|
|
if activeTrackings[plate] then
|
|
|
|
QBCore.Functions.Notify('Fahrzeug wird bereits getrackt!', 'error')
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
activeTrackings[plate] = {
|
|
|
|
vehicle = vehicleData.vehicle,
|
|
|
|
coords = vehicleData.coords,
|
2025-08-05 09:31:49 +02:00
|
|
|
lastUpdate = GetGameTimer(),
|
|
|
|
owner = vehicleData.owner or "Unbekannt"
|
2025-08-05 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
-- Erstelle Blip
|
|
|
|
local blip = AddBlipForCoord(vehicleData.coords.x, vehicleData.coords.y, vehicleData.coords.z)
|
|
|
|
SetBlipSprite(blip, 225)
|
|
|
|
SetBlipDisplay(blip, 4)
|
|
|
|
SetBlipScale(blip, 0.8)
|
|
|
|
SetBlipColour(blip, 1)
|
|
|
|
SetBlipAsShortRange(blip, false)
|
|
|
|
BeginTextCommandSetBlipName("STRING")
|
|
|
|
AddTextComponentString("Tracking: " .. plate)
|
|
|
|
EndTextCommandSetBlipName(blip)
|
|
|
|
|
|
|
|
trackingBlips[plate] = blip
|
|
|
|
|
2025-08-05 09:31:49 +02:00
|
|
|
-- Zeige Besitzerinformation an
|
|
|
|
QBCore.Functions.Notify('Fahrzeug gehört: ' .. activeTrackings[plate].owner, 'info', 5000)
|
|
|
|
|
2025-08-05 00:18:35 +02:00
|
|
|
-- Starte Update Loop
|
|
|
|
CreateThread(function()
|
|
|
|
while activeTrackings[plate] do
|
|
|
|
TriggerServerEvent('tracking:server:updateVehicleLocation', plate)
|
|
|
|
Wait(5000) -- Update alle 5 Sekunden
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
function ShowActiveTrackings()
|
|
|
|
local options = {}
|
|
|
|
|
|
|
|
if next(activeTrackings) == nil then
|
|
|
|
options[#options + 1] = {
|
|
|
|
title = 'Keine aktiven Trackings',
|
|
|
|
description = 'Derzeit werden keine Fahrzeuge getrackt',
|
|
|
|
icon = 'fas fa-info-circle'
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for plate, data in pairs(activeTrackings) do
|
|
|
|
local distance = #(GetEntityCoords(PlayerPedId()) - vector3(data.coords.x, data.coords.y, data.coords.z))
|
|
|
|
options[#options + 1] = {
|
|
|
|
title = 'Kennzeichen: ' .. plate,
|
2025-08-05 09:31:49 +02:00
|
|
|
description = 'Besitzer: ' .. data.owner .. ' | Entfernung: ' .. math.floor(distance) .. 'm | Letztes Update: ' .. math.floor((GetGameTimer() - data.lastUpdate) / 1000) .. 's',
|
2025-08-05 00:18:35 +02:00
|
|
|
icon = 'fas fa-car',
|
|
|
|
onSelect = function()
|
|
|
|
SetNewWaypoint(data.coords.x, data.coords.y)
|
|
|
|
QBCore.Functions.Notify('Wegpunkt zum Fahrzeug gesetzt!', 'success')
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
lib.registerContext({
|
|
|
|
id = 'active_trackings',
|
|
|
|
title = 'Aktive Trackings',
|
|
|
|
menu = 'tracking_menu',
|
|
|
|
options = options
|
|
|
|
})
|
|
|
|
|
|
|
|
lib.showContext('active_trackings')
|
|
|
|
end
|
|
|
|
|
|
|
|
function StopTracking()
|
|
|
|
local options = {}
|
|
|
|
|
|
|
|
if next(activeTrackings) == nil then
|
|
|
|
options[#options + 1] = {
|
|
|
|
title = 'Keine aktiven Trackings',
|
|
|
|
description = 'Derzeit werden keine Fahrzeuge getrackt',
|
|
|
|
icon = 'fas fa-info-circle'
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for plate, data in pairs(activeTrackings) do
|
|
|
|
options[#options + 1] = {
|
|
|
|
title = 'Stoppe: ' .. plate,
|
|
|
|
description = 'Tracking für dieses Fahrzeug beenden',
|
|
|
|
icon = 'fas fa-stop',
|
|
|
|
onSelect = function()
|
|
|
|
StopVehicleTracking(plate)
|
|
|
|
end
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
lib.registerContext({
|
|
|
|
id = 'stop_tracking',
|
|
|
|
title = 'Tracking beenden',
|
|
|
|
menu = 'tracking_menu',
|
|
|
|
options = options
|
|
|
|
})
|
|
|
|
|
|
|
|
lib.showContext('stop_tracking')
|
|
|
|
end
|
|
|
|
|
|
|
|
function StopVehicleTracking(plate)
|
|
|
|
if activeTrackings[plate] then
|
|
|
|
activeTrackings[plate] = nil
|
|
|
|
|
|
|
|
if trackingBlips[plate] then
|
|
|
|
RemoveBlip(trackingBlips[plate])
|
|
|
|
trackingBlips[plate] = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
TriggerServerEvent('tracking:server:stopTracking', plate)
|
|
|
|
QBCore.Functions.Notify('Tracking für ' .. plate .. ' beendet!', 'success')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Update Tracking Position
|
|
|
|
RegisterNetEvent('tracking:client:updatePosition', function(plate, coords)
|
|
|
|
if activeTrackings[plate] then
|
|
|
|
activeTrackings[plate].coords = coords
|
|
|
|
activeTrackings[plate].lastUpdate = GetGameTimer()
|
|
|
|
|
|
|
|
if trackingBlips[plate] then
|
|
|
|
SetBlipCoords(trackingBlips[plate], coords.x, coords.y, coords.z)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Cleanup beim Disconnect
|
|
|
|
AddEventHandler('onResourceStop', function(resourceName)
|
|
|
|
if GetCurrentResourceName() == resourceName then
|
|
|
|
for plate, blip in pairs(trackingBlips) do
|
|
|
|
RemoveBlip(blip)
|
|
|
|
end
|
2025-08-05 09:48:15 +02:00
|
|
|
|
|
|
|
-- Hide DrawText if active when resource stops
|
|
|
|
if inTrackingZone then
|
|
|
|
exports['qb-core']:HideText()
|
|
|
|
end
|
2025-08-05 00:18:35 +02:00
|
|
|
end
|
|
|
|
end)
|