Назад к блогу
Guide8 мин чтения

Система работы грузоперевозок для FiveM: скрипты дальних перевозок

Добавьте полноценную карьеру дальнобойщика на ваш сервер FiveM. Маршруты, грузы, зарплаты и лучшие скрипты для грузоперевозок в экономиках QBCore и ESX.

Agency Scripts

Основатель и ведущий разработчик Agency Scripts

Почему грузовые работы важны для экономики сервера

Работы по грузоперевозкам и доставке служат экономической основой любого FiveM ролевого сервера. Они обеспечивают надёжный источник дохода для новых игроков, которые ещё не установили связи или не нашли специализированную работу, а также создают логистическую инфраструктуру, связывающую бизнесы по всей карте. Когда ресторану нужны ингредиенты, автодилеру , транспортировка автомобилей, а строительной площадке , материалы, грузоперевозки создают мост между спросом и предложением. Хорошо продуманная система грузоперевозок превращает простую доставку из точки А в точку Б в увлекательный карьерный путь с планированием маршрутов, управлением грузом, улучшениями транспорта и решениями с учётом риска и вознаграждения при выборе более длинных, но высокооплачиваемых маршрутов через опасные территории. Работа грузоперевозчика также наполняет карту активностью, размещая крупные транспортные средства на трассах и давая полиции повод следить за нарушениями ПДД, создавая естественные ролевые взаимодействия между дальнобойщиками и правоохранителями.

Конфигурация маршрутов и система контрактов

Проектируйте систему грузоперевозок на основе модели контрактов, где водители берут задания с диспетчерской доски на грузовом депо. Каждый контракт указывает место погрузки, пункт доставки, тип груза, вес, ставку оплаты и временное ограничение. Организуйте контракты по уровням в зависимости от класса водительских прав и опыта, чтобы новички начинали с местных доставок на box trucks, а опытные перевозчики брали дальние рейсы с прицепами и опасными грузами. Система контрактов должна динамически генерировать маршруты из пула точек погрузки и доставки, а не использовать статические маршруты, которые становятся повторяющимися после нескольких рейсов:

Config.TruckingDepot = {
    location = vector3(152.29, -3210.88, 5.91),
    spawnPoint = vector4(162.45, -3207.12, 5.91, 270.0),
    returnPoint = vector3(148.77, -3215.44, 5.91),
}

Config.ContractTiers = {
    [1] = {
        label = 'Local Delivery',
        requiredLevel = 0,
        vehicle = 'mule',
        payRange = { 500, 1200 },
        timeLimit = 600,
        routes = {
            { pickup = vector3(89.54, -1745.62, 29.33),
              dropoff = vector3(-46.23, -1758.49, 29.42),
              cargo = 'electronics', weight = 500 },
            { pickup = vector3(821.77, -2160.33, 29.62),
              dropoff = vector3(-324.18, -1522.87, 27.56),
              cargo = 'food_supplies', weight = 350 },
            { pickup = vector3(-1088.34, -2002.19, 13.22),
              dropoff = vector3(1214.56, -1386.73, 35.37),
              cargo = 'clothing', weight = 200 },
        }
    },
    [2] = {
        label = 'Regional Haul',
        requiredLevel = 5,
        vehicle = 'packer',
        trailer = 'trailers',
        payRange = { 2000, 4500 },
        timeLimit = 900,
        routes = {
            { pickup = vector3(1378.22, -2078.85, 52.04),
              dropoff = vector3(-2556.14, 2334.67, 33.06),
              cargo = 'construction_materials', weight = 15000 },
            { pickup = vector3(-58.83, -2538.92, 6.07),
              dropoff = vector3(2671.84, 1678.93, 24.49),
              cargo = 'fuel_barrels', weight = 12000,
              hazardous = true },
        }
    },
    [3] = {
        label = 'Long Haul',
        requiredLevel = 15,
        vehicle = 'hauler',
        trailer = 'tanker',
        payRange = { 5000, 10000 },
        timeLimit = 1200,
        routes = {
            { pickup = vector3(2682.34, 1410.77, 24.52),
              dropoff = vector3(-1143.27, -2002.47, 13.18),
              cargo = 'refined_fuel', weight = 25000,
              hazardous = true, fragile = false },
        }
    },
}

Config.LevelXP = {
    perDelivery = 25,
    bonusOnTime = 15,
    bonusNoDamage = 20,
    penaltyLate = -10,
    penaltyCargoDamage = -15,
}

Система уровней и опыта создает прогрессию, которая удерживает водителей вовлеченными со временем. Каждая успешная доставка приносит очки опыта с бонусами за своевременное выполнение и доставку груза без повреждений. Система опыта открывает контракты более высокого уровня с лучшей оплатой, но и большей сложностью, так как более длинные маршруты проходят через более опасные районы, а большие транспортные средства сложнее управлять на узких городских улицах.

