Исправление бага с «невидимками» и рассинхронизацией виртуальных миров
Один из самых старых и раздражающих багов в SA:MP/CRMP — это появление так называемых «невидимок». Игрок заходит в интерьер, на спавн или телепортируется на мероприятие, но не видит других участников, кастомные объекты (стены, двери, мебель) или машины, хотя для администраторов и по логам сервера он находится в правильном месте. Бывает и обратная ситуация: игрока убивает «невидимый» противник, который на самом деле стоит прямо перед ним.
В основе этой проблемы лежит рассинхронизация между тремя компонентами: сетевым движком самого SA:MP, функцией SetPlayerVirtualWorld и плагином Incognito Streamer. В этой статье мы разберем техническую изнанку этого бага и научимся правильно обновлять позиции игроков и зоны стрима.
Анатомия бага: Почему ломается стример?
Стандартный серверный движок SA:MP имеет жесткие лимиты на количество объектов (1000) и транспорта, которые он может одновременно отправить клиенту. Чтобы обойти это ограничение, абсолютно все современные моды используют плагин Incognito Streamer. Он постоянно отслеживает координаты каждого игрока и «подсовывает» его клиенту только те объекты, которые находятся в радиусе его видимости (Stream Distance).
Рассинхронизация и появление «невидимок» происходят из-за нарушения хронологии сетевых пакетов при резкой смене координат или виртуального мира (Virtual World). Типичный сценарий багов выглядит так:
- Скрипт вызывает функцию телепортации игрока в интерьер (изменяет координаты через
SetPlayerPosи виртуальный мир черезSetPlayerVirtualWorld). - Сервер моментально отправляет плагину Incognito Streamer сигнал: «Игрок сменил мир и позицию, обнови для него объекты!».
- Стример начинает судорожно выгружать старые объекты из памяти клиента и забывает загружать новые.
- Сбой синхронизации: Клиент игрока (сам ПК) из-за сетевой задержки (пинга) или долгого прогрузки текстур еще не успел обработать пакет о смене координат от сервера. Для клиента он все еще летит где-то в воздухе или находится на старом спавне.
- Объекты нового интерьера создаются стримером там, куда игрок еще «не долетел» по мнению его компьютера. Клиент считает эти объекты слишком далекими и просто их игнорирует. Игрок падает сквозь невидимые текстуры.
Как делать НЕЛЬЗЯ (Классический багованный код)
Большинство разработчиков используют моментальный перенос, который и рождает рассинхрон:
public OnPlayerPickUpDynamicPickup(playerid, pickupid)
{
if(pickupid == pickup_enter_ls_news)
{
SetPlayerVirtualWorld(playerid, 15);
SetPlayerInterior(playerid, 3);
SetPlayerPos(playerid, 823.12, -1324.44, 15.40);
}
return 1;
}
Правильный алгоритм: Замораживание и форсирование стрима
Чтобы гарантированно избежать багов прогрузки, профессиональная архитектура телепортации должна состоять из четырех этапов: заморозка игрока, плавная смена данных, принудительное обновление стримера (Force Update) и разморозка после сетевого отклика.
Реализация безопасной функции телепортации (Внедряем в свой мод):
stock TeleportPlayerSecure(playerid, Float:x, Float:y, Float:z, interior, virtual_world)
{
TogglePlayerControllable(playerid, false);
SetPlayerInterior(playerid, interior);
SetPlayerVirtualWorld(playerid, virtual_world);
SetPlayerPos(playerid, x, y, z);
Streamer_UpdateEx(playerid, x, y, z, virtual_world, interior, streamer_type:STREAMER_TYPE_OBJECT);
SetTimerEx("UnfreezeTeleportedPlayer", 400, false, "d", playerid);
return 1;
}
forward UnfreezeTeleportedPlayer(playerid);
public UnfreezeTeleportedPlayer(playerid)
{
if(!IsPlayerConnected(playerid)) return 1;
TogglePlayerControllable(playerid, true);
return 1;
}
Дополнительная оптимизация параметров Стримера
Сам плагин Incognito Streamer имеет файл конфигурации streamer.cfg (или настраивается через Pawn-скрипт в OnGameModeInit). По умолчанию его параметры рассчитаны на слабые сервера, что вызывает задержки прогрузки на крупных проектах.
Для моментальной прогрузки текстур и игроков добавьте в OnGameModeInit следующие настройки:
Streamer_TickRate(20);— скорость работы стримера (в миллисекундах). По умолчанию установлено 50мс. Снижение до 20мс заставит стример проверять координаты игроков чаще, что уберет задержки появления объектов перед летящим автомобилем.Streamer_SetVisibleItems(STREAMER_TYPE_OBJECT, 700);— сколько объектов стример может одновременно показать игроку. Не выставляйте больше 900, иначе лимит самого SA:MP (1000) будет превышен, и игра начнет крашиться.
Рассинхронизация транспорта и игроков («Невидимки» в ПВП)
Если с объектами все понятно, то почему становятся невидимыми сами игроки или машины? За это отвечает внутренний радиус стриминга SA:MP (он жестко зашит в клиент и равен примерно 150-200 метрам).
Если вы меняете виртуальный мир игрока слишком часто или используете динамические зоны (например, для зон каптов или интерьеров домов), движок SA:MP может посчитать, что игроки находятся в разных подмирах, даже если ID мира совпадает. Это происходит, если вы вызываете SetPlayerVirtualWorld в один и тот же тик с созданием кастомного 3D-текста или иконки.
| Тип рассинхронизации | Причина возникновения | Способ лечения |
|---|---|---|
| Провал под текстуры интерьера | Объекты не успели создаться в новом виртуальном мире к моменту падения игрока | Использование связки Streamer_UpdateEx + кратковременная заморозка (Freeze) |
| Невидимые кары / лодки | Транспорт был создан в мире 0, а затем перенесен в мир игрока без обновления стрима машин | Используйте на сервере LinkVehicleToInterior для принудительной привязки авто к интерьерам. |
| Невидимые игроки на каптах | Перегрузка сетевого канала пакетами (Packet Loss) из-за флуда функциями анимаций | Ограничьте частоту вызова циклов, проверяющих координаты игроков (не чаще 1 раза в секунду вместо каждого тика). |
Резюме: Чтобы навсегда избавить игроков от «невидимок», приучите свой игровой мод давать клиенту небольшую фору (паузу в 300-400мс) на загрузку окружения при каждом масштабном перемещении по виртуальным мирам хостинга.