374 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			374 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local QBCore = exports['qb-core']:GetCoreObject()
 | |
| local activeRentals = {}
 | |
| 
 | |
| -- Füge einen Schlüssel für ein Mietfahrzeug hinzu
 | |
| function AddRentalKey(citizenid, plate, model)
 | |
|     MySQL.Async.execute('INSERT INTO vehicle_keys (owner, plate, count) VALUES (?, ?, ?)', {
 | |
|         citizenid,
 | |
|         plate,
 | |
|         1
 | |
|     }, function(rowsChanged)
 | |
|         if rowsChanged > 0 then
 | |
|             print("Schlüssel für Mietfahrzeug hinzugefügt: " .. plate .. " für Spieler " .. citizenid)
 | |
|         end
 | |
|     end)
 | |
| end
 | |
| 
 | |
| -- Entferne einen Schlüssel für ein Mietfahrzeug
 | |
| function RemoveRentalKey(citizenid, plate)
 | |
|     MySQL.Async.execute('DELETE FROM vehicle_keys WHERE owner = ? AND plate = ?', {
 | |
|         citizenid,
 | |
|         plate
 | |
|     }, function(rowsChanged)
 | |
|         if rowsChanged > 0 then
 | |
|             print("Schlüssel für Mietfahrzeug entfernt: " .. plate .. " für Spieler " .. citizenid)
 | |
|         end
 | |
|     end)
 | |
| end
 | |
| 
 | |
| -- Lade alle aktiven Mietfahrzeuge beim Serverstart
 | |
| Citizen.CreateThread(function()
 | |
|     Wait(5000) -- Warte, bis die Datenbank bereit ist
 | |
|     
 | |
|     MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE returned = FALSE', {}, function(results)
 | |
|         if results and #results > 0 then
 | |
|             print("Lade " .. #results .. " aktive Mietfahrzeuge...")
 | |
|             
 | |
|             for _, rental in ipairs(results) do
 | |
|                 activeRentals[rental.vehicle_plate] = rental
 | |
|                 
 | |
|                 -- Stelle sicher, dass für jedes Mietfahrzeug ein Schlüssel existiert
 | |
|                 MySQL.Async.fetchAll('SELECT * FROM vehicle_keys WHERE owner = ? AND plate = ?', {
 | |
|                     rental.citizenid,
 | |
|                     rental.vehicle_plate
 | |
|                 }, function(keyResults)
 | |
|                     if not keyResults or #keyResults == 0 then
 | |
|                         -- Füge einen Schlüssel hinzu, wenn keiner existiert
 | |
|                         AddRentalKey(rental.citizenid, rental.vehicle_plate, rental.vehicle_model)
 | |
|                     end
 | |
|                 end)
 | |
|             end
 | |
|             
 | |
|             -- Benachrichtige alle Clients, dass sie die Fahrzeuge spawnen sollen
 | |
|             TriggerClientEvent('vehiclerental:client:loadRentals', -1, results)
 | |
|         end
 | |
|     end)
 | |
| end)
 | |
| 
 | |
| -- Aktualisiere die Position eines Mietfahrzeugs
 | |
| RegisterServerEvent('vehiclerental:server:updatePosition')
 | |
| AddEventHandler('vehiclerental:server:updatePosition', function(plate, position, rotation)
 | |
|     if not plate or not position then return end
 | |
|     
 | |
|     -- Aktualisiere in der Datenbank
 | |
|     MySQL.Async.execute('UPDATE vehicle_rentals SET posX = ?, posY = ?, posZ = ?, rotX = ?, rotY = ?, rotZ = ?, lastUpdated = CURRENT_TIMESTAMP WHERE vehicle_plate = ? AND returned = FALSE', {
 | |
|         position.x, position.y, position.z,
 | |
|         rotation.x, rotation.y, rotation.z,
 | |
|         plate
 | |
|     })
 | |
|     
 | |
|     -- Aktualisiere im Cache
 | |
|     if activeRentals[plate] then
 | |
|         activeRentals[plate].posX = position.x
 | |
|         activeRentals[plate].posY = position.y
 | |
|         activeRentals[plate].posZ = position.z
 | |
|         activeRentals[plate].rotX = rotation.x
 | |
|         activeRentals[plate].rotY = rotation.y
 | |
|         activeRentals[plate].rotZ = rotation.z
 | |
|     end
 | |
| end)
 | |
