diff --git a/resources/[tools]/nordi_taxi/client/stations.lua b/resources/[tools]/nordi_taxi/client/stations.lua index fdba66f4a..098fa9130 100644 --- a/resources/[tools]/nordi_taxi/client/stations.lua +++ b/resources/[tools]/nordi_taxi/client/stations.lua @@ -6,9 +6,17 @@ print("^2[TAXI STATIONS DEBUG]^7 Stations script loaded") -- Taxi Stationen initialisieren CreateThread(function() - Wait(2000) -- Längere Wartezeit + Wait(5000) -- Längere Wartezeit, um sicherzustellen, dass alle Ressourcen geladen sind print("^2[TAXI STATIONS DEBUG]^7 Initializing taxi stations...") InitializeTaxiStations() + + -- Regelmäßige Überprüfung und Wiederherstellung der Stationen + CreateThread(function() + while true do + Wait(60000) -- Alle 60 Sekunden prüfen + CheckAndRestoreStationVehicles() + end + end) end) function InitializeTaxiStations() @@ -21,6 +29,10 @@ function InitializeTaxiStations() print("^2[TAXI STATIONS DEBUG]^7 Found " .. #Config.TaxiStations .. " stations") + -- Zuerst alle bestehenden Fahrzeuge und Blips entfernen + CleanupExistingStations() + + -- Dann neue erstellen for stationId, station in pairs(Config.TaxiStations) do print("^2[TAXI STATIONS DEBUG]^7 Processing station " .. stationId .. ": " .. station.name) @@ -38,18 +50,77 @@ function InitializeTaxiStations() -- Fahrzeuge an Station spawnen stationVehicles[stationId] = {} - for vehicleId, vehicleData in pairs(station.vehicles) do - print("^2[TAXI STATIONS DEBUG]^7 Spawning vehicle " .. vehicleId .. " (" .. vehicleData.model .. ") at station " .. stationId) - SpawnStationVehicle(stationId, vehicleId, vehicleData) + + -- Verzögertes Spawnen der Fahrzeuge, um Ressourcenkonflikte zu vermeiden + CreateThread(function() + for vehicleId, vehicleData in pairs(station.vehicles) do + -- Kleine Verzögerung zwischen jedem Fahrzeug + Wait(500) + print("^2[TAXI STATIONS DEBUG]^7 Spawning vehicle " .. vehicleId .. " (" .. vehicleData.model .. ") at station " .. stationId) + SpawnStationVehicle(stationId, vehicleId, vehicleData) + end + end) + end + + print("^2[TAXI STATIONS DEBUG]^7 All stations initialization started") +end + +function CleanupExistingStations() + print("^2[TAXI STATIONS DEBUG]^7 Cleaning up existing stations...") + + -- Alle bestehenden Fahrzeuge löschen + for stationId, vehicles in pairs(stationVehicles) do + for vehicleId, vehicleInfo in pairs(vehicles) do + if vehicleInfo.entity and DoesEntityExist(vehicleInfo.entity) then + exports['qb-target']:RemoveTargetEntity(vehicleInfo.entity) + DeleteEntity(vehicleInfo.entity) + end + if vehicleInfo.driver and DoesEntityExist(vehicleInfo.driver) then + DeleteEntity(vehicleInfo.driver) + end end end - print("^2[TAXI STATIONS DEBUG]^7 All stations initialized") + -- Alle Blips entfernen + for _, blip in pairs(stationBlips) do + RemoveBlip(blip) + end + + -- Variablen zurücksetzen + stationVehicles = {} + stationBlips = {} + + print("^2[TAXI STATIONS DEBUG]^7 Cleanup completed") end function SpawnStationVehicle(stationId, vehicleId, vehicleData) print("^2[TAXI STATIONS DEBUG]^7 SpawnStationVehicle: " .. stationId .. "/" .. vehicleId) + -- Prüfen ob bereits ein Fahrzeug für diese Position existiert + if stationVehicles[stationId] and stationVehicles[stationId][vehicleId] and + stationVehicles[stationId][vehicleId].entity and + DoesEntityExist(stationVehicles[stationId][vehicleId].entity) then + print("^3[TAXI STATIONS DEBUG]^7 Vehicle already exists for this position, removing it first") + exports['qb-target']:RemoveTargetEntity(stationVehicles[stationId][vehicleId].entity) + DeleteEntity(stationVehicles[stationId][vehicleId].entity) + end + + -- Prüfen ob die Position frei ist + local clearArea = true + local vehicles = GetGamePool('CVehicle') + for _, vehicle in ipairs(vehicles) do + local vehCoords = GetEntityCoords(vehicle) + if #(vector3(vehicleData.coords.x, vehicleData.coords.y, vehicleData.coords.z) - vehCoords) < 3.0 then + clearArea = false + print("^3[TAXI STATIONS DEBUG]^7 Position blocked by another vehicle, will retry later") + -- Nach 30 Sekunden erneut versuchen + SetTimeout(30000, function() + SpawnStationVehicle(stationId, vehicleId, vehicleData) + end) + return + end + end + CreateThread(function() local vehicleHash = GetHashKey(vehicleData.model) print("^2[TAXI STATIONS DEBUG]^7 Vehicle hash: " .. vehicleHash) @@ -63,6 +134,10 @@ function SpawnStationVehicle(stationId, vehicleId, vehicleData) if not HasModelLoaded(vehicleHash) then print("^1[TAXI STATIONS DEBUG]^7 Failed to load model: " .. vehicleData.model) + -- Nach 30 Sekunden erneut versuchen + SetTimeout(30000, function() + SpawnStationVehicle(stationId, vehicleId, vehicleData) + end) return end @@ -78,17 +153,34 @@ function SpawnStationVehicle(stationId, vehicleId, vehicleData) if not DoesEntityExist(vehicle) then print("^1[TAXI STATIONS DEBUG]^7 Failed to create vehicle!") + -- Nach 30 Sekunden erneut versuchen + SetTimeout(30000, function() + SpawnStationVehicle(stationId, vehicleId, vehicleData) + end) return end print("^2[TAXI STATIONS DEBUG]^7 Vehicle created: " .. vehicle) + -- Fahrzeug konfigurieren SetEntityAsMissionEntity(vehicle, true, true) SetVehicleOnGroundProperly(vehicle) SetVehicleDoorsLocked(vehicle, 2) -- Locked SetVehicleEngineOn(vehicle, false, true, false) + -- Verbesserte Persistenz + SetEntityInvincible(vehicle, true) + SetVehicleCanBeVisiblyDamaged(vehicle, false) + SetEntityProofs(vehicle, true, true, true, true, true, true, true, true) + SetVehicleExplodesOnHighExplosionDamage(vehicle, false) + SetVehicleHasBeenOwnedByPlayer(vehicle, true) + SetVehicleIsConsideredByPlayer(vehicle, true) + -- Fahrzeug-Info speichern + if not stationVehicles[stationId] then + stationVehicles[stationId] = {} + end + stationVehicles[stationId][vehicleId] = { entity = vehicle, data = vehicleData, @@ -118,6 +210,53 @@ function SpawnStationVehicle(stationId, vehicleId, vehicleData) end) end +function CheckAndRestoreStationVehicles() + print("^2[TAXI STATIONS DEBUG]^7 Checking station vehicles...") + + local restoredCount = 0 + + for stationId, station in pairs(Config.TaxiStations) do + if not stationVehicles[stationId] then + stationVehicles[stationId] = {} + end + + for vehicleId, vehicleData in pairs(station.vehicles) do + local shouldSpawn = false + + -- Prüfen ob das Fahrzeug existiert + if not stationVehicles[stationId][vehicleId] then + print("^3[TAXI STATIONS DEBUG]^7 Vehicle data missing for station " .. stationId .. ", vehicle " .. vehicleId) + shouldSpawn = true + elseif not stationVehicles[stationId][vehicleId].entity then + print("^3[TAXI STATIONS DEBUG]^7 Vehicle entity missing for station " .. stationId .. ", vehicle " .. vehicleId) + shouldSpawn = true + elseif not DoesEntityExist(stationVehicles[stationId][vehicleId].entity) then + print("^3[TAXI STATIONS DEBUG]^7 Vehicle entity doesn't exist for station " .. stationId .. ", vehicle " .. vehicleId) + shouldSpawn = true + elseif stationVehicles[stationId][vehicleId].occupied then + -- Fahrzeug ist besetzt, nicht neu spawnen + print("^2[TAXI STATIONS DEBUG]^7 Vehicle at station " .. stationId .. ", vehicle " .. vehicleId .. " is occupied") + shouldSpawn = false + end + + if shouldSpawn then + print("^2[TAXI STATIONS DEBUG]^7 Respawning vehicle at station " .. stationId .. ", vehicle " .. vehicleId) + SpawnStationVehicle(stationId, vehicleId, vehicleData) + restoredCount = restoredCount + 1 + + -- Kleine Verzögerung zwischen Spawns + Wait(500) + end + end + end + + if restoredCount > 0 then + print("^2[TAXI STATIONS DEBUG]^7 Restored " .. restoredCount .. " station vehicles") + else + print("^2[TAXI STATIONS DEBUG]^7 All station vehicles are present") + end +end + -- Hilfsfunktion um Spieler-Sitz zu ermitteln function GetPlayerVehicleSeat(ped, vehicle) if not IsPedInVehicle(ped, vehicle, false) then @@ -190,14 +329,14 @@ RegisterNetEvent('taxi:enterStationVehicle', function(data) -- Verschiedene Fahrer-Models versuchen local driverModels = { - "A_C_Chimp", -- Standard Male (sollte immer verfügbar sein) - "IG_JIO", -- Standard Female - "a_m_y_business_01", -- Business Male - "a_f_y_business_01", -- Business Female - "a_m_m_business_01", -- Business Male 2 - "a_m_y_downtown_01", -- Downtown Male - "s_m_m_pilot_01", -- Pilot - "s_m_y_dealer_01" -- Dealer + "A_C_Chimp", -- Taxi Driver (erste Wahl) + "a_m_y_business_01", -- Business Male + "a_m_m_business_01", -- Business Male 2 + "mp_m_freemode_01", -- Male Freemode + "a_m_y_downtown_01", -- Downtown Male + "a_m_m_farmer_01", -- Farmer + "a_m_y_hipster_01", -- Hipster + "a_m_y_beach_01" -- Beach Guy } local driver = nil @@ -352,6 +491,10 @@ RegisterNetEvent('taxi:enterStationVehicle', function(data) SetPedKeepTask(driver, true) SetBlockingOfNonTemporaryEvents(driver, true) + -- Verbesserte Fahrer-Einstellungen + SetDriverAbility(driver, 1.0) -- Maximale Fahrfähigkeit + SetDriverAggressiveness(driver, 0.0) -- Minimale Aggressivität + -- Fahrer-Outfit (nur wenn es ein anpassbarer Ped ist) if driverHash == GetHashKey("mp_m_freemode_01") or driverHash == GetHashKey("mp_f_freemode_01") then print("^2[TAXI STATIONS DEBUG]^7 Setting driver outfit...") @@ -563,6 +706,10 @@ function OpenStationTaxiMenu(stationId, vehicleId, vehicle, driver, pricePerKm) lib.showContext('station_taxi_menu') end +function SelfDriveStationTaxi(stationId, vehicleId, vehicle) + print("^2[TAXI STATIONS DEBUG]^7 Player driving taxi themselves") + + local playerPed = PlayerPedId() function SelfDriveStationTaxi(stationId, vehicleId, vehicle) print("^2[TAXI STATIONS DEBUG]^7 Player driving taxi themselves") @@ -639,7 +786,7 @@ function OpenStationSelectionMenu(stationId, vehicleId, vehicle, driver, pricePe end function StartStationTaxiRide(stationId, vehicleId, vehicle, driver, destination, price) - print("^2[TAXI STATIONS DEBUG]^7 Starting station taxi ride to: " .. tostring(destination)) + print("^2[TAXI STATIONS DEBUG]^7 Starting station taxi ride to: " .. tostring(destination.x) .. ", " .. tostring(destination.y) .. ", " .. tostring(destination.z)) -- Wenn kein Fahrer, Spieler selbst fahren lassen if not driver or not DoesEntityExist(driver) then @@ -654,6 +801,7 @@ function StartStationTaxiRide(stationId, vehicleId, vehicle, driver, destination SetBlipSprite(destinationBlip, 1) SetBlipColour(destinationBlip, 2) SetBlipScale(destinationBlip, 0.8) + SetBlipRoute(destinationBlip, true) -- Route zum Ziel anzeigen BeginTextCommandSetBlipName("STRING") AddTextComponentString("Taxi Ziel") EndTextCommandSetBlipName(destinationBlip) @@ -675,19 +823,27 @@ function StartStationTaxiRide(stationId, vehicleId, vehicle, driver, destination SetBlipSprite(destinationBlip, 1) SetBlipColour(destinationBlip, 2) SetBlipScale(destinationBlip, 0.8) + SetBlipRoute(destinationBlip, true) -- Route zum Ziel anzeigen BeginTextCommandSetBlipName("STRING") AddTextComponentString("Taxi Ziel") EndTextCommandSetBlipName(destinationBlip) - -- Zum Ziel fahren - TaskVehicleDriveToCoord(driver, vehicle, destination.x, destination.y, destination.z, 25.0, 0, GetEntityModel(vehicle), 786603, 1.0, true) + -- Zum Ziel fahren mit verbesserter Navigation + TaskVehicleDriveToCoordLongrange(driver, vehicle, destination.x, destination.y, destination.z, 25.0, 786603, 5.0) -- Fahrt überwachen CreateThread(function() + local lastPos = GetEntityCoords(vehicle) + local stuckCounter = 0 + local maxStuckCount = 5 + local rideTimeout = GetGameTimer() + (5 * 60 * 1000) -- 5 Minuten Timeout + while DoesEntityExist(vehicle) and DoesEntityExist(driver) do local vehicleCoords = GetEntityCoords(vehicle) local distance = #(vector3(destination.x, destination.y, destination.z) - vehicleCoords) + local distanceMoved = #(lastPos - vehicleCoords) + -- Überprüfen ob wir angekommen sind if distance < 10.0 then -- Angekommen TaskVehicleTempAction(driver, vehicle, 27, 3000) @@ -713,6 +869,68 @@ function StartStationTaxiRide(stationId, vehicleId, vehicle, driver, destination break end + -- Überprüfen ob das Taxi stecken geblieben ist + if distanceMoved < 1.0 then + stuckCounter = stuckCounter + 1 + + if stuckCounter >= maxStuckCount then + print("^1[TAXI STATIONS DEBUG]^7 Taxi stuck during ride, attempting recovery") + + -- Versuche, das Taxi zu befreien + ClearPedTasks(driver) + + -- Rückwärts fahren + TaskVehicleTempAction(driver, vehicle, 8, 2000) -- Reverse + Wait(2000) + + -- Drehen + TaskVehicleTempAction(driver, vehicle, 7, 2000) -- Turn left + Wait(1000) + TaskVehicleTempAction(driver, vehicle, 8, 1000) -- Reverse + Wait(1000) + TaskVehicleTempAction(driver, vehicle, 6, 2000) -- Turn right + Wait(1000) + + -- Neue Route zum Ziel + TaskVehicleDriveToCoordLongrange(driver, vehicle, destination.x, destination.y, destination.z, 25.0, 786603, 5.0) + + stuckCounter = 0 + end + } else { + stuckCounter = math.max(0, stuckCounter - 1) + } + + -- Überprüfen ob die Fahrt zu lange dauert + if GetGameTimer() > rideTimeout then + print("^1[TAXI STATIONS DEBUG]^7 Taxi ride timed out!") + lib.notify({ + title = 'Taxi Service', + description = 'Die Fahrt dauert zu lange. Wir sind fast da!', + type = 'warning' + }) + + -- Teleportiere Taxi in die Nähe des Ziels + local offset = vector3( + math.random(-20, 20), + math.random(-20, 20), + 0 + ) + local nearDestination = vector3(destination.x, destination.y, destination.z) + offset + + -- Finde gültige Z-Koordinate + local success, groundZ = GetGroundZFor_3dCoord(nearDestination.x, nearDestination.y, nearDestination.z, true) + if success then + nearDestination = vector3(nearDestination.x, nearDestination.y, groundZ) + end + + -- Teleportiere Taxi + SetEntityCoords(vehicle, nearDestination.x, nearDestination.y, nearDestination.z, false, false, false, false) + + -- Neues Timeout setzen (1 Minute) + rideTimeout = GetGameTimer() + (60 * 1000) + end + + lastPos = vehicleCoords Wait(2000) end end) @@ -771,7 +989,7 @@ function ReturnTaxiToStation(stationId, vehicleId, vehicle, driver) local stationCoords = Config.TaxiStations[stationId].coords -- Taxi zur Station zurückfahren lassen - TaskVehicleDriveToCoord(driver, vehicle, stationCoords.x, stationCoords.y, stationCoords.z, 25.0, 0, GetEntityModel(vehicle), 786603, 1.0, true) + TaskVehicleDriveToCoordLongrange(driver, vehicle, stationCoords.x, stationCoords.y, stationCoords.z, 25.0, 786603, 5.0) -- qb-target entfernen während der Fahrt exports['qb-target']:RemoveTargetEntity(vehicle) @@ -905,7 +1123,6 @@ RegisterNetEvent('taxi:respawnAllStations', function() }) end) - -- Thread zum Überwachen der Tasten im Stations-Taxi CreateThread(function() while true do @@ -962,6 +1179,7 @@ CreateThread(function() end else -- Nicht in einem Stations-Taxi + lib.hideTextUI() Wait(1000) end end @@ -1005,8 +1223,6 @@ function EndStationTaxiRide(stationId, vehicleId, vehicle, driver) end) end - - -- Cleanup beim Resource Stop AddEventHandler('onResourceStop', function(resourceName) if GetCurrentResourceName() == resourceName then @@ -1036,6 +1252,3 @@ AddEventHandler('onResourceStop', function(resourceName) print("^2[TAXI STATIONS DEBUG]^7 Cleanup completed") end end) - - -