245 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
local QBCore = exports['qb-core']:GetCoreObject()
 | 
						|
local loadedKayaks = {}
 | 
						|
local currentTrailer = nil
 | 
						|
 | 
						|
-- Function to check if a model is a kayak
 | 
						|
local function IsKayakModel(model)
 | 
						|
    for _, kayakModel in ipairs(Config.KayakModels) do
 | 
						|
        if GetHashKey(kayakModel) == model then
 | 
						|
            return true
 | 
						|
        end
 | 
						|
    end
 | 
						|
    return false
 | 
						|
end
 | 
						|
 | 
						|
-- Function to get nearby kayak
 | 
						|
local function GetNearbyKayak()
 | 
						|
    local playerPed = PlayerPedId()
 | 
						|
    local playerCoords = GetEntityCoords(playerPed)
 | 
						|
    
 | 
						|
    local kayak = nil
 | 
						|
    local minDistance = Config.InteractionRange
 | 
						|
    
 | 
						|
    for _, entity in ipairs(GetGamePool('CVehicle')) do
 | 
						|
        if IsKayakModel(GetEntityModel(entity)) then
 | 
						|
            local distance = #(playerCoords - GetEntityCoords(entity))
 | 
						|
            if distance < minDistance then
 | 
						|
                minDistance = distance
 | 
						|
                kayak = entity
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    return kayak
 | 
						|
end
 | 
						|
 | 
						|
-- Function to get nearby trailer
 | 
						|
local function GetNearbyTrailer()
 | 
						|
    local playerPed = PlayerPedId()
 | 
						|
    local playerCoords = GetEntityCoords(playerPed)
 | 
						|
    
 | 
						|
    local trailer = nil
 | 
						|
    local minDistance = Config.InteractionRange
 | 
						|
    
 | 
						|
    for _, entity in ipairs(GetGamePool('CVehicle')) do
 | 
						|
        if GetEntityModel(entity) == GetHashKey(Config.TrailerModel) then
 | 
						|
            local distance = #(playerCoords - GetEntityCoords(entity))
 | 
						|
            if distance < minDistance then
 | 
						|
                minDistance = distance
 | 
						|
                trailer = entity
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    return trailer
 | 
						|
end
 | 
						|
 | 
						|
-- Function to load kayak onto trailer
 | 
						|
local function LoadKayakOntoTrailer(trailer, kayak)
 | 
						|
    if not trailer or not kayak then return end
 | 
						|
    
 | 
						|
    local trailerNetId = NetworkGetNetworkIdFromEntity(trailer)
 | 
						|
    local kayakNetId = NetworkGetNetworkIdFromEntity(kayak)
 | 
						|
    
 | 
						|
    -- Check if trailer already has max kayaks
 | 
						|
    if #loadedKayaks >= Config.MaxKayaks then
 | 
						|
        QBCore.Functions.Notify("Trailer rack is already fully loaded with kayaks", "error")
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Add kayak to loaded kayaks
 | 
						|
    table.insert(loadedKayaks, kayakNetId)
 | 
						|
    
 | 
						|
    -- Update kayak position on trailer
 | 
						|
    local position = Config.KayakPositions[#loadedKayaks]
 | 
						|
    local trailerCoords = GetEntityCoords(trailer)
 | 
						|
    local trailerHeading = GetEntityHeading(trailer)
 | 
						|
    
 | 
						|
    -- Calculate world position based on trailer position and offset
 | 
						|
    local kayakX = trailerCoords.x + (math.cos(math.rad(trailerHeading)) * position.x) - (math.sin(math.rad(trailerHeading)) * position.y)
 | 
						|
    local kayakY = trailerCoords.y + (math.sin(math.rad(trailerHeading)) * position.x) + (math.cos(math.rad(trailerHeading)) * position.y)
 | 
						|
    local kayakZ = trailerCoords.z + position.z
 | 
						|
    local kayakHeading = trailerHeading + position.heading
 | 
						|
    
 | 
						|
    -- Set kayak position and attach to trailer
 | 
						|
    SetEntityCoords(kayak, kayakX, kayakY, kayakZ, false, false, false, false)
 | 
						|
    SetEntityHeading(kayak, kayakHeading)
 | 
						|
    
 | 
						|
    -- Attach kayak to trailer
 | 
						|
    AttachEntityToEntity(kayak, trailer, 0, position.x, position.y, position.z, 0.0, 0.0, position.heading, true, false, true, false, 0, true)
 | 
						|
    
 | 
						|
    -- Display which rack position was loaded
 | 
						|
    local side = #loadedKayaks <= 3 and "left" or "right"
 | 
						|
    local level = (#loadedKayaks - 1) % 3 + 1
 | 
						|
    local levelNames = {"bottom", "middle", "top"}
 | 
						|
    
 | 
						|
    QBCore.Functions.Notify("Kayak loaded onto " .. levelNames[level] .. " rack, " .. side .. " side", "success")
 | 
						|
    
 | 
						|
    -- Save current trailer
 | 
						|
    currentTrailer = trailerNetId
 | 
						|
    
 | 
						|
    -- Sync with server
 | 
						|
    TriggerServerEvent('kayak_trailer:syncLoadedKayaks', trailerNetId, loadedKayaks)
 | 
						|
end
 | 
						|
 | 
						|
-- Function to unload kayak from trailer
 | 
						|
local function UnloadKayakFromTrailer(trailer)
 | 
						|
    if not trailer or #loadedKayaks == 0 then return end
 | 
						|
    
 | 
						|
    local trailerNetId = NetworkGetNetworkIdFromEntity(trailer)
 | 
						|
    
 | 
						|
    -- Get last kayak
 | 
						|
    local kayakNetId = loadedKayaks[#loadedKayaks]
 | 
						|
    local kayak = NetworkGetEntityFromNetworkId(kayakNetId)
 | 
						|
    
 | 
						|
    -- Get position info for notification
 | 
						|
    local side = #loadedKayaks <= 3 and "left" or "right"
 | 
						|
    local level = (#loadedKayaks - 1) % 3 + 1
 | 
						|
    local levelNames = {"bottom", "middle", "top"}
 | 
						|
    
 | 
						|
    -- Remove from loaded kayaks
 | 
						|
    table.remove(loadedKayaks, #loadedKayaks)
 | 
						|
    
 | 
						|
    -- Detach kayak from trailer
 | 
						|
    DetachEntity(kayak, true, true)
 | 
						|
    
 | 
						|
    -- Place kayak behind trailer
 | 
						|
    local trailerCoords = GetEntityCoords(trailer)
 | 
						|
    local trailerHeading = GetEntityHeading(trailer)
 | 
						|
    local offsetX = -3.0 -- 3 meters behind trailer
 | 
						|
    
 | 
						|
    local kayakX = trailerCoords.x - (math.cos(math.rad(trailerHeading)) * offsetX)
 | 
						|
    local kayakY = trailerCoords.y - (math.sin(math.rad(trailerHeading)) * offsetX)
 | 
						|
    local kayakZ = trailerCoords.z
 | 
						|
    
 | 
						|
    SetEntityCoords(kayak, kayakX, kayakY, kayakZ, false, false, false, false)
 | 
						|
    SetEntityHeading(kayak, trailerHeading)
 | 
						|
    
 | 
						|
    QBCore.Functions.Notify("Kayak unloaded from " .. levelNames[level] .. " rack, " .. side .. " side", "success")
 | 
						|
    
 | 
						|
    -- Sync with server
 | 
						|
    TriggerServerEvent('kayak_trailer:syncLoadedKayaks', trailerNetId, loadedKayaks)
 | 
						|
end
 | 
						|
 | 
						|
-- Initialize qb-target
 | 
						|
Citizen.CreateThread(function()
 | 
						|
    -- Target for loading kayaks onto trailer
 | 
						|
    exports['qb-target']:AddTargetModel(Config.TrailerModel, {
 | 
						|
        options = {
 | 
						|
            {
 | 
						|
                type = "client",
 | 
						|
                event = "kayak_trailer:loadKayak",
 | 
						|
                icon = "fas fa-truck-loading",
 | 
						|
                label = "Load Kayak to Rack",
 | 
						|
                canInteract = function()
 | 
						|
                    local kayak = GetNearbyKayak()
 | 
						|
                    return kayak ~= nil and #loadedKayaks < Config.MaxKayaks
 | 
						|
                end
 | 
						|
            },
 | 
						|
            {
 | 
						|
                type = "client",
 | 
						|
                event = "kayak_trailer:unloadKayak",
 | 
						|
                icon = "fas fa-dolly",
 | 
						|
                label = "Unload Kayak from Rack",
 | 
						|
                canInteract = function()
 | 
						|
                    return #loadedKayaks > 0
 | 
						|
                end
 | 
						|
            }
 | 
						|
        },
 | 
						|
        distance = Config.InteractionRange
 | 
						|
    })
 | 
						|
    
 | 
						|
    -- Target for kayaks
 | 
						|
    for _, model in ipairs(Config.KayakModels) do
 | 
						|
        exports['qb-target']:AddTargetModel(model, {
 | 
						|
            options = {
 | 
						|
                {
 | 
						|
                    type = "client",
 | 
						|
                    event = "kayak_trailer:loadKayak",
 | 
						|
                    icon = "fas fa-truck-loading",
 | 
						|
                    label = "Load onto Trailer Rack",
 | 
						|
                    canInteract = function()
 | 
						|
                        local trailer = GetNearbyTrailer()
 | 
						|
                        return trailer ~= nil and #loadedKayaks < Config.MaxKayaks
 | 
						|
                    end
 | 
						|
                }
 | 
						|
            },
 | 
						|
            distance = Config.InteractionRange
 | 
						|
        })
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
-- Event handlers
 | 
						|
RegisterNetEvent('kayak_trailer:loadKayak', function()
 | 
						|
    local trailer = GetNearbyTrailer()
 | 
						|
    local kayak = GetNearbyKayak()
 | 
						|
    
 | 
						|
    if trailer and kayak then
 | 
						|
        LoadKayakOntoTrailer(trailer, kayak)
 | 
						|
    else
 | 
						|
        QBCore.Functions.Notify("No trailer or kayak nearby", "error")
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
RegisterNetEvent('kayak_trailer:unloadKayak', function()
 | 
						|
    local trailer = GetNearbyTrailer()
 | 
						|
    
 | 
						|
    if trailer then
 | 
						|
        UnloadKayakFromTrailer(trailer)
 | 
						|
    else
 | 
						|
        QBCore.Functions.Notify("No trailer nearby", "error")
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
-- Sync loaded kayaks from server
 | 
						|
RegisterNetEvent('kayak_trailer:syncLoadedKayaksClient', function(trailerNetId, kayakList)
 | 
						|
    if NetworkDoesNetworkIdExist(trailerNetId) then
 | 
						|
        local trailer = NetworkGetEntityFromNetworkId(trailerNetId)
 | 
						|
        
 | 
						|
        -- Clear existing kayaks
 | 
						|
        for _, kayakNetId in ipairs(loadedKayaks) do
 | 
						|
            if NetworkDoesNetworkIdExist(kayakNetId) then
 | 
						|
                local kayak = NetworkGetEntityFromNetworkId(kayakNetId)
 | 
						|
                if DoesEntityExist(kayak) then
 | 
						|
                    DetachEntity(kayak, true, true)
 | 
						|
                end
 | 
						|
            end
 | 
						|
        end
 | 
						|
        
 | 
						|
        -- Update loaded kayaks
 | 
						|
        loadedKayaks = kayakList
 | 
						|
        
 | 
						|
        -- Reattach kayaks
 | 
						|
        for i, kayakNetId in ipairs(loadedKayaks) do
 | 
						|
            if NetworkDoesNetworkIdExist(kayakNetId) then
 | 
						|
                local kayak = NetworkGetEntityFromNetworkId(kayakNetId)
 | 
						|
                if DoesEntityExist(kayak) then
 | 
						|
                    local position = Config.KayakPositions[i]
 | 
						|
                    AttachEntityToEntity(kayak, trailer, 0, position.x, position.y, position.z, 0.0, 0.0, position.heading, true, false, true, false, 0, true)
 | 
						|
                end
 | 
						|
            end
 | 
						|
        end
 | 
						|
        
 | 
						|
        currentTrailer = trailerNetId
 | 
						|
    end
 | 
						|
end)
 |