| 
 | |
| -- Fahrzeug mieten
 | |
| QBCore.Functions.CreateCallback('vehiclerental:server:rentVehicle', function(source, cb, data)
 | |
|     local Player = QBCore.Functions.GetPlayer(source)
 | |
|     if not Player then return cb(false) end
 | |
| 
 | |
|     local totalCost = data.pricePerHour * data.hours
 | |
|     local currentTime = os.time()
 | |
|     local endTime = currentTime + (data.hours * 3600)
 | |
| 
 | |
|     -- Zahlung prüfen und abziehen
 | |
|     local paymentSuccess = false
 | |
|     if Config.UseOkokBanking then
 | |
|         local bankMoney = exports['okokBanking']:GetAccount(Player.PlayerData.citizenid)
 | |
|         if bankMoney and bankMoney >= totalCost then
 | |
|             exports['okokBanking']:RemoveMoney(Player.PlayerData.citizenid, totalCost)
 | |
|             paymentSuccess = true
 | |
|         end
 | |
|     else
 | |
|         if Player.Functions.RemoveMoney('cash', totalCost) then
 | |
|             paymentSuccess = true
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     if not paymentSuccess then
 | |
|         TriggerClientEvent('QBCore:Notify', source, 'Nicht genug Geld!', 'error')
 | |
|         return cb(false)
 | |
|     end
 | |
| 
 | |
|     -- Fahrzeug in Datenbank eintragen
 | |
|     MySQL.Async.insert('INSERT INTO vehicle_rentals (citizenid, vehicle_model, vehicle_plate, rental_location, start_time, end_time, price_per_hour) VALUES (?, ?, ?, ?, ?, ?, ?)', {
 | |
|         Player.PlayerData.citizenid,
 | |
|         data.vehicleModel,
 | |
|         data.plate,
 | |
|         data.locationId,
 | |
|         currentTime,
 | |
|         endTime,
 | |
|         data.pricePerHour
 | |
|     }, function(rentalId)
 | |
|         -- Füge das Fahrzeug zum aktiven Cache hinzu
 | |
|         activeRentals[data.plate] = {
 | |
|             id = rentalId,
 | |
|             citizenid = Player.PlayerData.citizenid,
 | |
|             vehicle_model = data.vehicleModel,
 | |
|             vehicle_plate = data.plate,
 | |
|             rental_location = data.locationId,
 | |
|             start_time = currentTime,
 | |
|             end_time = endTime,
 | |
|             price_per_hour = data.pricePerHour,
 | |
|             returned = false
 | |
|         }
 | |
|         
 | |
|         -- Füge einen Schlüssel für das Mietfahrzeug hinzu
 | |
|         AddRentalKey(Player.PlayerData.citizenid, data.plate, data.vehicleModel)
 | |
|         
 | |
|         TriggerClientEvent('QBCore:Notify', source, 'Fahrzeug erfolgreich gemietet für $' .. totalCost, 'success')
 | |
|         cb(true)
 | |
|     end)
 | |
| end)
 | |
| 
 | |
| -- Fahrzeug zurückgeben
 | |
| QBCore.Functions.CreateCallback('vehiclerental:server:returnVehicle', function(source, cb, plate)
 | |
|     local Player = QBCore.Functions.GetPlayer(source)
 | |
|     if not Player then return cb(false) end
 | |
| 
 | |
|     MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE citizenid = ? AND vehicle_plate = ? AND returned = FALSE', {
 | |
|         Player.PlayerData.citizenid,
 | |
|         plate
 | |
|     }, function(result)
 | |
|         if not result[1] then
 | |
