FiveM: настройка спавнов и системы возрождения
Игрок умирает в перестрелке, жмёт «Возродиться» — и оказывается либо голым в чистом поле без единого предмета, либо мгновенно на ногах у той же точки, будто ничего не было. Оба варианта убивают RP: первый бесит игроков технически, второй убивает саму идею смерти как последствия. Разберём, как собрать нормальную цепочку «смерть → больница → штраф → возрождение», которая работает на ESX и QBCore и не разваливается при большом онлайне.
Содержание
Как вообще устроен спавн в FiveM
Базовый механизм спавна в FiveM держится на ресурсе spawnmanager — он идёт в стандартном наборе большинства сборок и отвечает за то, что происходит с игроком в момент коннекта или возрождения. Ключевые exports, с которыми вы будете работать:
-- отключаем автоспавн, чтобы фреймворк сам решал, где заспавнить игрока
exports.spawnmanager:setAutoSpawn(false)
-- задаём точку и коллбэк для конкретного спавна
exports.spawnmanager:spawnPlayer({
x = -269.4, y = -955.3, z = 31.2, heading = 205.0,
model = `mp_m_freemode_01`
}, function()
TriggerEvent('playerSpawned')
end)
Важный момент: если setAutoSpawn(true) — spawnmanager сам выберет случайную точку из встроенного списка стандартных локаций GTA V, и вы получите спавн где попало (иногда в океане или на крыше). На RP-сервере это почти всегда не то, что нужно — отключайте автоспавн и передавайте координаты вручную.
Фреймворки (ESX, QBCore) оборачивают spawnmanager своей логикой: ESX слушает событие esx:onPlayerSpawn/esx:playerLoaded, QBCore — QBCore:Client:OnPlayerLoaded и QBCore:Client:OnGameEventTriggered для смерти. Если пишете кастомную систему спавна с нуля, отталкивайтесь от этих событий, а не от сырых GTA-нативов напрямую — фреймворк уже решает половину проблем с загрузкой персонажа и синхронизацией позиции.
Если сервер только разворачивается, сначала убедитесь, что база стоит и работает штатно — этот гайд предполагает, что у вас уже пройдена установка FiveM-сервера с нуля и выбран фреймворк, будь то ESX или QBCore — команды и таблицы ниже написаны под оба, но имена полей отличаются.
Возрождение в больнице: базовая механика ESX/QBCore
Стандартный сценарий RP-сервера — смерть от урона переводит персонажа в состояние "без сознания" (ragdoll/лежит), включается обратный отсчёт, а по истечении таймера или при подходе медика игрок либо возрождается на месте, либо телепортируется в больницу. За это отвечают esx_ambulancejob на ESX и qb-ambulancejob на QBCore — оба ресурса хранят точки больниц в config.lua.
Пример конфига точки больницы (структура похожа в обоих фреймворках, отличаются только имена таблиц):
Config.Hospitals = {
['pillbox'] = {
label = 'Pillbox Hospital',
blip = { x = 298.7, y = -584.9, z = 43.3 },
spawn = vector4(298.7, -584.9, 43.3, 70.6), -- дефолтная точка возрождения
cam = { x = 298.9, y = -589.3, z = 44.0 },
},
}
Координаты — это стандартная точка входа в Pillbox Hospital, которая кочует почти во всех дефолтных сборках ESX/QBCore; если у вас кастомная MLO-карта больницы, замените их на реальный вход своей модели.
Логика возрождения на сервере обычно выглядит так:
RegisterNetEvent('hospital:server:revivePlayer', function()
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
TriggerClientEvent('hospital:client:revive', src, Config.Hospitals['pillbox'].spawn)
-- штраф и лечение — см. следующий раздел
end)
На клиенте возрождение — это снятие ragdoll-флага, восстановление здоровья и телепорт нативами NetworkResurrectLocalPlayer и SetEntityCoords:
RegisterNetEvent('hospital:client:revive', function(coords)
local ped = PlayerPedId()
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, coords.w, true, false)
SetEntityHealth(ped, 200)
ClearPedBloodDamage(ped)
DoScreenFadeIn(1000)
end)
Обратите внимание на ClearPedBloodDamage — без неё персонаж возрождается со старыми ранами и кровью на текстуре, что смотрится странно после "лечения" в больнице.
Поднять сервер FiveM (GTA V) за пару минут
Готовый образ MAATRIX GAMES: NVMe, AMD EPYC, DDoS-защита, панель управления. Локации UK, US, RU. Оплата картой РФ, СБП или криптой.
Создать серверШтраф за респавн: деньги, время, предметы
Смерть без последствий обесценивает весь RP — если умереть ничего не стоит, никто не боится перестрелок и не пытается их избегать. Рабочая система штрафа обычно комбинирует три рычага, и не обязательно включать все сразу:
- Денежный штраф (медицинский счёт). Списывается с банковского счёта при возрождении — символизирует оплату лечения.
- Таймер возрождения. Игрок не может нажать "Возродиться" сразу, а ждёт отсчёт — это и есть цена смерти во времени, а не только в деньгах.
- Потеря предметов/оружия. Часть инвентаря или всё оружие сбрасывается на месте смерти либо конфискуется — сильнее всего ощущается в PvP-ориентированных RP.
RegisterNetEvent('hospital:server:revivePlayer', function()
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
local medBill = 500 -- сумму подбирайте под свою экономику
if xPlayer.getAccount('bank').money >= medBill then
xPlayer.removeAccountMoney('bank', medBill)
else
-- денег не хватает — не блокируем возрождение, но фиксируем долг
xPlayer.setMeta('medDebt', (xPlayer.getMeta('medDebt') or 0) + medBill)
end
TriggerClientEvent('hospital:client:revive', src, Config.Hospitals['pillbox'].spawn)
end)
Таймер обычно реализуют на клиенте — NUI-оверлей с обратным отсчётом и заблокированными контролами, пока игрок "без сознания":
CreateThread(function()
local timer = Config.RespawnTimer -- держите в районе 20-90 секунд, это не готовая цифра, подбирайте под темп RP
while timer > 0 do
Wait(1000)
timer -= 1
SendNUIMessage({ action = 'updateTimer', time = timer })
end
SendNUIMessage({ action = 'showRespawnButton' })
end)
Ориентируйтесь не на абсолютную сумму штрафа, а на долю от типичного заработка на сервере — этот же принцип разбирался в статье про штрафы ГИБДД и баланс экономики: если штраф за смерть равен часовой зарплате, игроки будут избегать риска патологически; если это мелочь — смерть перестаёт что-то значить.
Кастомные точки спавна для разных фракций
На развитом RP-сервере не у всех должна быть одна точка возрождения. Полиция логично возрождается у участка, банда — на своей территории, гражданский персонаж — у стандартной больницы. Это не только про иммерсивность: если у вас фракции враждуют за территорию, единая точка спавна превращает больницу в спавн-килл зону.
Конфиг с точками по фракциям:
Config.FactionSpawns = {
['police'] = vector4(441.8, -981.4, 30.6, 90.0),
['ambulance'] = vector4(294.6, -584.6, 43.2, 70.0),
['ballas'] = vector4(-91.2, -1616.9, 26.2, 210.0),
['default'] = vector4(298.7, -584.9, 43.3, 70.6),
}
function GetFactionSpawn(job)
return Config.FactionSpawns[job] or Config.FactionSpawns['default']
end
Серверная сторона при возрождении подставляет нужную точку в зависимости от job.name игрока (ESX) или PlayerData.job.name (QBCore):
RegisterNetEvent('hospital:server:revivePlayer', function()
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
local spawn = GetFactionSpawn(xPlayer.job.name)
TriggerClientEvent('hospital:client:revive', src, spawn)
end)
Если фракции нелегальные (банды, картели) и завязаны на систему территорий, точку спавна логично привязывать не к статичным координатам в конфиге, а к текущей "домашней" зоне банды — это уже требует связки со системой фракций и банд, где территория хранится в базе и может переходить от одной группировки к другой. В таком случае GetFactionSpawn стоит превратить в запрос к базе, а не в статичную таблицу.
Отдельно продумайте PvP-балансировку: если банда контролирует территорию и там же возрождается после смерти, противник может держать точку под прицелом и фармить respawn kill. Частое решение — временная неуязвимость на 3-5 секунд после спавна или невидимость до первого движения игрока.
Экран выбора персонажа и первый спавн после захода
Первый спавн (не после смерти, а после захода на сервер или выбора персонажа в esx_multicharacter/qb-multicharacter) — отдельный случай. Для нового персонажа нужна точка "по умолчанию", для существующего — последняя сохранённая позиция из базы.
В таблице users (ESX) или players (QBCore) обычно есть поле position (JSON с координатами). Логика:
local function GetSpawnForCharacter(xPlayer)
local savedPos = xPlayer.get('position') -- уже распарсенный JSON, если персонаж не новый
if savedPos and savedPos.x then
return savedPos
end
return Config.FactionSpawns['default'] -- новый персонаж — стандартная точка
end
Частая ошибка на этом этапе — телепортировать игрока в сохранённые координаты до того, как загрузился мир вокруг (стрим-зона ещё не подгружена). Персонаж проваливается сквозь текстуры или зависает в воздухе. Решается ожиданием коллизии перед финальным спавном:
local function SafeTeleport(coords)
RequestCollisionAtCoord(coords.x, coords.y, coords.z)
local timeout = GetGameTimer() + 5000
while not HasCollisionLoadedAroundEntity(PlayerPedId()) and GetGameTimer() < timeout do
Wait(50)
end
SetEntityCoords(PlayerPedId(), coords.x, coords.y, coords.z, false, false, false, true)
end
Таймаут в 5 секунд — защита от вечного цикла, если коллизия по какой-то причине не подгрузится; реальное время загрузки у игроков разное.
Частые баги спавна и как их лечить
| Симптом | Вероятная причина | Что проверить |
|---|---|---|
| Игрок падает сквозь карту при спавне | Коллизия не успела загрузиться | Добавить RequestCollisionAtCoord + ожидание перед телепортом |
| Спавн под текстурой/в объекте | Координаты не совпадают с актуальной MLO-картой | Свериться с реальным входом в модель, а не с дефолтными координатами из другого конфига |
| Персонаж завис в чёрном экране после возрождения | DoScreenFadeIn не вызван или коллбэк spawnmanager отвалился с ошибкой | Проверить консоль на клиенте (F8) на предмет Lua-ошибок в цепочке спавна |
| Респавн срабатывает дважды подряд | Событие playerSpawned/revivePlayer триггерится и клиентом, и сервером без проверки состояния | Добавить флаг "уже возрождается" и игнорировать повторные вызовы, пока флаг не сброшен |
| Игрок возрождается не у своей фракции, а в дефолтной точке | job.name ещё не подгружен на момент спавна (гонка при первом заходе) | Дождаться полной загрузки xPlayer/PlayerData перед вызовом GetFactionSpawn |
| Штраф списывается, а возрождение не происходит | Ошибка в серверном обработчике до TriggerClientEvent обрывает цепочку | Обернуть списание денег в pcall или проверку и не блокировать сам ивент возрождения |
Если баги спавна усиливаются именно при заполненном сервере — это уже смежная тема нагрузки и десинхронизации ресурсов, а не логики спавна как таковой.
Поднять сервер FiveM (GTA V) за пару минут
Готовый образ MAATRIX GAMES: NVMe, AMD EPYC, DDoS-защита, панель управления. Локации UK, US, RU. Оплата картой РФ, СБП или криптой.
Создать серверЧастые вопросы
Можно ли сделать разное время респавна для разных фракций?
Да, просто храните таймер не как единую константу, а как поле в той же таблице Config.FactionSpawns или в конфиге job'а — например, у медиков (которые и так постоянно рискуют) таймер короче, чем у гражданских.
Стоит ли делать точку возрождения случайной из нескольких вариантов?
Для больницы обычно нет смысла — игроки привыкают к одной точке и это часть RP-идентичности локации. А вот для нелегальных фракций без официальной "базы" рандом между несколькими явками снижает спавн-килл.
Как сделать, чтобы админы возрождались без штрафа и таймера?
Проверяйте xPlayer.getGroup() (ESX) или пермишены ACE перед списанием денег и запуском таймера — если группа admin/superadmin, просто пропускайте эти шаги в обработчике.
Что делать, если после обновления фреймворка (ESX Legacy, QBCore) спавн перестал работать?
Сверьте актуальные названия событий и экспортов в changelog обновления — между версиями меняются имена ивентов (esx:onPlayerSpawn вместо старого esx:onPlayerLoaded в некоторых форках), и кастомный код на старых именах просто перестаёт триггериться без ошибок в консоли.
Нужен ли отдельный ресурс для системы спавна или писать всё в death-скрипте?
Для маленького сервера можно держать в одном ресурсе вместе со смертью/лечением. При росте функционала (фракции, кастомные больницы, VIP-точки) стоит вынести спавн в отдельный ресурс — проще дебажить и обновлять независимо от остальной ambulance-логики.