Гайд API SF | Урок 4 - RakNet

Тема в разделе "C/C++", создана пользователем CleanLegend, 8 авг 2018.

Статус темы:
Закрыта.
  1. CleanLegend

    Всефорумный модератор

    Регистрация:
    28 мар 2013
    Сообщения:
    259
    Симпатии:
    306
    Введение
    RakNet — это сетевой движок, используемый в SA:MP для обмена данными между игроками и сервером. Клиент отправляет пакет серверу, сервер его обрабатывает и рассылает другим игрокам — таким образом это работает.

    В этом уроке я покажу, как отправлять свои пакеты и заносить в них данные, как перехватывать отправляемые/получаемые пакеты и читать и перезаписывать данные.

    Отправка пакетов
    Пример отправки пакета ID_PLAYER_SYNC:

    stOnFootData sync; // объявляем объект структуры stOnFootData, в которой хранятся данные.
    memset( &sync, 0, sizeof( stOnFootData ) ); // обнуляем его.
    
    sync = SF->getSAMP()->getPlayers()->pLocalPlayer->onFootData; // копируем данные из структуры локального игрока.
    
    sync.byteHealth = 100; // записываем значение числа жизней ( к примеру ).
    
    BitStream bsActorSync; // объявляем объект класса BitStream, в котором хранятся пакетные данные.
    bsActorSync.Write( ( BYTE ) ID_PLAYER_SYNC ); // записываем ID пакета.
    bsActorSync.Write( ( PCHAR ) &sync, sizeof( stOnFootData ) ); // записываем данные из структуры sync
    SF->getRakNet()->SendPacket( &bsActorSync ); // отправляем пакет на сервер.
    RPC (Remote Procedure Call) — оболочка пакета ID_RPC, предназначенная для удалённого выполнения определенных событий. Все RPC перечислены в RPCEnumeration и ScriptRPCEnumeration.

    Пример использования RPC_RequestClass, который запрашивает у сервера сменить наш класс (скин) на сервере:

    void CALLBACK cmd_setclass( std::string param ) // объявляем чат-команду /setclass <id>
    {
       BitStream bsClass; // объявляем объект класса BitStream, в котором хранятся пакетные данные.
       bsClass.Write( std::stoi( param ) ); // записываем в него ID переданный в команду.
       SF->getRakNet()->SendRPC( RPC_RequestClass, &bsClass );    // отправляем RPC
    };
    SF->getSAMP()->registerChatCommand( "setclass", cmd_setclass );    // регистрируем команду
    Перехват пакетов
    Средствами API можно установить четыре вида перехватов:

    1. RAKHOOK_TYPE_OUTCOMING_RPC — RPC, отправленный серверу;
    2. RAKHOOK_TYPE_OUTCOMING_PACKET — пакет, отправленный серверу;
    3. RAKHOOK_TYPE_INCOMING_RPC — RPC, пришедший от сервера;
    4. RAKHOOK_TYPE_INCOMING_PACKET — пакет, пришедший от сервера.
    Пример перехвата отправляемого пакета ID_PLAYER_SYNC:

    bool CALLBACK outcomingData( stRakNetHookParams *params ) // определение callback-функции, которая будет вызвана при отправке какого либо пакета
    {
       if( params->packetId == PacketEnumeration::ID_PLAYER_SYNC ) // если отправляемый пакет — это ID_PLAYER_SYNC
       {
           stOnFootData data; // определяем объект, в который сохраним отправляемые данные
           memset( &data, 0, sizeof( stOnFootData ) ); // обнуляем его
           byte packet;
    
           params->bitStream->ResetReadPointer(); // на всякий случай устанавливаем оффсет чтения на начало
           params->bitStream->Read( packet ); // читаем ID пакета
           params->bitStream->Read( (PCHAR)&data, sizeof( stOnFootData ) ); // читаем отправляемые данные
           params->bitStream->ResetReadPointer(); // снова обнуляем оффсет чтения
    
           SF->getSAMP()->getChat()->AddChatMessage( D3DCOLOR_XRGB( 255, 255, 0 ), "Наша скорость: %.2f %.2f %.2f",
               data.fMoveSpeed[0], data.fMoveSpeed[1], data.fMoveSpeed[2] ); // пишем в чат скорость нашего передвижения, записанную в пакет
    
                   data.fMoveSpeed[0] = rand()%10;
           data.fMoveSpeed[1] = rand()%10;
           data.fMoveSpeed[2] = rand()%10; // перезаписали скорость на случайную; получается эффект, похожий на Pizdarvanka.
    
           params->bitStream->ResetWritePointer(); // обнуляем оффсет записи
           params->bitStream->Write( packet ); // пишем ид пакета
           params->bitStream->Write( (PCHAR)&data, sizeof( stOnFootData ) ); // пишем обновлённые данные  
       };
    
       return true; // успешно завершаем отправку пакета
    };
    
    SF->getRakNet()->registerRakNetCallback( RakNetScriptHookType::RAKHOOK_TYPE_OUTCOMING_PACKET, outcomingData ); // регистрируем callback
    Пример перехвата входящего (пришедшего от сервера) RPC_ScrServerJoin:

    bool CALLBACK incomingRPC( stRakNetHookParams *params ) // определение callback-функции, которая будет вызвана, если от сервера был получен новый RPC.
    {
       if( params->packetId == ScriptRPCEnumeration::RPC_ScrServerJoin ) // если это RPC_ScrServerJoin
       {
           short int sPlayerID;  
           D3DCOLOR D3DPlayerColor;
           byte isNPC, nameLen;
           char szPlayerName[25];
    
           params->bitStream->ResetReadPointer(); // обнуляем оффсет чтения.
           params->bitStream->Read( sPlayerID ); // читаем ID игрока.
           params->bitStream->Read( D3DPlayerColor ); // цвет ника игрока.
           params->bitStream->Read( isNPC ); // флаг, говорящий о том, NPC это или нет.
           params->bitStream->Read( nameLen ); // длина ника.
           params->bitStream->Read( szPlayerName, nameLen ); // ник.
           szPlayerName[ nameLen ]= '\0'; // обрезаем, чтоб не было мусора
           params->bitStream->ResetReadPointer(); // обнуляем оффсет чтения
    
           SF->getSAMP()->getChat()->AddChatMessage( D3DPlayerColor, "%s[%d] Подключился к серверу.",
               szPlayerName, sPlayerID ); // добавляем сообщение в чат.          
       };
    
       return true; // успешно завершаем обработку RPC.
    };
    
    SF->getRakNet()->registerRakNetCallback( RakNetScriptHookType::RAKHOOK_TYPE_INCOMING_RPC, incomingRPC ); // регистрируем callback
    Автор: urShadow
     
  2. x3wt

    x3wt Интересующийся

    Регистрация:
    25 июн 2018
    Сообщения:
    190
    Симпатии:
    56
    Продолжать будешь?
     
  3. SR_team

    SR_team BH Team
    BH Team

    Регистрация:
    26 окт 2013
    Сообщения:
    3.179
    Симпатии:
    3.086
    Нахуй ты это из вики сюда скопипастил?
     
  4. FYP

    FYP
    not-set

    Регистрация:
    9 мар 2013
    Сообщения:
    1.584
    Симпатии:
    4.110
    перенёс их на форум, как и с гайдами по клео
     
  5. Dark_Knight

    Dark_Knight Режим чтения

    Регистрация:
    18 мар 2013
    Сообщения:
    3.364
    Симпатии:
    1.678
    Смысл в чем-то? Мы же всегда в темах направляли на вики же с подобными вопросами.
     
  6. FYP

    FYP
    not-set

    Регистрация:
    9 мар 2013
    Сообщения:
    1.584
    Симпатии:
    4.110
    смысл несложно придумать, но мы-то прекрасно знаем, что на этом форуме всё делается исключительно ради лайков.
     
    Lupus нравится это.
  7. Dark_Knight

    Dark_Knight Режим чтения

    Регистрация:
    18 мар 2013
    Сообщения:
    3.364
    Симпатии:
    1.678
    И вот такое лучше пресекать на корню и вырезать это, как раковую опухоль.
     
  8. CleanLegend

    Всефорумный модератор

    Регистрация:
    28 мар 2013
    Сообщения:
    259
    Симпатии:
    306
    Это было сделано в целях развития раздела. На wiki уже давно держится оповещение о переносе, перед переносом спросил у Фипа насчет этого, он дал добро.
    [​IMG]
     
Статус темы:
Закрыта.