|             TriggerClientEvent('QBCore:Notify', source, 'Kein aktives Mietverhältnis für dieses Fahrzeug gefunden!', 'error')
 | |
|             return cb(false)
 | |
|         end
 | |
| 
 | |
|         local rental = result[1]
 | |
|         local currentTime = os.time()
 | |
|         local penalty = 0
 | |
| 
 | |
|         -- Strafe berechnen wenn verspätet
 | |
|         if currentTime > rental.end_time then
 | |
|             local hoursLate = math.ceil((currentTime - rental.end_time) / 3600)
 | |
|             penalty = hoursLate * Config.PenaltyPerHour
 | |
|         end
 | |
| 
 | |
|         -- Strafe abziehen falls vorhanden
 | |
|         if penalty > 0 then
 | |
|             local penaltyPaid = false
 | |
|             if Config.UseOkokBanking then
 | |
|                 local bankMoney = exports['okokBanking']:GetAccount(Player.PlayerData.citizenid)
 | |
|                 if bankMoney and bankMoney >= penalty then
 | |
|                     exports['okokBanking']:RemoveMoney(Player.PlayerData.citizenid, penalty)
 | |
|                     penaltyPaid = true
 | |
|                 end
 | |
|             else
 | |
|                 if Player.Functions.RemoveMoney('cash', penalty) then
 | |
|                     penaltyPaid = true
 | |
|                 end
 | |
|             end
 | |
| 
 | |
|             if penaltyPaid then
 | |
|                 TriggerClientEvent('QBCore:Notify', source, 'Verspätungsstrafe von $' .. penalty .. ' wurde abgezogen!', 'error')
 | |
|             else
 | |
|                 TriggerClientEvent('QBCore:Notify', source, 'Nicht genug Geld für Verspätungsstrafe!', 'error')
 | |
|                 return cb(false)
 | |
|             end
 | |
|         end
 | |
| 
 | |
|         -- Mietverhältnis als zurückgegeben markieren
 | |
|         MySQL.Async.execute('UPDATE vehicle_rentals SET returned = TRUE, penalty_paid = ? WHERE id = ?', {
 | |
|             penalty > 0,
 | |
|             rental.id
 | |
|         })
 | |
|         
 | |
|         -- Aus dem aktiven Cache entfernen
 | |
|         activeRentals[plate] = nil
 | |
|         
 | |
|         -- Entferne den Schlüssel für das Mietfahrzeug
 | |
|         RemoveRentalKey(Player.PlayerData.citizenid, plate)
 | |
|         
 | |
|         -- Benachrichtige alle Clients, dass das Fahrzeug zurückgegeben wurde
 | |
|         TriggerClientEvent('vehiclerental:client:vehicleReturned', -1, plate)
 | |
| 
 | |
|         TriggerClientEvent('QBCore:Notify', source, 'Fahrzeug erfolgreich zurückgegeben!', 'success')
 | |
|         cb(true)
 | |
|     end)
 | |
| end)
 | |
| 
 | |
| -- Spieler Mietverhältnisse abrufen
 | |
| QBCore.Functions.CreateCallback('vehiclerental:server:getPlayerRentals', function(source, cb)
 | |
|     local Player = QBCore.Functions.GetPlayer(source)
 | |
|     if not Player then return cb(nil) end
 | |
| 
 | |
|     MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE citizenid = ? AND returned = FALSE', {
 | |
|         Player.PlayerData.citizenid
 | |
|     }, function(result)
 | |
|         if not result or #result == 0 then
 | |
|             return cb(nil)
 | |
|         end
 | |
| 
 | |
|         local currentTime = os.time()
 | |
|         for i = 1, #result do
 | |
|             -- Berechne verbleibende Zeit auf dem Server
 | |
|             result[i].timeLeft = result[i].end_time - currentTime
 | |
|             result[i].isOverdue = result[i].timeLeft < 0
 | |
|             
 | |
|             -- Formatiere die Zeit für die Anzeige
 | |
|             if result[i].isOverdue then
 | |
|                 local hoursOverdue = math.ceil(math.abs(result[i].timeLeft) / 3600)
 | |
