forked from Simnation/Main
ed
This commit is contained in:
parent
19928f3c5f
commit
90ab2c2b27
3 changed files with 326 additions and 219 deletions
|
@ -1,44 +1,64 @@
|
|||
local QBCore = exports['qb-core']:GetCoreObject()
|
||||
local spawnedNPCs = {}
|
||||
local currentRental = nil
|
||||
local activeRentalVehicles = {}
|
||||
|
||||
-- NPCs spawnen
|
||||
CreateThread(function()
|
||||
-- Warte kurz, bis die Welt geladen ist
|
||||
Wait(2000)
|
||||
|
||||
for i = 1, #Config.RentalLocations do
|
||||
local location = Config.RentalLocations[i]
|
||||
local modelHash = GetHashKey(location.npc.model)
|
||||
|
||||
RequestModel(location.npc.model)
|
||||
while not HasModelLoaded(location.npc.model) do
|
||||
Wait(1)
|
||||
-- Modell laden
|
||||
RequestModel(modelHash)
|
||||
local timeout = 0
|
||||
while not HasModelLoaded(modelHash) and timeout < 30 do
|
||||
Wait(100)
|
||||
timeout = timeout + 1
|
||||
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)
|
||||
FreezeEntityPosition(npc, true)
|
||||
SetEntityInvincible(npc, true)
|
||||
SetBlockingOfNonTemporaryEvents(npc, true)
|
||||
|
||||
spawnedNPCs[location.id] = npc
|
||||
|
||||
-- QB-Target für NPC
|
||||
exports['qb-target']:AddTargetEntity(npc, {
|
||||
options = {
|
||||
{
|
||||
type = "client",
|
||||
event = "vehiclerental:client:openMenu",
|
||||
icon = "fas fa-car",
|
||||
label = "Fahrzeug mieten",
|
||||
locationId = location.id
|
||||
if HasModelLoaded(modelHash) then
|
||||
-- NPC erstellen
|
||||
local coords = location.npc.coords
|
||||
local npc = CreatePed(4, modelHash, coords.x, coords.y, coords.z - 1.0, coords.w, false, false)
|
||||
|
||||
-- NPC-Eigenschaften setzen
|
||||
FreezeEntityPosition(npc, true)
|
||||
SetEntityInvincible(npc, true)
|
||||
SetBlockingOfNonTemporaryEvents(npc, true)
|
||||
SetPedDefaultComponentVariation(npc)
|
||||
|
||||
-- NPC speichern
|
||||
spawnedNPCs[location.id] = npc
|
||||
|
||||
-- Debug-Info
|
||||
print("NPC spawned at location: " .. location.name)
|
||||
|
||||
-- QB-Target für NPC
|
||||
exports['qb-target']:AddTargetEntity(npc, {
|
||||
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
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "client",
|
||||
event = "vehiclerental:client:returnVehicle",
|
||||
icon = "fas fa-car-side",
|
||||
label = "Fahrzeug zurückgeben",
|
||||
locationId = location.id
|
||||
}
|
||||
},
|
||||
distance = 2.0
|
||||
})
|
||||
distance = 2.0
|
||||
})
|
||||
else
|
||||
print("Failed to load NPC model for location: " .. location.name)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
@ -130,12 +150,18 @@ function spawnRentalVehicle(model, spawnPoint, plate)
|
|||
TriggerEvent("vehiclekeys:client:SetOwner", plate)
|
||||
SetModelAsNoLongerNeeded(model)
|
||||
|
||||
-- Registriere das Fahrzeug im Parking-System
|
||||
TriggerEvent('vehiclerental:client:vehicleRented', vehicle, plate)
|
||||
-- Speichere das Fahrzeug lokal
|
||||
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
|
||||
|
||||
|
||||
-- Fahrzeug zurückgeben (KORRIGIERT - ohne im Auto zu sitzen)
|
||||
-- Fahrzeug zurückgeben
|
||||
RegisterNetEvent('vehiclerental:client:returnVehicle', function(data)
|
||||
-- Hole alle aktiven Mietverhältnisse des Spielers
|
||||
QBCore.Functions.TriggerCallback('vehiclerental:server:getPlayerRentals', function(rentals)
|
||||
|
@ -171,17 +197,33 @@ end)
|
|||
|
||||
-- Spezifisches Fahrzeug zurückgeben
|
||||
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
|
||||
local playerPos = GetEntityCoords(PlayerPedId())
|
||||
local vehicle = nil
|
||||
local closestDistance = 50.0 -- Maximale Entfernung
|
||||
local closestDistance = 50.0 -- Maximale Suchentfernung
|
||||
|
||||
-- Suche nach dem Fahrzeug mit dem Kennzeichen
|
||||
for veh in EnumerateVehicles() do
|
||||
local vehPlate = GetVehicleNumberPlateText(veh)
|
||||
if string.gsub(vehPlate, "%s+", "") == string.gsub(plate, "%s+", "") then
|
||||
local vehPos = GetEntityCoords(veh)
|
||||
local distance = #(playerPos - vehPos)
|
||||
local distance = #(returnPoint - vehPos)
|
||||
|
||||
if distance < closestDistance then
|
||||
vehicle = veh
|
||||
|
@ -191,38 +233,137 @@ function returnSpecificVehicle(plate, locationId)
|
|||
end
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
-- Prüfe ob das Fahrzeug am richtigen Ort ist
|
||||
local location = nil
|
||||
for i = 1, #Config.RentalLocations do
|
||||
if Config.RentalLocations[i].id == locationId then
|
||||
location = Config.RentalLocations[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if location then
|
||||
local returnPos = vector3(location.returnPoint.x, location.returnPoint.y, location.returnPoint.z)
|
||||
local vehPos = GetEntityCoords(vehicle)
|
||||
local distance = #(returnPos - vehPos)
|
||||
|
||||
if distance > 10.0 then
|
||||
QBCore.Functions.Notify('Bringe das Fahrzeug näher zum Rückgabeort!', 'error')
|
||||
return
|
||||
end
|
||||
-- Prüfe ob das Fahrzeug nahe genug am Rückgabeort ist
|
||||
local vehPos = GetEntityCoords(vehicle)
|
||||
local distance = #(returnPoint - vehPos)
|
||||
|
||||
if distance > Config.MaxReturnDistance then
|
||||
QBCore.Functions.Notify('Das Fahrzeug muss näher am Rückgabeort sein! (Max. ' .. Config.MaxReturnDistance .. 'm)', 'error')
|
||||
return
|
||||
end
|
||||
|
||||
-- Fahrzeug zurückgeben
|
||||
QBCore.Functions.TriggerCallback('vehiclerental:server:returnVehicle', function(success)
|
||||
if success then
|
||||
DeleteVehicle(vehicle)
|
||||
activeRentalVehicles[plate] = nil
|
||||
QBCore.Functions.Notify('Fahrzeug erfolgreich zurückgegeben!', 'success')
|
||||
end
|
||||
end, plate)
|
||||
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
|
||||
function EnumerateVehicles()
|
||||
return coroutine.wrap(function()
|
||||
|
@ -236,7 +377,7 @@ function EnumerateVehicles()
|
|||
end)
|
||||
end
|
||||
|
||||
-- Kennzeichen generieren (GEÄNDERT - RENTAL + 3 zufällige Zeichen)
|
||||
-- Kennzeichen generieren (RENT + 4 zufällige Zeichen)
|
||||
function GeneratePlate()
|
||||
local plate = "RENT"
|
||||
for i = 1, 4 do
|
||||
|
@ -258,24 +399,10 @@ AddEventHandler('onResourceStop', function(resourceName)
|
|||
DeleteEntity(npc)
|
||||
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
|
||||
if DoesEntityExist(vehicle) then
|
||||
TriggerEvent("mh_Parking:updateVehicle", vehicle)
|
||||
print("Mietfahrzeug im Parking-System registriert: " .. plate)
|
||||
for plate, vehicle in pairs(activeRentalVehicles) do
|
||||
if DoesEntityExist(vehicle) then
|
||||
DeleteVehicle(vehicle)
|
||||
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)
|
||||
|
|
|
@ -3,7 +3,8 @@ Config = {}
|
|||
Config.MaxRentalTime = 24 -- Maximale Mietdauer in Stunden
|
||||
Config.PenaltyPerHour = 100 -- Strafe pro Stunde Verspätung
|
||||
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 = {
|
||||
{
|
||||
|
|
|
@ -1,23 +1,46 @@
|
|||
local QBCore = exports['qb-core']:GetCoreObject()
|
||||
|
||||
-- Datenbank Tabelle erstellen
|
||||
MySQL.ready(function()
|
||||
MySQL.Async.execute([[
|
||||
CREATE TABLE IF NOT EXISTS vehicle_rentals (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
citizenid VARCHAR(50) NOT NULL,
|
||||
vehicle_model VARCHAR(50) NOT NULL,
|
||||
vehicle_plate VARCHAR(10) NOT NULL,
|
||||
rental_location VARCHAR(50) NOT NULL,
|
||||
start_time BIGINT NOT NULL,
|
||||
end_time BIGINT NOT NULL,
|
||||
price_per_hour INT NOT NULL,
|
||||
returned BOOLEAN DEFAULT FALSE,
|
||||
penalty_paid BOOLEAN DEFAULT FALSE,
|
||||
INDEX(citizenid),
|
||||
INDEX(vehicle_plate)
|
||||
)
|
||||
]])
|
||||
local QBCore = exports['qb-core']:GetCoreObject()
|
||||
local activeRentals = {}
|
||||
|
||||
-- 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
|
||||
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
|
||||
|
@ -57,10 +80,23 @@ QBCore.Functions.CreateCallback('vehiclerental:server:rentVehicle', function(sou
|
|||
currentTime,
|
||||
endTime,
|
||||
data.pricePerHour
|
||||
})
|
||||
|
||||
TriggerClientEvent('QBCore:Notify', source, 'Fahrzeug erfolgreich gemietet für $' .. totalCost, 'success')
|
||||
cb(true)
|
||||
}, 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')
|
||||
cb(true)
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Fahrzeug zurückgeben
|
||||
|
@ -115,39 +151,48 @@ QBCore.Functions.CreateCallback('vehiclerental:server:returnVehicle', function(s
|
|||
penalty > 0,
|
||||
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')
|
||||
cb(true)
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Mietzeit abfragen
|
||||
QBCore.Functions.CreateCallback('vehiclerental:server:getRentalInfo', function(source, cb)
|
||||
-- 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[1] then
|
||||
if not result or #result == 0 then
|
||||
return cb(nil)
|
||||
end
|
||||
|
||||
local rentals = {}
|
||||
local currentTime = os.time()
|
||||
for i = 1, #result do
|
||||
local rental = result[i]
|
||||
local currentTime = os.time()
|
||||
local timeLeft = rental.end_time - currentTime
|
||||
-- Berechne verbleibende Zeit auf dem Server
|
||||
result[i].timeLeft = result[i].end_time - currentTime
|
||||
result[i].isOverdue = result[i].timeLeft < 0
|
||||
|
||||
table.insert(rentals, {
|
||||
vehicleModel = rental.vehicle_model,
|
||||
plate = rental.vehicle_plate,
|
||||
timeLeft = timeLeft,
|
||||
isOverdue = 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(rentals)
|
||||
cb(result)
|
||||
end)
|
||||
end)
|
||||
|
||||
|
@ -184,115 +229,49 @@ QBCore.Commands.Add('mietzeit', 'Zeige deine aktuelle Mietzeit an', {}, false, f
|
|||
end)
|
||||
end)
|
||||
|
||||
-- Spieler Mietverhältnisse abrufen (VERBESSERT)
|
||||
QBCore.Functions.CreateCallback('vehiclerental:server:getPlayerRentals', function(source, cb)
|
||||
local Player = QBCore.Functions.GetPlayer(source)
|
||||
if not Player then return cb(nil) 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
|
||||
})
|
||||
|
||||
-- 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(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)
|
||||
-- Funktion zum Entfernen von Mietfahrzeugen aus dem Parking-System
|
||||
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('QBCore:Notify', source, 'Fahrzeug erfolgreich zurückgegeben!', 'success')
|
||||
cb(true)
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, 'Kein aktives Mietverhältnis für dieses Fahrzeug gefunden!', 'error')
|
||||
cb(false)
|
||||
}, function(results)
|
||||
if results and #results > 0 then
|
||||
TriggerClientEvent('vehiclerental:client:loadRentals', src, results)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue