diff --git a/resources/[carscripts]/nordi_tracking/client.lua b/resources/[carscripts]/nordi_tracking/client.lua new file mode 100644 index 000000000..b55303c44 --- /dev/null +++ b/resources/[carscripts]/nordi_tracking/client.lua @@ -0,0 +1,225 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +-- Tracking Menu öffnen +RegisterCommand('tracking', 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) + +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 + +local activeTrackings = {} +local trackingBlips = {} + +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, + lastUpdate = GetGameTimer() + } + + -- 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 + + -- 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, + description = 'Entfernung: ' .. math.floor(distance) .. 'm | Letztes Update: ' .. math.floor((GetGameTimer() - data.lastUpdate) / 1000) .. 's', + 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 + end +end) diff --git a/resources/[carscripts]/nordi_tracking/fxmanifest.lua b/resources/[carscripts]/nordi_tracking/fxmanifest.lua new file mode 100644 index 000000000..994cc4272 --- /dev/null +++ b/resources/[carscripts]/nordi_tracking/fxmanifest.lua @@ -0,0 +1,28 @@ +fx_version 'cerulean' +game 'gta5' + +author 'YourName' +description 'Vehicle Tracking System for QBCore' +version '1.0.0' + +shared_scripts { + '@ox_lib/init.lua', + '@qb-core/shared/locale.lua' +} + +client_scripts { + 'client.lua' +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'server.lua' +} + +dependencies { + 'qb-core', + 'ox_lib', + 'oxmysql' +} + +lua54 'yes' diff --git a/resources/[carscripts]/nordi_tracking/server.lua b/resources/[carscripts]/nordi_tracking/server.lua new file mode 100644 index 000000000..3c66dd404 --- /dev/null +++ b/resources/[carscripts]/nordi_tracking/server.lua @@ -0,0 +1,108 @@ +local QBCore = exports['qb-core']:GetCoreObject() + +local activeTrackings = {} + +-- Callback für Fahrzeug Tracking +QBCore.Functions.CreateCallback('tracking:server:trackVehicle', function(source, cb, plate) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + + if not Player then + cb(false, 'Spieler nicht gefunden!') + return + end + + -- Überprüfe Job Berechtigung + local allowedJobs = {'police', 'ambulance', 'mechanic'} + local hasPermission = false + + for _, job in pairs(allowedJobs) do + if Player.PlayerData.job.name == job then + hasPermission = true + break + end + end + + if not hasPermission then + cb(false, 'Keine Berechtigung!') + return + end + + -- Suche Fahrzeug in der Datenbank + MySQL.Async.fetchAll('SELECT * FROM player_vehicles WHERE plate = ?', {plate}, function(result) + if result[1] then + -- Suche das Fahrzeug in der Welt + local vehicles = GetAllVehicles() + local foundVehicle = nil + local vehicleCoords = nil + + for _, vehicle in pairs(vehicles) do + if DoesEntityExist(vehicle) then + local vehiclePlate = GetVehicleNumberPlateText(vehicle) + if vehiclePlate and string.gsub(vehiclePlate, '^%s*(.-)%s*$', '%1') == plate then + foundVehicle = vehicle + vehicleCoords = GetEntityCoords(vehicle) + break + end + end + end + + if foundVehicle and vehicleCoords then + activeTrackings[plate] = { + vehicle = foundVehicle, + coords = {x = vehicleCoords.x, y = vehicleCoords.y, z = vehicleCoords.z}, + tracker = src + } + + cb(true, 'Fahrzeug gefunden!', { + vehicle = foundVehicle, + coords = {x = vehicleCoords.x, y = vehicleCoords.y, z = vehicleCoords.z} + }) + else + cb(false, 'Fahrzeug nicht in der Welt gefunden!') + end + else + cb(false, 'Fahrzeug mit diesem Kennzeichen existiert nicht!') + end + end) +end) + +-- Update Fahrzeug Position +RegisterNetEvent('tracking:server:updateVehicleLocation', function(plate) + local src = source + + if activeTrackings[plate] and activeTrackings[plate].tracker == src then + local vehicle = activeTrackings[plate].vehicle + + if DoesEntityExist(vehicle) then + local coords = GetEntityCoords(vehicle) + activeTrackings[plate].coords = {x = coords.x, y = coords.y, z = coords.z} + + TriggerClientEvent('tracking:client:updatePosition', src, plate, {x = coords.x, y = coords.y, z = coords.z}) + else + -- Fahrzeug existiert nicht mehr + activeTrackings[plate] = nil + TriggerClientEvent('QBCore:Notify', src, 'Tracking verloren - Fahrzeug nicht mehr verfügbar!', 'error') + end + end +end) + +-- Stoppe Tracking +RegisterNetEvent('tracking:server:stopTracking', function(plate) + local src = source + + if activeTrackings[plate] and activeTrackings[plate].tracker == src then + activeTrackings[plate] = nil + end +end) + +-- Cleanup bei Disconnect +AddEventHandler('playerDropped', function() + local src = source + + for plate, data in pairs(activeTrackings) do + if data.tracker == src then + activeTrackings[plate] = nil + end + end +end)