Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Исходник [Сурс] Warface — Отправка RMI (RequestShootHit) без прямых адресов

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
538
Реакции
14
Для тех, кто плотно копает CryEngine и сетевую часть Warface, выкладываю пример реализации отправки RMI-запросов (RequestShootHit) через расширения. Трюк в том, что нам не нужно хардкодить адреса функций, если можно заюзать нативные методы IGameObject и GetRMIExtension.

Ниже основные структуры для сериализации хитов и прожектайлов. Это база, на которой строится сетевой урон в игре.

Структуры данных запроса:
Код:
Expand Collapse Copy
struct SvRequestHit
{
    EntityId targetId;  // 0x00
    int32 material;   // 0x04
    int32 typeId;   // 0x08
    int32 partId;   // 0x0C
    Vec3 pos;    // 0x10
    f32 damageReduction; // 0x1C
    uint8 physCounter;  // 0x20

    void SerializeWith(TSerialize ser)
    {
        ser.Value(0, targetId, 'eid');
        ser.Value(0, material, 'mat');
        ser.Value(0, typeId, 'hTyp');
        ser.Value(0, partId, 'binv');
        ser.Value(0, damageReduction, 'hVal');
        ser.Value(0, pos);
        ser.Value(0, physCounter, 'ui2');
    }
};

Основной пакет SvRequestShootHit:
Включает в себя позицию выстрела, направление, разброс и контейнеры прожектайлов. Сериализация здесь критична, так как любая ошибка в типах данных приведет к десинхрону или кику от MRAC за невалидный пакет.

Код:
Expand Collapse Copy
struct SvRequestShootHit
{
    Vec3 shootPos;    // 0x00
    int32 predictionHandle;  // 0x0C
    Vec3 dir;     // 0x10
    uint8 physCounter;   // 0x1C
    std::vector<SvRequestProjectile> projectiles; // 0x20
    uint8 fireCounter;   // 0x38
    f32 spreadMax;    // 0x3C 
    bool nulled;    // 0x40
    int32 bulletType;   // 0x44

    void SerializeWith(TSerialize ser)
    {
        ser.Value(0, predictionHandle, 'phdl');
        ser.Value(0, dir, 'dir3');
        ser.Value(0, shootPos);
        ser.Value(0, physCounter, 'ui2');
        ser.Value(0, fireCounter, 'ui8');
        ser.Value(0, spreadMax, 'sprd');
        ser.Value(0, nulled, 'bool');
        ser.Value(0, bulletType);
        // ... логика сериализации вектора ...
    }
};

Механика вызова через InvokeRMI:
Вместо того чтобы искать сигнатуру функции стрельбы и прыгать по оффсетам, можно дернуть InvokeRMI у объекта предмета.

Код:
Expand Collapse Copy
void RequestShootHit(IItem* pItem, SvRequestShootHit& request)
{
    auto rmiExt = pItem->GetRMIExtension("RMI:CItemProxy:SvRequestShootHit");
    pItem->GetGameObject()->InvokeRMI(rmiExt, request, eRMI_ToServer, -1);
}

Нюансы реализации:
  1. Этот метод гораздо стабильнее при обновах игры, так как опирается на строковые идентификаторы расширений.
  2. Для корректной работы вам все равно придется восстановить классы CRMIBody и TSerialize, если вы пишете internal софт.
  3. MRAC активно чекает аномальный урон и частоту таких запросов. Если слать пакеты без реального выстрела на стороне клиента, мануалбан прилетит очень быстро.
  4. Не забывайте про physCounter — если счетчик физики не совпадет с серверным, хит просто не засчитает.

Кто ковырял последние билды — как сейчас обстоят дела с проверкой predictionHandle на стороне сервера, гайки еще сильнее закрутили?
 
Назад
Сверху Снизу