diff --git a/resources/[carscripts]/qb-vehicle-tracker/client/client.lua b/resources/[carscripts]/qb-vehicle-tracker/client/client.lua index 877a7e189..b7cf8c03a 100644 --- a/resources/[carscripts]/qb-vehicle-tracker/client/client.lua +++ b/resources/[carscripts]/qb-vehicle-tracker/client/client.lua @@ -29,28 +29,43 @@ local function playSound(audioName, audioDict) end -- Events -RegisterNetEvent('qb_vehicle_tracker:client:manageTracker', function(serialNumber) - lib.registerContext({ - id = 'vt_menu', - title = locale('vt_menu_header'), - options = { - { - title = locale('vt_menu_check_location'), +RegisterNetEvent('qb_vehicle_tracker:client:showTrackerMenu', function(citizenid) + lib.callback('qb_vehicle_tracker:getPlayerTrackers', false, function(trackers) + if not trackers or #trackers == 0 then + uiNotify(locale('vt_no_trackers_found') or "No trackers found", 'error') + return + end + + local options = {} + for _, tracker in ipairs(trackers) do + table.insert(options, { + title = (locale('vt_vehicle_plate') or "Vehicle Plate") .. ': ' .. tracker.vehiclePlate, + description = (locale('vt_serial_number') or "Serial Number") .. ': ' .. tracker.serialNumber, event = 'qb_vehicle_tracker:client:locateTracker', - icon = 'eye', - args = serialNumber - } - } - }) - - if uiProgressBar(2000, locale('vt_pb_connecting'), { - dict = 'amb@code_human_in_bus_passenger_idles@female@tablet@base', - clip = 'base' - }, { - model = `prop_cs_tablet`, - pos = vec3(0.03, 0.002, -0.0), - rot = vec3(10.0, 160.0, 0.0) - }) then lib.showContext('vt_menu') else uiNotify(locale('vt_pb_cancelled'), 'error') end + icon = 'car', + args = tracker.serialNumber + }) + end + + lib.registerContext({ + id = 'vt_menu', + title = locale('vt_menu_header') or "Vehicle Tracker", + options = options + }) + + if uiProgressBar(2000, locale('vt_pb_connecting') or "Connecting to tracker network...", { + dict = 'amb@code_human_in_bus_passenger_idles@female@tablet@base', + clip = 'base' + }, { + model = `prop_cs_tablet`, + pos = vec3(0.03, 0.002, -0.0), + rot = vec3(10.0, 160.0, 0.0) + }) then + lib.showContext('vt_menu') + else + uiNotify(locale('vt_pb_cancelled') or "Cancelled", 'error') + end + end, citizenid) end) RegisterNetEvent('qb_vehicle_tracker:client:scanTracker', function(slot) @@ -182,4 +197,4 @@ CreateThread(function() end end end -end) \ No newline at end of file +end) diff --git a/resources/[carscripts]/qb-vehicle-tracker/locales/en.json b/resources/[carscripts]/qb-vehicle-tracker/locales/en.json index 43eebc9a7..07194471e 100644 --- a/resources/[carscripts]/qb-vehicle-tracker/locales/en.json +++ b/resources/[carscripts]/qb-vehicle-tracker/locales/en.json @@ -15,5 +15,8 @@ "vt_pb_removing": "Removing GPS Tracker...", "vt_pb_cancelled": "Cancelled", "vt_alert_title": "GPS Tracker Found!", - "vt_alert_description": "You have found a GPS Tracker! Do you want to remove it?" + "vt_alert_description": "You have found a GPS Tracker! Do you want to remove it?", + "vt_no_trackers_found": "You don't have any active trackers", + "vt_vehicle_plate": "Vehicle Plate", + "vt_serial_number": "Serial Number" } \ No newline at end of file diff --git a/resources/[carscripts]/qb-vehicle-tracker/server/db.lua b/resources/[carscripts]/qb-vehicle-tracker/server/db.lua index e08ec551a..da5e996f8 100644 --- a/resources/[carscripts]/qb-vehicle-tracker/server/db.lua +++ b/resources/[carscripts]/qb-vehicle-tracker/server/db.lua @@ -4,8 +4,9 @@ function db.deleteOldTrackers() return MySQL.query.await('DELETE FROM `vehicle_trackers` WHERE startedAt < (NOW() - INTERVAL 7 DAY)') end -function db.addTracker(serialNumber, vehiclePlate) - return MySQL.prepare.await('INSERT INTO `vehicle_trackers` (`serialNumber`, `vehiclePlate`) VALUES (?, ?)', { serialNumber, vehiclePlate }) +function db.addTracker(serialNumber, vehiclePlate, owner) + return MySQL.prepare.await('INSERT INTO `vehicle_trackers` (`serialNumber`, `vehiclePlate`, `owner`) VALUES (?, ?, ?)', + { serialNumber, vehiclePlate, owner }) end function db.deleteTracker(vehiclePlate) @@ -20,4 +21,8 @@ function db.isTracked(vehiclePlate) return MySQL.scalar.await('SELECT `serialNumber` FROM `vehicle_trackers` WHERE `vehiclePlate` = ? LIMIT 1', { vehiclePlate }) end -return db \ No newline at end of file +function db.getPlayerTrackers(owner) + return MySQL.query.await('SELECT `serialNumber`, `vehiclePlate` FROM `vehicle_trackers` WHERE `owner` = ?', { owner }) +end + +return db diff --git a/resources/[carscripts]/qb-vehicle-tracker/server/server.lua b/resources/[carscripts]/qb-vehicle-tracker/server/server.lua index 8faa014a7..f6d8cb7fd 100644 --- a/resources/[carscripts]/qb-vehicle-tracker/server/server.lua +++ b/resources/[carscripts]/qb-vehicle-tracker/server/server.lua @@ -1,16 +1,71 @@ local QBCore = exports['qb-core']:GetCoreObject() local config = require 'config' -local utils = require 'server.utils' -local db = require 'server.db' + +-- Database functions +local function deleteOldTrackers() + return MySQL.query.await('DELETE FROM `vehicle_trackers` WHERE startedAt < (NOW() - INTERVAL 7 DAY)') +end + +local function addTracker(serialNumber, vehiclePlate, owner) + return MySQL.prepare.await('INSERT INTO `vehicle_trackers` (`serialNumber`, `vehiclePlate`, `owner`) VALUES (?, ?, ?)', + { serialNumber, vehiclePlate, owner }) +end + +local function deleteTracker(vehiclePlate) + return MySQL.prepare.await('DELETE FROM `vehicle_trackers` WHERE `vehiclePlate` = ?', { vehiclePlate }) +end + +local function getTracker(serialNumber) + return MySQL.single.await('SELECT `serialNumber`, `vehiclePlate` FROM `vehicle_trackers` WHERE `serialNumber` = ? LIMIT 1', { serialNumber }) +end + +local function isTracked(vehiclePlate) + return MySQL.scalar.await('SELECT `serialNumber` FROM `vehicle_trackers` WHERE `vehiclePlate` = ? LIMIT 1', { vehiclePlate }) +end + +local function getPlayerTrackers(owner) + return MySQL.query.await('SELECT `serialNumber`, `vehiclePlate` FROM `vehicle_trackers` WHERE `owner` = ?', { owner }) +end + +-- Utility functions +local function getRandomSerialNumber() + return lib.string.random('...........') +end + +local function trim(plate) + return (plate:gsub("^%s*(.-)%s*$", "%1")) +end + +local function getVehicleNetworkIdByPlate(vehiclePlate) + local vehicles = GetAllVehicles() + + for _, vehicle in ipairs(vehicles) do + if trim(GetVehicleNumberPlateText(vehicle)) == trim(vehiclePlate) then + return NetworkGetNetworkIdFromEntity(vehicle) + end + end + + return nil +end + +local function isPlayerNearVehicle(playerCoords, vehiclePlate) + local vehicle = lib.getClosestVehicle(playerCoords, 3.0, true) + + if not vehicle or not DoesEntityExist(vehicle) or GetVehicleNumberPlateText(vehicle) ~= vehiclePlate then + return false + end + + return true +end -- QB Usable Items QBCore.Functions.CreateUseableItem(config.trackerItem, function(source, item) - TriggerClientEvent('qb_vehicle_tracker:client:placeTracker', source, item.slot, utils.getRandomSerialNumber()) + TriggerClientEvent('qb_vehicle_tracker:client:placeTracker', source, item.slot, getRandomSerialNumber()) end) QBCore.Functions.CreateUseableItem(config.trackerTabletItem, function(source, item) - local serialNumber = item.info and item.info.serialNumber or item.metadata.serialNumber - TriggerClientEvent('qb_vehicle_tracker:client:manageTracker', source, serialNumber) + local Player = QBCore.Functions.GetPlayer(source) + TriggerClientEvent('qb_vehicle_tracker:client:showTrackerMenu', source, Player.PlayerData.citizenid) end) QBCore.Functions.CreateUseableItem(config.trackerScannerItem, function(source, item) @@ -19,8 +74,8 @@ end) -- Event Handler AddEventHandler('onResourceStart', function(resourceName) - if cache.resource == resourceName then - db.deleteOldTrackers() + if GetCurrentResourceName() == resourceName then + deleteOldTrackers() end end) @@ -28,10 +83,10 @@ end) lib.callback.register('qb_vehicle_tracker:getTrackedVehicleBySerial', function(_, serialNumber) if type(serialNumber) ~= "string" or string.len(serialNumber) < 11 then return end - local tracker = db.getTracker(serialNumber) + local tracker = getTracker(serialNumber) if not tracker then return end - local vehicleNetworkID = utils.getVehicleNetworkIdByPlate(tracker.vehiclePlate) + local vehicleNetworkID = getVehicleNetworkIdByPlate(tracker.vehiclePlate) if not vehicleNetworkID then return end local vehicleEntity = NetworkGetEntityFromNetworkId(vehicleNetworkID) @@ -43,33 +98,32 @@ lib.callback.register('qb_vehicle_tracker:getTrackedVehicleBySerial', function(_ end) lib.callback.register('qb_vehicle_tracker:isVehicleTracked', function(source, vehiclePlate) - if type(vehiclePlate) ~= "string" or not utils.isPlayerNearVehicle(GetEntityCoords(GetPlayerPed(source)), vehiclePlate) then + if type(vehiclePlate) ~= "string" or not isPlayerNearVehicle(GetEntityCoords(GetPlayerPed(source)), vehiclePlate) then return false end - return db.isTracked(utils.trim(vehiclePlate)) + return isTracked(trim(vehiclePlate)) end) lib.callback.register('qb_vehicle_tracker:placeTracker', function(source, vehiclePlate, slot, serialNumber) if type(vehiclePlate) ~= "string" or type(serialNumber) ~= "string" or string.len(serialNumber) < 11 then return false end - if not utils.isPlayerNearVehicle(GetEntityCoords(GetPlayerPed(source)), vehiclePlate) then return false end - if not db.addTracker(serialNumber, utils.trim(vehiclePlate)) then return false end - + if not isPlayerNearVehicle(GetEntityCoords(GetPlayerPed(source)), vehiclePlate) then return false end + local Player = QBCore.Functions.GetPlayer(source) - if Player.Functions.AddItem(config.trackerTabletItem, 1, false, { plate = utils.trim(vehiclePlate), serialNumber = serialNumber }) then - Player.Functions.RemoveItem(config.trackerItem, 1, slot) - TriggerClientEvent('inventory:client:ItemBox', source, QBCore.Shared.Items[config.trackerTabletItem], 'add') - end + if not addTracker(serialNumber, trim(vehiclePlate), Player.PlayerData.citizenid) then return false end + + Player.Functions.RemoveItem(config.trackerItem, 1, slot) + TriggerClientEvent('inventory:client:ItemBox', source, QBCore.Shared.Items[config.trackerItem], 'remove') return true end) lib.callback.register('qb_vehicle_tracker:removeTracker', function(source, vehiclePlate, slot) - if type(vehiclePlate) ~= "string" or not utils.isPlayerNearVehicle(GetEntityCoords(GetPlayerPed(source)), vehiclePlate) then + if type(vehiclePlate) ~= "string" or not isPlayerNearVehicle(GetEntityCoords(GetPlayerPed(source)), vehiclePlate) then return false end - if not db.deleteTracker(utils.trim(vehiclePlate)) then return false end + if not deleteTracker(trim(vehiclePlate)) then return false end local Player = QBCore.Functions.GetPlayer(source) if Player.Functions.RemoveItem(config.trackerScannerItem, 1, slot) then @@ -77,4 +131,11 @@ lib.callback.register('qb_vehicle_tracker:removeTracker', function(source, vehic end return true -end) \ No newline at end of file +end) + +lib.callback.register('qb_vehicle_tracker:getPlayerTrackers', function(source, citizenid) + local Player = QBCore.Functions.GetPlayer(source) + if Player.PlayerData.citizenid ~= citizenid then return {} end + + return getPlayerTrackers(citizenid) +end) diff --git a/resources/[carscripts]/qb-vehicle-tracker/sql/vehicle_trackers.sql b/resources/[carscripts]/qb-vehicle-tracker/sql/vehicle_trackers.sql index d4019ca23..06036dd22 100644 --- a/resources/[carscripts]/qb-vehicle-tracker/sql/vehicle_trackers.sql +++ b/resources/[carscripts]/qb-vehicle-tracker/sql/vehicle_trackers.sql @@ -1,7 +1,8 @@ CREATE TABLE IF NOT EXISTS `vehicle_trackers` ( `serialNumber` varchar(11) NOT NULL, `vehiclePlate` varchar(11) NOT NULL, + `owner` varchar(50) NULL, `startedAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY `serialNumber` (`serialNumber`), KEY `vehiclePlate` (`vehiclePlate`) -); \ No newline at end of file +);