Управление автомобилями и прицепами

Грузовые автомобили требуют особого обращения по сравнению с обычными машинами игроков. При принятии контракта водителем создавайте соответствующий грузовик в точке спавна депо и прикрепляйте необходимый прицеп. Используйте AttachVehicleToTrailer для правильной физики прицепа и реализации ручной системы сцепки, где водители должны сдавать назад своим тягачом к прицепу и нажимать клавишу для сцепления. Этот ручной процесс добавляет игровой элемент, основанный на навыках, и создает приятные моменты, когда водитель идеально выполняет сложный задний ход в узкий погрузочный бокс. Тщательно отслеживайте состояние сцепления прицепа, потому что физика прицепов в GTA может отсоединять прицепы при столкновениях, и ваш скрипт должен обнаруживать это и уведомлять водителя:

local activeTrailer = nil
local trailerAttached = false

function SpawnTruckWithTrailer(vehicleModel, trailerModel, spawnPoint)
    -- Spawn truck
    local truckHash = GetHashKey(vehicleModel)
    RequestModel(truckHash)
    while not HasModelLoaded(truckHash) do Wait(10) end

    local truck = CreateVehicle(truckHash, spawnPoint.x, spawnPoint.y,
        spawnPoint.z, spawnPoint.w, true, false)
    SetVehicleNumberPlateText(truck, 'HAUL' .. math.random(100, 999))
    SetEntityAsMissionEntity(truck, true, true)
    SetModelAsNoLongerNeeded(truckHash)

    -- Spawn trailer if needed
    if trailerModel then
        local trailerHash = GetHashKey(trailerModel)
        RequestModel(trailerHash)
        while not HasModelLoaded(trailerHash) do Wait(10) end

        local trailerSpawn = GetOffsetFromEntityInWorldCoords(truck, 0.0, -8.0, 0.0)
        activeTrailer = CreateVehicle(trailerHash, trailerSpawn.x,
            trailerSpawn.y, trailerSpawn.z, spawnPoint.w, true, false)
        SetEntityAsMissionEntity(activeTrailer, true, true)
        SetModelAsNoLongerNeeded(trailerHash)

        -- Auto-attach trailer
        AttachVehicleToTrailer(truck, activeTrailer, 1.0)
        trailerAttached = true
    end

    return truck
end

-- Monitor trailer attachment status
CreateThread(function()
    while activeTrailer do
        if trailerAttached then
            local truck = GetVehiclePedIsIn(PlayerPedId(), false)
            if truck ~= 0 and not IsVehicleAttachedToTrailer(truck) then
                trailerAttached = false
                lib.notify({
                    title = 'Trailer Detached!',
                    description = 'Your trailer has come loose! Re-attach it.',
                    type = 'error'
                })
                -- Add blip to trailer location
                local trailerCoords = GetEntityCoords(activeTrailer)
                local blip = AddBlipForEntity(activeTrailer)
                SetBlipSprite(blip, 479)
                SetBlipColour(blip, 1)
                BeginTextCommandSetBlipName('STRING')
                AddTextComponentSubstringPlayerName('Detached Trailer')
                EndTextCommandSetBlipName(blip)
            end
        end
        Wait(1000)
    end
end)

Отслеживание повреждений и состояния груза

Состояние груза добавляет значимый игровой элемент в каждую доставку. Отслеживайте здоровье груза на основе ударов, скорости при проезде неровностей и стиля вождения на протяжении всего маршрута. Когда грузовик сталкивается с объектами или другими транспортными средствами, рассчитывайте степень удара, используя изменение скорости автомобиля, и применяйте пропорциональные повреждения к грузу. Хрупкий груз, такой как электроника или стекло, получает серьёзные повреждения от незначительных ударов, в то время как прочный груз, например строительная сталь, почти не реагирует на удары. Отображайте здоровье груза в процентах на Agency HUD, чтобы водители могли видеть последствия своего вождения в реальном времени. Пропорционально уменьшайте итоговую выплату в зависимости от повреждений груза и устанавливайте минимальный порог, ниже которого доставка полностью проваливается из-за уничтожения груза. Эта механика естественным образом стимулирует аккуратное вождение без искусственных ограничений скорости, позволяя водителям самостоятельно оценивать риск и выгоду: ехать быстро, чтобы уложиться в лимит времени, или ехать осторожно, чтобы сохранить состояние груза.

GPS навигация и отображение маршрута

