1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-07-26 03:22:23 +02:00
parent 19928f3c5f
commit 90ab2c2b27
3 changed files with 326 additions and 219 deletions

View file

@ -1,44 +1,64 @@
local QBCore = exports['qb-core']:GetCoreObject() local QBCore = exports['qb-core']:GetCoreObject()
local spawnedNPCs = {} local spawnedNPCs = {}
local currentRental = nil local activeRentalVehicles = {}
-- NPCs spawnen -- NPCs spawnen
CreateThread(function() CreateThread(function()
-- Warte kurz, bis die Welt geladen ist
Wait(2000)
for i = 1, #Config.RentalLocations do for i = 1, #Config.RentalLocations do
local location = Config.RentalLocations[i] local location = Config.RentalLocations[i]
local modelHash = GetHashKey(location.npc.model)
RequestModel(location.npc.model) -- Modell laden
while not HasModelLoaded(location.npc.model) do RequestModel(modelHash)
Wait(1) local timeout = 0
while not HasModelLoaded(modelHash) and timeout < 30 do
Wait(100)
timeout = timeout + 1
end end
local npc = CreatePed(4, location.npc.model, location.npc.coords.x, location.npc.coords.y, location.npc.coords.z - 1.0, location.npc.coords.w, false, true) if HasModelLoaded(modelHash) then
FreezeEntityPosition(npc, true) -- NPC erstellen
SetEntityInvincible(npc, true) local coords = location.npc.coords
SetBlockingOfNonTemporaryEvents(npc, true) local npc = CreatePed(4, modelHash, coords.x, coords.y, coords.z - 1.0, coords.w, false, false)
spawnedNPCs[location.id] = npc -- NPC-Eigenschaften setzen
FreezeEntityPosition(npc, true)
SetEntityInvincible(npc, true)
SetBlockingOfNonTemporaryEvents(npc, true)
SetPedDefaultComponentVariation(npc)
-- QB-Target für NPC -- NPC speichern
exports['qb-target']:AddTargetEntity(npc, { spawnedNPCs[location.id] = npc
options = {
{ -- Debug-Info
type = "client", print("NPC spawned at location: " .. location.name)
event = "vehiclerental:client:openMenu",
icon = "fas fa-car", -- QB-Target für NPC
label = "Fahrzeug mieten", exports['qb-target']:AddTargetEntity(npc, {
locationId = location.id options = {
{
type = "client",
event = "vehiclerental:client:openMenu",
icon = "fas fa-car",
label = "Fahrzeug mieten",
locationId = location.id
},
{
type = "client",
event = "vehiclerental:client:returnVehicle",
icon = "fas fa-car-side",
label = "Fahrzeug zurückgeben",
locationId = location.id
}
}, },
{ distance = 2.0
type = "client", })
event = "vehiclerental:client:returnVehicle", else
icon = "fas fa-car-side", print("Failed to load NPC model for location: " .. location.name)
label = "Fahrzeug zurückgeben", end
locationId = location.id
}
},
distance = 2.0
})
end end
end) end)
@ -130,12 +150,18 @@ function spawnRentalVehicle(model, spawnPoint, plate)
TriggerEvent("vehiclekeys:client:SetOwner", plate) TriggerEvent("vehiclekeys:client:SetOwner", plate)
SetModelAsNoLongerNeeded(model) SetModelAsNoLongerNeeded(model)
-- Registriere das Fahrzeug im Parking-System -- Speichere das Fahrzeug lokal
TriggerEvent('vehiclerental:client:vehicleRented', vehicle, plate) activeRentalVehicles[plate] = vehicle
-- Speichere die initiale Position
local pos = GetEntityCoords(vehicle)
local rot = GetEntityRotation(vehicle)
TriggerServerEvent('vehiclerental:server:updatePosition', plate, pos, rot)
print("Neues Mietfahrzeug erstellt: " .. plate)
end end
-- Fahrzeug zurückgeben
-- Fahrzeug zurückgeben (KORRIGIERT - ohne im Auto zu sitzen)
RegisterNetEvent('vehiclerental:client:returnVehicle', function(data) RegisterNetEvent('vehiclerental:client:returnVehicle', function(data)
-- Hole alle aktiven Mietverhältnisse des Spielers -- Hole alle aktiven Mietverhältnisse des Spielers
QBCore.Functions.TriggerCallback('vehiclerental:server:getPlayerRentals', function(rentals) QBCore.Functions.TriggerCallback('vehiclerental:server:getPlayerRentals', function(rentals)
@ -171,17 +197,33 @@ end)
-- Spezifisches Fahrzeug zurückgeben -- Spezifisches Fahrzeug zurückgeben
function returnSpecificVehicle(plate, locationId) function returnSpecificVehicle(plate, locationId)
-- Finde die Location-Daten
local location = nil
for i = 1, #Config.RentalLocations do
if Config.RentalLocations[i].id == locationId then
location = Config.RentalLocations[i]
break
end
end
if not location then
QBCore.Functions.Notify('Fehler beim Finden des Rückgabeorts!', 'error')
return
end
-- Definiere den Rückgabeort
local returnPoint = vector3(location.returnPoint.x, location.returnPoint.y, location.returnPoint.z)
-- Finde das Fahrzeug in der Nähe -- Finde das Fahrzeug in der Nähe
local playerPos = GetEntityCoords(PlayerPedId())
local vehicle = nil local vehicle = nil
local closestDistance = 50.0 -- Maximale Entfernung local closestDistance = 50.0 -- Maximale Suchentfernung
-- Suche nach dem Fahrzeug mit dem Kennzeichen -- Suche nach dem Fahrzeug mit dem Kennzeichen
for veh in EnumerateVehicles() do for veh in EnumerateVehicles() do
local vehPlate = GetVehicleNumberPlateText(veh) local vehPlate = GetVehicleNumberPlateText(veh)
if string.gsub(vehPlate, "%s+", "") == string.gsub(plate, "%s+", "") then if string.gsub(vehPlate, "%s+", "") == string.gsub(plate, "%s+", "") then
local vehPos = GetEntityCoords(veh) local vehPos = GetEntityCoords(veh)
local distance = #(playerPos - vehPos) local distance = #(returnPoint - vehPos)
if distance < closestDistance then if distance < closestDistance then
vehicle = veh vehicle = veh
@ -191,38 +233,137 @@ function returnSpecificVehicle(plate, locationId)
end end
if not vehicle then if not vehicle then
QBCore.Functions.Notify('Fahrzeug nicht in der Nähe gefunden! Bringe es zum Mietort zurück.', 'error') QBCore.Functions.Notify('Fahrzeug nicht in der Nähe des Rückgabeorts gefunden!', 'error')
return return
end end
-- Prüfe ob das Fahrzeug am richtigen Ort ist -- Prüfe ob das Fahrzeug nahe genug am Rückgabeort ist
local location = nil local vehPos = GetEntityCoords(vehicle)
for i = 1, #Config.RentalLocations do local distance = #(returnPoint - vehPos)
if Config.RentalLocations[i].id == locationId then
location = Config.RentalLocations[i]
break
end
end
if location then if distance > Config.MaxReturnDistance then
local returnPos = vector3(location.returnPoint.x, location.returnPoint.y, location.returnPoint.z) QBCore.Functions.Notify('Das Fahrzeug muss näher am Rückgabeort sein! (Max. ' .. Config.MaxReturnDistance .. 'm)', 'error')
local vehPos = GetEntityCoords(vehicle) return
local distance = #(returnPos - vehPos)
if distance > 10.0 then
QBCore.Functions.Notify('Bringe das Fahrzeug näher zum Rückgabeort!', 'error')
return
end
end end
-- Fahrzeug zurückgeben -- Fahrzeug zurückgeben
QBCore.Functions.TriggerCallback('vehiclerental:server:returnVehicle', function(success) QBCore.Functions.TriggerCallback('vehiclerental:server:returnVehicle', function(success)
if success then if success then
DeleteVehicle(vehicle) DeleteVehicle(vehicle)
activeRentalVehicles[plate] = nil
QBCore.Functions.Notify('Fahrzeug erfolgreich zurückgegeben!', 'success')
end end
end, plate) end, plate)
end end
-- Lade alle aktiven Mietfahrzeuge
RegisterNetEvent('vehiclerental:client:loadRentals')
AddEventHandler('vehiclerental:client:loadRentals', function(rentals)
-- Lösche alle vorhandenen Mietfahrzeuge
for plate, vehicle in pairs(activeRentalVehicles) do
if DoesEntityExist(vehicle) then
DeleteVehicle(vehicle)
end
end
activeRentalVehicles = {}
-- Spawne alle aktiven Mietfahrzeuge
for _, rental in ipairs(rentals) do
-- Prüfe, ob das Fahrzeug dem aktuellen Spieler gehört
local playerCitizenId = QBCore.Functions.GetPlayerData().citizenid
if rental.citizenid == playerCitizenId then
-- Spawne das Fahrzeug nur, wenn es eine Position hat
if rental.posX ~= 0 or rental.posY ~= 0 or rental.posZ ~= 0 then
Citizen.CreateThread(function()
local model = rental.vehicle_model
local plate = rental.vehicle_plate
-- Lade das Modell
RequestModel(model)
while not HasModelLoaded(model) do
Citizen.Wait(10)
end
-- Spawne das Fahrzeug
local vehicle = CreateVehicle(model,
rental.posX, rental.posY, rental.posZ,
rental.rotZ or 0.0, true, false)
-- Setze Eigenschaften
SetVehicleNumberPlateText(vehicle, plate)
SetEntityAsMissionEntity(vehicle, true, true)
SetVehicleDoorsLocked(vehicle, 2) -- Abgeschlossen
-- Setze Rotation
SetEntityRotation(vehicle,
rental.rotX or 0.0,
rental.rotY or 0.0,
rental.rotZ or 0.0,
2, true)
-- Gib dem Spieler die Schlüssel
TriggerEvent("vehiclekeys:client:SetOwner", plate)
-- Speichere das Fahrzeug lokal
activeRentalVehicles[plate] = vehicle
print("Mietfahrzeug geladen: " .. plate)
end)
end
end
end
end)
-- Fahrzeug zurückgegeben
RegisterNetEvent('vehiclerental:client:vehicleReturned')
AddEventHandler('vehiclerental:client:vehicleReturned', function(plate)
-- Lösche das Fahrzeug, wenn es existiert
if activeRentalVehicles[plate] and DoesEntityExist(activeRentalVehicles[plate]) then
DeleteVehicle(activeRentalVehicles[plate])
activeRentalVehicles[plate] = nil
print("Mietfahrzeug gelöscht: " .. plate)
end
end)
-- Regelmäßiges Update der Fahrzeugpositionen
Citizen.CreateThread(function()
while true do
Citizen.Wait(30000) -- Alle 30 Sekunden
-- Update alle aktiven Mietfahrzeuge
for plate, vehicle in pairs(activeRentalVehicles) do
if DoesEntityExist(vehicle) then
local pos = GetEntityCoords(vehicle)
local rot = GetEntityRotation(vehicle)
TriggerServerEvent('vehiclerental:server:updatePosition', plate, pos, rot)
end
end
end
end)
-- Wenn der Spieler das Fahrzeug verlässt, aktualisiere die Position
Citizen.CreateThread(function()
while true do
Citizen.Wait(500)
local playerPed = PlayerPedId()
local vehicle = GetVehiclePedIsIn(playerPed, true)
if vehicle ~= 0 then
local plate = GetVehicleNumberPlateText(vehicle)
-- Wenn es ein Mietfahrzeug ist und der Spieler es gerade verlassen hat
if activeRentalVehicles[plate] and not IsPedInVehicle(playerPed, vehicle, false) then
local pos = GetEntityCoords(vehicle)
local rot = GetEntityRotation(vehicle)
TriggerServerEvent('vehiclerental:server:updatePosition', plate, pos, rot)
end
end
end
end)
-- Fahrzeug-Enumerator -- Fahrzeug-Enumerator
function EnumerateVehicles() function EnumerateVehicles()
return coroutine.wrap(function() return coroutine.wrap(function()
@ -236,7 +377,7 @@ function EnumerateVehicles()
end) end)
end end
-- Kennzeichen generieren (GEÄNDERT - RENTAL + 3 zufällige Zeichen) -- Kennzeichen generieren (RENT + 4 zufällige Zeichen)
function GeneratePlate() function GeneratePlate()
local plate = "RENT" local plate = "RENT"
for i = 1, 4 do for i = 1, 4 do
@ -258,24 +399,10 @@ AddEventHandler('onResourceStop', function(resourceName)
DeleteEntity(npc) DeleteEntity(npc)
end end
end end
end)
-- Integration mit mh_Parking
RegisterNetEvent('vehiclerental:client:vehicleRented')
AddEventHandler('vehiclerental:client:vehicleRented', function(vehicle, plate)
-- Warte kurz, bis das Fahrzeug vollständig gespawnt ist
Citizen.Wait(1000)
-- Aktualisiere das Fahrzeug im Parking-System for plate, vehicle in pairs(activeRentalVehicles) do
if DoesEntityExist(vehicle) then if DoesEntityExist(vehicle) then
TriggerEvent("mh_Parking:updateVehicle", vehicle) DeleteVehicle(vehicle)
print("Mietfahrzeug im Parking-System registriert: " .. plate) end
end end
end) end)
-- Wenn ein Mietfahrzeug zurückgegeben wird
RegisterNetEvent('vehiclerental:client:vehicleReturned')
AddEventHandler('vehiclerental:client:vehicleReturned', function(plate)
-- Entferne das Fahrzeug aus dem Parking-System
TriggerServerEvent("mh_Parking:deleteVehicle", plate, true)
print("Mietfahrzeug aus dem Parking-System entfernt: " .. plate)
end)

View file

@ -3,7 +3,8 @@ Config = {}
Config.MaxRentalTime = 24 -- Maximale Mietdauer in Stunden Config.MaxRentalTime = 24 -- Maximale Mietdauer in Stunden
Config.PenaltyPerHour = 100 -- Strafe pro Stunde Verspätung Config.PenaltyPerHour = 100 -- Strafe pro Stunde Verspätung
Config.UseOkokBanking = false -- true für okokBanking, false für Bargeld Config.UseOkokBanking = false -- true für okokBanking, false für Bargeld
Config.MaxReturnDistance = 10.0 -- Maximale Entfernung zum Rückgabepunkt in Metern Config.MaxReturnDistance = 20.0 -- Maximale Entfernung zum Rückgabepunkt in Metern
Config.MaxOverdueHours = 24 -- Nach wie vielen Stunden überfällige Fahrzeuge automatisch zurückgegeben werden
Config.RentalLocations = { Config.RentalLocations = {
{ {

View file

@ -1,23 +1,46 @@
local QBCore = exports['qb-core']:GetCoreObject()
-- Datenbank Tabelle erstellen local QBCore = exports['qb-core']:GetCoreObject()
MySQL.ready(function() local activeRentals = {}
MySQL.Async.execute([[
CREATE TABLE IF NOT EXISTS vehicle_rentals ( -- Lade alle aktiven Mietfahrzeuge beim Serverstart
id INT AUTO_INCREMENT PRIMARY KEY, Citizen.CreateThread(function()
citizenid VARCHAR(50) NOT NULL, Wait(5000) -- Warte, bis die Datenbank bereit ist
vehicle_model VARCHAR(50) NOT NULL,
vehicle_plate VARCHAR(10) NOT NULL, MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE returned = FALSE', {}, function(results)
rental_location VARCHAR(50) NOT NULL, if results and #results > 0 then
start_time BIGINT NOT NULL, print("Lade " .. #results .. " aktive Mietfahrzeuge...")
end_time BIGINT NOT NULL,
price_per_hour INT NOT NULL, for _, rental in ipairs(results) do
returned BOOLEAN DEFAULT FALSE, activeRentals[rental.vehicle_plate] = rental
penalty_paid BOOLEAN DEFAULT FALSE, end
INDEX(citizenid),
INDEX(vehicle_plate) -- 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) end)
-- Fahrzeug mieten -- Fahrzeug mieten
@ -57,10 +80,23 @@ QBCore.Functions.CreateCallback('vehiclerental:server:rentVehicle', function(sou
currentTime, currentTime,
endTime, endTime,
data.pricePerHour 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
}
TriggerClientEvent('QBCore:Notify', source, 'Fahrzeug erfolgreich gemietet für $' .. totalCost, 'success') TriggerClientEvent('QBCore:Notify', source, 'Fahrzeug erfolgreich gemietet für $' .. totalCost, 'success')
cb(true) cb(true)
end)
end) end)
-- Fahrzeug zurückgeben -- Fahrzeug zurückgeben
@ -116,38 +152,47 @@ QBCore.Functions.CreateCallback('vehiclerental:server:returnVehicle', function(s
rental.id rental.id
}) })
-- Aus dem aktiven Cache entfernen
activeRentals[plate] = nil
-- Benachrichtige alle Clients, dass das Fahrzeug zurückgegeben wurde
TriggerClientEvent('vehiclerental:client:vehicleReturned', -1, plate)
TriggerClientEvent('QBCore:Notify', source, 'Fahrzeug erfolgreich zurückgegeben!', 'success') TriggerClientEvent('QBCore:Notify', source, 'Fahrzeug erfolgreich zurückgegeben!', 'success')
cb(true) cb(true)
end) end)
end) end)
-- Mietzeit abfragen -- Spieler Mietverhältnisse abrufen
QBCore.Functions.CreateCallback('vehiclerental:server:getRentalInfo', function(source, cb) QBCore.Functions.CreateCallback('vehiclerental:server:getPlayerRentals', function(source, cb)
local Player = QBCore.Functions.GetPlayer(source) local Player = QBCore.Functions.GetPlayer(source)
if not Player then return cb(nil) end if not Player then return cb(nil) end
MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE citizenid = ? AND returned = FALSE', { MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE citizenid = ? AND returned = FALSE', {
Player.PlayerData.citizenid Player.PlayerData.citizenid
}, function(result) }, function(result)
if not result[1] then if not result or #result == 0 then
return cb(nil) return cb(nil)
end end
local rentals = {} local currentTime = os.time()
for i = 1, #result do for i = 1, #result do
local rental = result[i] -- Berechne verbleibende Zeit auf dem Server
local currentTime = os.time() result[i].timeLeft = result[i].end_time - currentTime
local timeLeft = rental.end_time - currentTime result[i].isOverdue = result[i].timeLeft < 0
table.insert(rentals, { -- Formatiere die Zeit für die Anzeige
vehicleModel = rental.vehicle_model, if result[i].isOverdue then
plate = rental.vehicle_plate, local hoursOverdue = math.ceil(math.abs(result[i].timeLeft) / 3600)
timeLeft = timeLeft, result[i].timeText = "(Überfällig um " .. hoursOverdue .. " Stunden)"
isOverdue = timeLeft < 0 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 end
cb(rentals) cb(result)
end) end)
end) end)
@ -184,115 +229,49 @@ QBCore.Commands.Add('mietzeit', 'Zeige deine aktuelle Mietzeit an', {}, false, f
end) end)
end) end)
-- Spieler Mietverhältnisse abrufen (VERBESSERT) -- Regelmäßige Überprüfung auf überfällige Fahrzeuge
QBCore.Functions.CreateCallback('vehiclerental:server:getPlayerRentals', function(source, cb) Citizen.CreateThread(function()
local Player = QBCore.Functions.GetPlayer(source) while true do
if not Player then return cb(nil) end Citizen.Wait(60000) -- Überprüfe jede Minute
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() local currentTime = os.time()
for i = 1, #result do local overdueVehicles = {}
-- 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 -- Überprüfe alle aktiven Mietfahrzeuge
if result[i].isOverdue then for plate, rental in pairs(activeRentals) do
local hoursOverdue = math.ceil(math.abs(result[i].timeLeft) / 3600) if currentTime > rental.end_time + (Config.MaxOverdueHours * 3600) then
result[i].timeText = "(Überfällig um " .. hoursOverdue .. " Stunden)" -- Fahrzeug ist zu lange überfällig, markiere es als zurückgegeben
else MySQL.Async.execute('UPDATE vehicle_rentals SET returned = TRUE, penalty_paid = TRUE WHERE vehicle_plate = ? AND returned = FALSE', {
local hoursLeft = math.floor(result[i].timeLeft / 3600) plate
local minutesLeft = math.floor((result[i].timeLeft % 3600) / 60) })
result[i].timeText = "(" .. hoursLeft .. "h " .. minutesLeft .. "m verbleibend)"
-- Füge es zur Liste der zu entfernenden Fahrzeuge hinzu
table.insert(overdueVehicles, plate)
end end
end end
cb(result) -- Entferne überfällige Fahrzeuge aus dem Cache
end) for _, plate in ipairs(overdueVehicles) do
end) activeRentals[plate] = nil
-- Funktion zum Entfernen von Mietfahrzeugen aus dem Parking-System -- Benachrichtige alle Clients, dass das Fahrzeug entfernt werden soll
function RemoveRentalFromParking(plate)
-- Entferne das Fahrzeug aus dem mh_Parking System
TriggerEvent("mh_Parking:removeVehicle", plate)
-- Lösche es auch aus der Datenbank des Parking-Systems
MySQL.Async.execute("DELETE FROM vehicle_parking WHERE plate = @plate", {
["@plate"] = plate
})
end
-- Wenn ein Fahrzeug zurückgegeben wird, entferne es aus dem Parking-System
RegisterNetEvent('vehiclerental:server:vehicleReturned')
AddEventHandler('vehiclerental:server:vehicleReturned', function(plate)
RemoveRentalFromParking(plate)
end)
-- Modifiziere die bestehende returnVehicle Callback-Funktion
local originalReturnCallback = QBCore.Functions.CreateCallback('vehiclerental:server:returnVehicle')
QBCore.Functions.CreateCallback('vehiclerental:server:returnVehicle', function(source, cb, plate)
-- Wenn das Fahrzeug erfolgreich zurückgegeben wurde
MySQL.Async.fetchAll('SELECT * FROM vehicle_rentals WHERE vehicle_plate = ? AND returned = FALSE', {
plate
}, function(result)
if result[1] then
-- Führe die normale Rückgabe durch
local Player = QBCore.Functions.GetPlayer(source)
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
})
-- Entferne das Fahrzeug aus dem Parking-System
RemoveRentalFromParking(plate)
-- Benachrichtige alle Clients
TriggerClientEvent('vehiclerental:client:vehicleReturned', -1, plate) TriggerClientEvent('vehiclerental:client:vehicleReturned', -1, plate)
end
end
end)
TriggerClientEvent('QBCore:Notify', source, 'Fahrzeug erfolgreich zurückgegeben!', 'success') -- Spieler verbindet sich
cb(true) RegisterNetEvent('QBCore:Server:PlayerLoaded')
else AddEventHandler('QBCore:Server:PlayerLoaded', function()
TriggerClientEvent('QBCore:Notify', source, 'Kein aktives Mietverhältnis für dieses Fahrzeug gefunden!', 'error') local src = source
cb(false) 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
TriggerClientEvent('vehiclerental:client:loadRentals', src, results)
end end
end) end)
end) end)