Виправлення багу з «невидимками» та розсинхронізацією віртуальних світів
Один із найстаріших і найдратівливіших багів у 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мс) на завантаження оточення при кожному масштабному переміщенні віртуальними світами хостингу.