|                 result[i].timeText = "(Überfällig um " .. hoursOverdue .. " Stunden)"
 | |
|             else
 | |
|                 local hoursLeft = math.floor(result[i].timeLeft / 3600)
 | |
|                 local minutesLeft = math.floor((result[i].timeLeft % 3600) / 60)
 | |
|                 result[i].timeText = "(" .. hoursLeft .. "h " .. minutesLeft .. "m verbleibend)"
 | |
|             end
 | |
|         end
 | |
| 
 | |
|         cb(result)
 | |
|     end)
 | |
| end)
 | |
| 
 | |
| -- Befehl für Mietzeit
 | |
| QBCore.Commands.Add('mietzeit', 'Zeige deine aktuelle Mietzeit an', {}, false, function(source, args)
 | |
|     local Player = QBCore.Functions.GetPlayer(source)
 | |
|     if not Player then return end
 | |
| 
 | |
|     MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE citizenid = ? AND returned = FALSE', {
 | |
|         Player.PlayerData.citizenid
 | |
|     }, function(result)
 | |
|         if not result or #result == 0 then
 | |
|             TriggerClientEvent('QBCore:Notify', source, 'Du hast keine aktiven Mietverhältnisse!', 'error')
 | |
|             return
 | |
|         end
 | |
| 
 | |
|         for i = 1, #result do
 | |
|             local rental = result[i]
 | |
|             local currentTime = os.time()
 | |
|             local timeLeft = rental.end_time - currentTime
 | |
|             local timeText = ""
 | |
|             
 | |
|             if timeLeft < 0 then
 | |
|                 local hoursOverdue = math.ceil(math.abs(timeLeft) / 3600)
 | |
|                 timeText = "Überfällig um " .. hoursOverdue .. " Stunden"
 | |
|                 TriggerClientEvent('QBCore:Notify', source, rental.vehicle_model .. " (" .. rental.vehicle_plate .. "): " .. timeText, 'error')
 | |
|             else
 | |
|                 local hoursLeft = math.floor(timeLeft / 3600)
 | |
|                 local minutesLeft = math.floor((timeLeft % 3600) / 60)
 | |
|                 timeText = hoursLeft .. "h " .. minutesLeft .. "m verbleibend"
 | |
|                 TriggerClientEvent('QBCore:Notify', source, rental.vehicle_model .. " (" .. rental.vehicle_plate .. "): " .. timeText, 'primary')
 | |
|             end
 | |
|         end
 | |
|     end)
 | |
| end)
 | |
| 
 | |
| -- Regelmäßige Überprüfung auf überfällige Fahrzeuge
 | |
| Citizen.CreateThread(function()
 | |
|     while true do
 | |
|         Citizen.Wait(60000) -- Überprüfe jede Minute
 | |
|         
 | |
|         local currentTime = os.time()
 | |
|         local overdueVehicles = {}
 | |
|         
 | |
|         -- Überprüfe alle aktiven Mietfahrzeuge
 | |
|         for plate, rental in pairs(activeRentals) do
 | |
|             if currentTime > rental.end_time + (Config.MaxOverdueHours * 3600) then
 | |
|                 -- Fahrzeug ist zu lange überfällig, markiere es als zurückgegeben
 | |
|                 MySQL.Async.execute('UPDATE vehicle_rentals SET returned = TRUE, penalty_paid = TRUE WHERE vehicle_plate = ? AND returned = FALSE', {
 | |
|                     plate
 | |
|                 })
 | |
|                 
 | |
|                 -- Entferne den Schlüssel für das Mietfahrzeug
 | |
|                 RemoveRentalKey(rental.citizenid, plate)
 | |
|                 
 | |
|                 -- Füge es zur Liste der zu entfernenden Fahrzeuge hinzu
 | |
|                 table.insert(overdueVehicles, plate)
 | |
|             end
 | |
|         end
 | |
|         
 | |
|         -- Entferne überfällige Fahrzeuge aus dem Cache
 | |
|         for _, plate in ipairs(overdueVehicles) do
 | |
|             activeRentals[plate] = nil
 | |
|             -- Benachrichtige alle Clients, dass das Fahrzeug entfernt werden soll
 | |
|             TriggerClientEvent('vehiclerental:client:vehicleReturned', -1, plate)
 | |
|         end
 | |
|     end
 | |
| end)
 | |
