forked from Simnation/Main
408 lines
16 KiB
Lua
408 lines
16 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)
|
|
local player = QBCore.Functions.GetPlayerByCitizenId(citizenid)
|
|
if player then
|
|
-- Verwende MrNewbVehicleKeys Export
|
|
exports.MrNewbVehicleKeys:GiveKeysByPlate(player.PlayerData.source, plate)
|
|
print("[VehicleRental] Schlüssel für Mietfahrzeug hinzugefügt: " .. plate .. " für Spieler " .. citizenid)
|
|
else
|
|
-- Fallback für offline Spieler - Schlüssel werden beim nächsten Login hinzugefügt
|
|
print("[VehicleRental] Spieler offline, Schlüssel wird beim nächsten Login hinzugefügt: " .. plate)
|
|
end
|
|
end
|
|
|
|
-- Entferne einen Schlüssel für ein Mietfahrzeug
|
|
function RemoveRentalKey(citizenid, plate, model)
|
|
local player = QBCore.Functions.GetPlayerByCitizenId(citizenid)
|
|
if player then
|
|
-- Verwende MrNewbVehicleKeys Export
|
|
exports.MrNewbVehicleKeys:RemoveKeysByPlate(player.PlayerData.source, plate)
|
|
print("[VehicleRental] Schlüssel für Mietfahrzeug entfernt: " .. plate .. " für Spieler " .. citizenid)
|
|
else
|
|
print("[VehicleRental] Kein Spieler gefunden zum Entfernen des Schlüssels: " .. plate .. " für Spieler " .. citizenid)
|
|
end
|
|
end
|
|
|
|
-- Prüfe, ob ein Spieler Schlüssel für ein Fahrzeug hat
|
|
function HasRentalKey(source, plate)
|
|
return exports.MrNewbVehicleKeys:HasKeysByPlate(source, plate)
|
|
end
|
|
|
|
-- Setze den Sperrstatus eines Fahrzeugs
|
|
function SetRentalVehicleLock(netId, lockStatus)
|
|
exports.MrNewbVehicleKeys:SetVehicleLock(netId, lockStatus)
|
|
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("[VehicleRental] 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
|
|
local player = QBCore.Functions.GetPlayerByCitizenId(rental.citizenid)
|
|
if player then
|
|
-- Verwende MrNewbVehicleKeys Export
|
|
exports.MrNewbVehicleKeys:GiveKeysByPlate(player.PlayerData.source, rental.vehicle_plate)
|
|
print("[VehicleRental] Schlüssel für Mietfahrzeug wiederhergestellt: " .. rental.vehicle_plate)
|
|
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 mit MrNewbVehicleKeys hinzu
|
|
exports.MrNewbVehicleKeys:GiveKeysByPlate(source, data.plate)
|
|
|
|
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 mit MrNewbVehicleKeys
|
|
exports.MrNewbVehicleKeys:RemoveKeysByPlate(source, 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
|
|
local player = QBCore.Functions.GetPlayerByCitizenId(rental.citizenid)
|
|
if player then
|
|
exports.MrNewbVehicleKeys:RemoveKeysByPlate(player.PlayerData.source, plate)
|
|
end
|
|
|
|
-- 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
|
|
-- Direkt MrNewbVehicleKeys Export verwenden
|
|
exports.MrNewbVehicleKeys:GiveKeysByPlate(src, rental.vehicle_plate)
|
|
print("[VehicleRental] Schlüssel für Mietfahrzeug wiederhergestellt: " .. rental.vehicle_plate)
|
|
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
|
|
-- Direkt MrNewbVehicleKeys Export verwenden
|
|
exports.MrNewbVehicleKeys:GiveKeysByPlate(src, rental.vehicle_plate)
|
|
print("[VehicleRental] Schlüssel für Mietfahrzeug wiederhergestellt: " .. rental.vehicle_plate)
|
|
end
|
|
end
|
|
end)
|
|
end)
|
|
|
|
-- Funktion zum Löschen aller Mietfahrzeuge eines Spielers (z.B. bei Charakter-Löschung)
|
|
exports('DeleteAllPlayerRentals', function(citizenid)
|
|
if not citizenid then return false end
|
|
|
|
-- Hole alle aktiven Mietverhältnisse des Spielers
|
|
MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE citizenid = ? AND returned = FALSE', {
|
|
citizenid
|
|
}, function(rentals)
|
|
if rentals and #rentals > 0 then
|
|
local player = QBCore.Functions.GetPlayerByCitizenId(citizenid)
|
|
|
|
for _, rental in ipairs(rentals) do
|
|
-- Markiere als zurückgegeben
|
|
MySQL.Async.execute('UPDATE vehicle_rentals SET returned = TRUE WHERE id = ?', {
|
|
rental.id
|
|
})
|
|
|
|
-- Entferne den Schlüssel mit MrNewbVehicleKeys wenn Spieler online ist
|
|
if player then
|
|
exports.MrNewbVehicleKeys:RemoveKeysByPlate(player.PlayerData.source, rental.vehicle_plate)
|
|
end
|
|
|
|
-- Entferne aus dem Cache
|
|
activeRentals[rental.vehicle_plate] = nil
|
|
|
|
-- Benachrichtige alle Clients
|
|
TriggerClientEvent('vehiclerental:client:vehicleReturned', -1, rental.vehicle_plate)
|
|
end
|
|
|
|
print("[VehicleRental] Deleted all rental vehicles for player: " .. citizenid)
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end)
|
|
end)
|
|
|