Обеспечьте дальнобойщиков специализированной GPS-системой, учитывающей размер транспорта при расчёте маршрутов. Стандартные точки GTA ведут игроков через узкие переулки и низкие мосты, которые тягач с прицепом не может проехать. Замените стандартную навигацию на пользовательские маркеры маршрута, которые следуют дорогам, удобным для грузовиков, избегают резких поворотов и предупреждают водителей о предстоящих препятствиях. Отображайте маршрут в виде серии контрольных точек на миникарте с индикаторами расстояния до следующей точки и показывайте предполагаемое время прибытия на основе текущей скорости. Добавьте механику расхода топлива, завязанную на пройденное расстояние и вес транспорта, чтобы водители планировали остановки для заправки на дальних рейсах, создавая дополнительные точки принятия решений в пути:

function CreateTruckRoute(pickupCoords, dropoffCoords)
    -- Clear previous route
    ClearGpsMultiRoute()

    -- Set up checkpoint blips along the route
    local checkpoints = CalculateTruckFriendlyRoute(pickupCoords, dropoffCoords)

    for i, checkpoint in ipairs(checkpoints) do
        local blip = AddBlipForCoord(checkpoint.x, checkpoint.y, checkpoint.z)
        SetBlipSprite(blip, 1)
        SetBlipScale(blip, 0.6)
        SetBlipColour(blip, i == #checkpoints and 5 or 3)
        SetBlipAsShortRange(blip, true)
        table.insert(routeBlips, blip)
    end

    -- Set final destination waypoint
    SetNewWaypoint(dropoffCoords.x, dropoffCoords.y)

    -- Start GPS multi-route display
    StartGpsMultiRoute(6, true, true)
    for _, cp in ipairs(checkpoints) do
        AddPointToGpsMultiRoute(cp.x, cp.y, cp.z)
    end
    SetGpsMultiRouteRender(true)
end

Весовые станции и инспекции

Добавьте весовые станции вдоль основных автомагистралей, где дальнобойщики должны останавливаться для проверки груза. Этот механизм создаёт естественные точки взаимодействия на длинных маршрутах и открывает возможности для ролевого взаимодействия между дальнобойщиками и инспекторами DOT, которые могут быть NPC или игроками с должностью в транспортном управлении. На весовой станции проверяйте общий вес грузовика на соответствие законодательным нормам, сверяйте грузовую накладную с загруженным грузом и осматривайте состояние транспортного средства. Перегруженные грузовики получают штрафы, уменьшающие прибыль от доставки, стимулируя водителей соблюдать нормы. Если на вашем сервере есть полиция, предоставьте офицерам возможность проводить дорожные проверки с аналогичными проверками, создавая естественные встречи с правоохранителями без необходимости преступлений. Соблюдение правил весовых станций добавляет ещё один уровень реализма, который по-настоящему ценят преданные дальнобойщики, так как это подтверждает их серьёзное отношение к роли.

Мультиплеерная система конвоев

Разрешить нескольким дальнобойщикам формировать конвои для групповых доставок с бонусом за каждого участника. Лидер конвоя принимает специальный мульти-грузовой контракт, который генерирует связанные доставки в одну и ту же зону назначения. Участники конвоя используют общий радиоканал для координации, видят позиции друг друга на миникарте с особыми метками конвоя и получают бонус за близость при движении на разумном расстоянии друг от друга. Это стимулирует социальный геймплей и создает впечатляющие визуальные моменты, когда колонна грузовиков движется по шоссе вместе. Реализовать индикатор формирования конвоя, показывающий позицию каждого участника в колонне и выделяющий тех, кто отстал или свернул не туда. Бонус за конвой должен быть достаточно значительным, чтобы мотивировать объединяться, обычно на 20-30% выше, чем одиночные рейсы, что делает ожидание других водителей выгоднее немедленного отъезда в одиночку.

Производительность и меры по предотвращению эксплойтов

Системы грузоперевозок создают крупные транспортные средства с высокой нагрузкой на рендеринг, поэтому тщательно управляйте их жизненным циклом. Удаляйте грузовик и прицеп сразу после завершения или провала доставки, не оставляя их на карте. Если водитель отключается во время доставки, очищайте созданные транспортные средства на стороне сервера и отмечайте контракт как заброшенный. Предотвращайте эксплойты с телепортацией, отслеживая позицию грузовика с регулярными интервалами и проверяя, что он следует правдоподобному маршруту от точки загрузки до разгрузки, помечая доставки, где транспортное средство преодолело невозможные расстояния между проверками. Ограничивайте скорость принятия контрактов, чтобы предотвратить быстрое принятие и отмену для выбора самых высокооплачиваемых маршрутов. Храните статистику доставок по игрокам для таблиц лидеров и достижений, но записывайте данные в базу пакетами по таймеру, а не после каждого контрольного пункта, чтобы минимизировать нагрузку на базу данных в часы пик, когда одновременно активны многие водители.

Готовы начать?

Возьмите скрипты в нашем магазине или заходите в Discord за поддержкой, обновлениями и анонсами.