| 
 | |
| -- Spieler verbindet sich
 | |
| RegisterNetEvent('QBCore:Server:PlayerLoaded')
 | |
| AddEventHandler('QBCore:Server:PlayerLoaded', function()
 | |
|     local src = source
 | |
|     local Player = QBCore.Functions.GetPlayer(src)
 | |
|     if not Player then return end
 | |
|     
 | |
|     -- Sende dem Spieler seine aktiven Mietfahrzeuge
 | |
|     MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE citizenid = ? AND returned = FALSE', {
 | |
|         Player.PlayerData.citizenid
 | |
|     }, function(results)
 | |
|         if results and #results > 0 then
 | |
|             -- Stelle sicher, dass für jedes Mietfahrzeug ein Schlüssel existiert
 | |
|             for _, rental in ipairs(results) do
 | |
|                 -- Prüfe, ob bereits ein Schlüssel existiert
 | |
|                 MySQL.Async.fetchAll('SELECT * FROM vehicle_keys WHERE owner = ? AND plate = ?', {
 | |
|                     Player.PlayerData.citizenid,
 | |
|                     rental.vehicle_plate
 | |
|                 }, function(keyResults)
 | |
|                     if not keyResults or #keyResults == 0 then
 | |
|                         -- Füge einen Schlüssel hinzu, wenn keiner existiert
 | |
|                         AddRentalKey(Player.PlayerData.citizenid, rental.vehicle_plate, rental.vehicle_model)
 | |
|                     end
 | |
|                 end)
 | |
|             end
 | |
|             
 | |
|             TriggerClientEvent('vehiclerental:client:loadRentals', src, results)
 | |
|         end
 | |
|     end)
 | |
| end)
 | |
| 
 | |
| -- Exportiere Funktionen für andere Ressourcen
 | |
| exports('GetActiveRentals', function(citizenid)
 | |
|     local playerRentals = {}
 | |
|     for plate, rental in pairs(activeRentals) do
 | |
|         if rental.citizenid == citizenid then
 | |
|             table.insert(playerRentals, rental)
 | |
|         end
 | |
|     end
 | |
|     return playerRentals
 | |
| end)
 | |
| 
 | |
| -- Event für andere Ressourcen
 | |
| RegisterNetEvent('vehiclerental:server:checkRentalKeys')
 | |
| AddEventHandler('vehiclerental:server:checkRentalKeys', function()
 | |
|     local src = source
 | |
|     local Player = QBCore.Functions.GetPlayer(src)
 | |
|     if not Player then return end
 | |
|     
 | |
|     -- Hole alle aktiven Mietverhältnisse des Spielers
 | |
|     MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE citizenid = ? AND returned = FALSE', {
 | |
|         Player.PlayerData.citizenid
 | |
|     }, function(rentals)
 | |
|         if rentals and #rentals > 0 then
 | |
|             for _, rental in ipairs(rentals) do
 | |
|                 -- Prüfe, ob ein Schlüssel existiert
 | |
|                 MySQL.Async.fetchAll('SELECT * FROM vehicle_keys WHERE owner = ? AND plate = ?', {
 | |
|                     Player.PlayerData.citizenid,
 | |
|                     rental.vehicle_plate
 | |
|                 }, function(keyResults)
 | |
|                     if not keyResults or #keyResults == 0 then
 | |
|                         -- Füge einen Schlüssel hinzu, wenn keiner existiert
 | |
|                         AddRentalKey(Player.PlayerData.citizenid, rental.vehicle_plate, rental.vehicle_model)
 | |
|                     end
 | |
|                 end)
 | |
|             end
 | |
|         end
 | |
|     end)
 | |
| end)
 | 
