forked from Simnation/Main
ed
This commit is contained in:
parent
8054759c73
commit
ffaf33c966
7 changed files with 338 additions and 12 deletions
245
resources/[Developer]/[Nordi]/nordi_kayaktrailer/client.lua
Normal file
245
resources/[Developer]/[Nordi]/nordi_kayaktrailer/client.lua
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
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)
|
29
resources/[Developer]/[Nordi]/nordi_kayaktrailer/config.lua
Normal file
29
resources/[Developer]/[Nordi]/nordi_kayaktrailer/config.lua
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
Config = {}
|
||||||
|
|
||||||
|
-- Trailer configuration
|
||||||
|
Config.TrailerModel = 'boattrailer' -- Default trailer model, can be changed to your custom model
|
||||||
|
Config.MaxKayaks = 6 -- Maximum number of kayaks (3 per side)
|
||||||
|
|
||||||
|
-- Kayak models that can be loaded onto the trailer
|
||||||
|
Config.KayakModels = {
|
||||||
|
'kayak01', -- Replace with your actual kayak model names
|
||||||
|
'kayak02',
|
||||||
|
'kayak03'
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Positions for kayaks on the trailer rack (relative to trailer)
|
||||||
|
-- Arranged as 3 levels on each side of the trailer
|
||||||
|
Config.KayakPositions = {
|
||||||
|
-- Left side (3 kayaks stacked vertically)
|
||||||
|
{x = -0.5, y = 0.0, z = 0.6, heading = 90.0}, -- Bottom level
|
||||||
|
{x = -0.5, y = 0.0, z = 1.2, heading = 90.0}, -- Middle level
|
||||||
|
{x = -0.5, y = 0.0, z = 1.8, heading = 90.0}, -- Top level
|
||||||
|
|
||||||
|
-- Right side (3 kayaks stacked vertically)
|
||||||
|
{x = 0.5, y = 0.0, z = 0.6, heading = 270.0}, -- Bottom level
|
||||||
|
{x = 0.5, y = 0.0, z = 1.2, heading = 270.0}, -- Middle level
|
||||||
|
{x = 0.5, y = 0.0, z = 1.8, heading = 270.0} -- Top level
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Range for qb-target interaction
|
||||||
|
Config.InteractionRange = 3.0
|
|
@ -0,0 +1,20 @@
|
||||||
|
fx_version 'cerulean'
|
||||||
|
game 'gta5'
|
||||||
|
|
||||||
|
description 'QBCore Kayak Trailer Script'
|
||||||
|
author 'Your Name'
|
||||||
|
version '1.0.0'
|
||||||
|
|
||||||
|
shared_scripts {
|
||||||
|
'config.lua'
|
||||||
|
}
|
||||||
|
|
||||||
|
client_scripts {
|
||||||
|
'client.lua'
|
||||||
|
}
|
||||||
|
|
||||||
|
server_scripts {
|
||||||
|
'server.lua'
|
||||||
|
}
|
||||||
|
|
||||||
|
lua54 'yes'
|
22
resources/[Developer]/[Nordi]/nordi_kayaktrailer/server.lua
Normal file
22
resources/[Developer]/[Nordi]/nordi_kayaktrailer/server.lua
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||||||
|
local trailerKayaks = {}
|
||||||
|
|
||||||
|
-- Event to sync loaded kayaks
|
||||||
|
RegisterNetEvent('kayak_trailer:syncLoadedKayaks', function(trailerNetId, kayakList)
|
||||||
|
local src = source
|
||||||
|
|
||||||
|
-- Store kayaks for this trailer
|
||||||
|
trailerKayaks[trailerNetId] = kayakList
|
||||||
|
|
||||||
|
-- Broadcast to all clients
|
||||||
|
TriggerClientEvent('kayak_trailer:syncLoadedKayaksClient', -1, trailerNetId, kayakList)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- When a player connects, send them the current state of all trailers
|
||||||
|
RegisterNetEvent('QBCore:Server:PlayerLoaded', function()
|
||||||
|
local src = source
|
||||||
|
|
||||||
|
for trailerNetId, kayakList in pairs(trailerKayaks) do
|
||||||
|
TriggerClientEvent('kayak_trailer:syncLoadedKayaksClient', src, trailerNetId, kayakList)
|
||||||
|
end
|
||||||
|
end)
|
|
@ -17,14 +17,14 @@ config.carryItmes = {
|
||||||
moveRate = 0.5, -- https://docs.fivem.net/natives/?_0x085BF80FA50A39D1 (1.0 Default)
|
moveRate = 0.5, -- https://docs.fivem.net/natives/?_0x085BF80FA50A39D1 (1.0 Default)
|
||||||
},
|
},
|
||||||
present = {
|
present = {
|
||||||
model = `xm3_prop_xm3_present_01a`,
|
model = `xm_prop_x17_bag_01d`,
|
||||||
bone = 28422,
|
bone = 28422,
|
||||||
offset = vector3(0.0, -0.18, -0.16),
|
offset = vector3(0.15, -0.05, -0.10),
|
||||||
rot = vector3(0.0, 0.0, 0.0),
|
rot = vector3(100.0, -50.0, 220.0),
|
||||||
anim = {
|
anim = {
|
||||||
dict = "anim@heists@box_carry@",
|
dict = "missfbi4prepp1",
|
||||||
name = "idle"
|
n ame = "idle" -- Neutrale Stehanimation
|
||||||
},
|
}
|
||||||
disableKeys = {
|
disableKeys = {
|
||||||
21, -- INPUT_SPRINT
|
21, -- INPUT_SPRINT
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,15 +30,15 @@ exports("RegisterJobCraft", registerJobCraft)
|
||||||
-- Default crafting
|
-- Default crafting
|
||||||
registerCraft("defaultCraft", "Main Craft", {
|
registerCraft("defaultCraft", "Main Craft", {
|
||||||
{
|
{
|
||||||
giveAmount = 1,
|
giveAmount = 24,
|
||||||
name = 'testburger',
|
name = 'ecola_dose',
|
||||||
costs = {
|
costs = {
|
||||||
['testitem'] = 5,
|
['pack_ecola'] = 1,
|
||||||
['testitemuniq'] = 3,
|
|
||||||
},
|
},
|
||||||
duration = 5000, -- 5 seconds crafting times (optional)
|
duration = 5000, -- 5 seconds crafting times (optional)
|
||||||
info = {
|
info = {
|
||||||
label = "My Test Label for Burger"
|
label = "Auspacken"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
--[[
|
--[[
|
||||||
|
|
|
@ -10193,7 +10193,17 @@ QBShared.Items = {
|
||||||
image = 'pdbag.png',
|
image = 'pdbag.png',
|
||||||
name = 'pdbag',
|
name = 'pdbag',
|
||||||
},
|
},
|
||||||
|
pack_ecola = {
|
||||||
|
shouldClose = true,
|
||||||
|
type = 'item',
|
||||||
|
description = '',
|
||||||
|
weight = 1000,
|
||||||
|
label = 'Packung E-Cola',
|
||||||
|
unique = true,
|
||||||
|
useable = true,
|
||||||
|
image = 'pack_ecola.png',
|
||||||
|
name = 'pack_ecola',
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue