Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
RakNet. На версии SAMP 0.3.7
Кратко и понятно о движке и его использовании в собейте и сампфункц!
И так RakNet это сетевой движок для связи клиента с сервером и наоборот. Общаются они с помощью обычных пакетов и RPC.
Для понятности, представим себе посылку, которую мы будем отправлять.
Как и обычная посылка, пакет должен иметь свой ID. Например это будет ID_PLAYER_SYNC он равен 207. В нём будут такие параметры как позиция игрока, скорость и другие, вот полная структура:
Прежде чем отправить эту посылку нужно заполнить её вот этой структурой, запишем позицию скорость и здоровье, остальное оставим по нулям. Чтоб не записывать в каждое поле ноль можно просто написать после обьявления структуры ZeroMemory(&название вашей струкуты, sizeof(stOnFootData));
Вот мы обьявили структуру как data, обнулили все значения(*образно*) и записали в позицию координаты Groove Street а в скорость записали ускорение в сторону поворота игрока(небольшое чтоб было заметней нужно домножить на 10 и поднять педа, тоесть data.fPosition[2]+=1.5)
Так же есть fQuaternion, это такая вещь, что то типа замены матрицы, которая отвечает за поворот игрока.
Тут я не буду обьяснять как перевести матрицу поворота в кватернион, но возможно в скором будущем обьясню.
Ну вот мы подготовили груз к отправке теперь его нужно положить в коробку. Коробка это выражение образное ,на самом деле в RakNet это последовательность битов(байтов) так называемый BitStream.
Создаём битстрим строчкой <BitStream bs;>
И так, как говорилось ранее сначало нужно записать ID нашего пакета, тоесть ID_PLAYER_SYNC, делается это просто <bs.Write((BYTE)ID_PLAYER_SYNC);>
Записали в битстрим байт с идом пакета, затем записываем всю структуру, так называемый груз который мы подготавливали ранее. Выглядит это таким образом <bs.Write((PCHAR)&data, sizeof(stOnFootData));>
Ну вот как говорится и рыбку сьели и на хуй сели, теперь можно отправлять наш пакет на сервер, делается это так: <g_RakClient->Send(&bs);> (в случае собейта) а если у вас сф, то делается это так <SF->getRakNet()->SendPacket(&bsOnfootSync);>
И на выходе вы получите такую картину:
~Не обращайте на приставку LQ_ внимания, это обозначение битстрима в LiquidMod в который я это решил пихнуть, у вас же будет просто BitStream.~
Но что же произойдёт после того как мы отправили пакет? Ну начнём с того что отправим мы его один раз, а пакеты PLAYER_SYNC отправляются довольно часто самим самп клиентом, примерно каждую секунду когда вы стоите, и очень быстро когда двигаетесь. Но на выходе вы получите быстрый телепорт на грув с ускорением в сторону которую вы смотрите и телепорт обратно. (!Важная инфа) Синхра она на то и синхра что вы её не видите, увидят этот телепорт только остальные люди!
RakNet хуки!
Как вы уже знаете, пакеты не только исходят от нас но и приходят к нам, всё тот же PLAYER, BULLET, VEHICLE и т.д и мы их уже умеем отправлять НО! Что если мы хотим не отправлять пакеты сами, а заменять те которые уже исходят от нас? В этом нам помогут хуки!
Хук исходящей синхры.
~Для тех у кого сф пример будет потом, наберитесь терпения~
В собейте(mod_sa на 0.3.7 R1-R2 etc.) есть уже готовый хук исходящей синхры, он находится в файле cheat_samp.cpp и является функцией bool OnSendPacket(BitStream *parameters, PacketPriority priority, PacketReliability reliability, char orderingChannel){ … }
И так всякий раз когда мы отправляем пакет, в собейте вызывается функция OnSendPacket
Ловится битстрим, как мы говорили в прошлом примере коробка и выполняются некие действия с ними. Рассмотрим простой пример GhostMod, когда другие игроки смогут проходить сквозь нас. Принцип простой: Ловим пакет, заменяем параметр byteSpecialAction на 3. И так начнём.
Для начала узнаем какой пакет у нас отловился, для этого пишем <parameters->ResetReadPointer();
parameters->Read(packetId);>
ResetReadPointer обозначает то что мы сдвинули указатель чтения пакета в 0, это можно сравнить с курсором в текстовом редакторе.
Теперь после обнуления перед курсором стоит ид пакета, после прочтения которого, «курсор»
сдвинется за него. Далее мы проверяем если ид пакета равен 207 (ID_PLAYER_SYNC) то начинаем редактировать.
Чтоб не читать всё подряд то нужного нам значения, мы поставим нужный нам сдвиг байтов, тоесть переместим его сами. Для этого есть функция SetReadOffset(int offset). Чтоб узнать на каком оффсете расположен byteSpecialAction нужно посчитать сколько было байт информации до него. Я этого делать не буду так как у меня есть сосчитаные оффсеты, которые я приложу к данному «гайду».
И так оффсет у нас равен 37, пишем parameters->SetReadOffset(37);
Отлично, мы сдвинули курсор в нужное нам место, теперь картина выглядит примерно вот так:
Можно прочитать byteSpecialAction в какую нибудь переменную например:
uint8_t sAction;
parameters->Read(sAction);
Но нам же нужно просто заменить?
Тогда делаем parameters->SetWriteOffset(37);
WriteOffset это уже курсор записи, а не чтения.
Запись выглядит так, будто был нажат Insert поэтому после записи какого то значения, остальное не сдвинется а заменится тем что вводили. И так поставили мы оффсет теперь parameters->Write((uint8_t)3);
Отлично! Мы заменили наше значение, теперь отпускам пакет на свободу return true;
Получилось примерно следущее:
А теперь главный вопрос: Как же быть с SF?
А всё очень просто, мы просто создадим такую же функу как в собейте.
Сначала регистрируем коллбэк функи в mainloop (там где вся инициализация)
SF->getRakNet()->registerRakNetCallback( RakNetScriptHookType::RAKHOOK_TYPE_OUTCOMING_PACKET, OnSendPacket );
Затем создаём функу
bool CALLBACK outcomingData( stRakNetHookParams *params ){
}
Теперь у нас есть удобная структурка в отличии от собейта где мы сразу можем достать ид пакета, вот так: if(params->packetId == ID_PLAYER_SYNC){ … }
Битстрим идёт отдельно как params->bitStream НО! В нём по прежднему лежит пакет айди, не стоит думать что он отдельно! Дальше всё происходит так же только вместа parameters мы пишем params->bitStream
Хук входящей синхры.
Как я уже говорил, пакеты идут не только от нас, но и к нам! Поэтому логично тебе подумать что входящие пакеты тоже можно ловить. И да, это так! Можно стопануть например унок синхру(она нужна для синхронизации пустых машин, исходят когда ты толкаешь машину) и пояснить за позицию например.
Чтобы не ебаться лишний раз с оффсетами мы прочитаем всю структуру разом. Функа для хука входящих пакетов в собейте находится в файле cheat_samp.cpp и является функцией bool OnReceivePacket(Packet *p){...}
Для начала получим пакет айди, он находится в p->data[0] и проверяем
if(p->data[0] == ID_UNOCCUPIED_SYNC){ … }
Затем нам нужно из пакета получить битстрим, делаем это так: BitStream bsUnoData((unsigned char *)p->data, p->length, false);
Получили битстрим затем читаем его в структуру UnoData(назвать можно как угодно хоть huimorzha)
stUnoccupiedData UnoData;
bsUnoData.IgnoreBits(8);
bsUnoData.Read(playerId);
bsUnoData.Read((PCHAR)&UnoData, sizeof(stUnoccupiedData));
Теперь просим пакет пояснить за позицию которую он шлёт, делается это так
if(UnoData.fPosition[2] > 20000 || UnoData.fPosition[2] < -20000){
return false;
}
проверяем если позиция больше 20000 или меньше -20000 значит пакет плохой и тот кто его отправил юзает крашер и хочет нас крашнуть. Значит нам нужно как то игнорировать этот пакет, тоесть не пустить его к нам в клиент дабы избежать краша. Можно просто написать return false; а можно написать p->data[0] = 255; что в принципе даст одно и тоже.
Что же делать в SF? Ну тут опять же всё просто, регистрируем коллбэк в mainloop инициализации:
SF->getRakNet()->registerRakNetCallback( RakNetScriptHookType::RAKHOOK_TYPE_INCOMING_PACKET, OnRecivePacket );
И создаём функу приёма пакета.
bool CALLBACK OnRecivePacket( stRakNetHookParams *params ){
...
}
Далее всё делается ещё проще, битстрим лежит всё там же в params->bitStream и пакет айди тоже. Читаем как исходящий а чтоб не пустить его, так же как в исходящем пишем return false;
На этом по ракнету у меня всё, RPC лень писать, возможно мне припрёт и я напишу про них, удачного кодинга вашего собейта/сфплагина
с вами был zH.F11GAR0
Thanks to:
FYP – for SF and mod_sa source
MasterZero – for motivation to make cheats
GH0ST – for help with sobeit and c++
DR8GUN8V – for testing my shit
0pc0d3r – for good nastroenie and motivation to reverce injenering shit and (?)
Zeta-Hack team – for motivation to fuCK SAMP JAJAJA
Кратко и понятно о движке и его использовании в собейте и сампфункц!
И так RakNet это сетевой движок для связи клиента с сервером и наоборот. Общаются они с помощью обычных пакетов и RPC.
Для понятности, представим себе посылку, которую мы будем отправлять.
Как и обычная посылка, пакет должен иметь свой ID. Например это будет ID_PLAYER_SYNC он равен 207. В нём будут такие параметры как позиция игрока, скорость и другие, вот полная структура:
Прежде чем отправить эту посылку нужно заполнить её вот этой структурой, запишем позицию скорость и здоровье, остальное оставим по нулям. Чтоб не записывать в каждое поле ноль можно просто написать после обьявления структуры ZeroMemory(&название вашей струкуты, sizeof(stOnFootData));
Вот мы обьявили структуру как data, обнулили все значения(*образно*) и записали в позицию координаты Groove Street а в скорость записали ускорение в сторону поворота игрока(небольшое чтоб было заметней нужно домножить на 10 и поднять педа, тоесть data.fPosition[2]+=1.5)
Так же есть fQuaternion, это такая вещь, что то типа замены матрицы, которая отвечает за поворот игрока.
Тут я не буду обьяснять как перевести матрицу поворота в кватернион, но возможно в скором будущем обьясню.
Ну вот мы подготовили груз к отправке теперь его нужно положить в коробку. Коробка это выражение образное ,на самом деле в RakNet это последовательность битов(байтов) так называемый BitStream.
Создаём битстрим строчкой <BitStream bs;>
И так, как говорилось ранее сначало нужно записать ID нашего пакета, тоесть ID_PLAYER_SYNC, делается это просто <bs.Write((BYTE)ID_PLAYER_SYNC);>
Записали в битстрим байт с идом пакета, затем записываем всю структуру, так называемый груз который мы подготавливали ранее. Выглядит это таким образом <bs.Write((PCHAR)&data, sizeof(stOnFootData));>
Ну вот как говорится и рыбку сьели и на хуй сели, теперь можно отправлять наш пакет на сервер, делается это так: <g_RakClient->Send(&bs);> (в случае собейта) а если у вас сф, то делается это так <SF->getRakNet()->SendPacket(&bsOnfootSync);>
И на выходе вы получите такую картину:
~Не обращайте на приставку LQ_ внимания, это обозначение битстрима в LiquidMod в который я это решил пихнуть, у вас же будет просто BitStream.~
Но что же произойдёт после того как мы отправили пакет? Ну начнём с того что отправим мы его один раз, а пакеты PLAYER_SYNC отправляются довольно часто самим самп клиентом, примерно каждую секунду когда вы стоите, и очень быстро когда двигаетесь. Но на выходе вы получите быстрый телепорт на грув с ускорением в сторону которую вы смотрите и телепорт обратно. (!Важная инфа) Синхра она на то и синхра что вы её не видите, увидят этот телепорт только остальные люди!
RakNet хуки!
Как вы уже знаете, пакеты не только исходят от нас но и приходят к нам, всё тот же PLAYER, BULLET, VEHICLE и т.д и мы их уже умеем отправлять НО! Что если мы хотим не отправлять пакеты сами, а заменять те которые уже исходят от нас? В этом нам помогут хуки!
Хук исходящей синхры.
~Для тех у кого сф пример будет потом, наберитесь терпения~
В собейте(mod_sa на 0.3.7 R1-R2 etc.) есть уже готовый хук исходящей синхры, он находится в файле cheat_samp.cpp и является функцией bool OnSendPacket(BitStream *parameters, PacketPriority priority, PacketReliability reliability, char orderingChannel){ … }
И так всякий раз когда мы отправляем пакет, в собейте вызывается функция OnSendPacket
Ловится битстрим, как мы говорили в прошлом примере коробка и выполняются некие действия с ними. Рассмотрим простой пример GhostMod, когда другие игроки смогут проходить сквозь нас. Принцип простой: Ловим пакет, заменяем параметр byteSpecialAction на 3. И так начнём.
Для начала узнаем какой пакет у нас отловился, для этого пишем <parameters->ResetReadPointer();
parameters->Read(packetId);>
ResetReadPointer обозначает то что мы сдвинули указатель чтения пакета в 0, это можно сравнить с курсором в текстовом редакторе.
Теперь после обнуления перед курсором стоит ид пакета, после прочтения которого, «курсор»
сдвинется за него. Далее мы проверяем если ид пакета равен 207 (ID_PLAYER_SYNC) то начинаем редактировать.
Чтоб не читать всё подряд то нужного нам значения, мы поставим нужный нам сдвиг байтов, тоесть переместим его сами. Для этого есть функция SetReadOffset(int offset). Чтоб узнать на каком оффсете расположен byteSpecialAction нужно посчитать сколько было байт информации до него. Я этого делать не буду так как у меня есть сосчитаные оффсеты, которые я приложу к данному «гайду».
И так оффсет у нас равен 37, пишем parameters->SetReadOffset(37);
Отлично, мы сдвинули курсор в нужное нам место, теперь картина выглядит примерно вот так:
Можно прочитать byteSpecialAction в какую нибудь переменную например:
uint8_t sAction;
parameters->Read(sAction);
Но нам же нужно просто заменить?
Тогда делаем parameters->SetWriteOffset(37);
WriteOffset это уже курсор записи, а не чтения.
Запись выглядит так, будто был нажат Insert поэтому после записи какого то значения, остальное не сдвинется а заменится тем что вводили. И так поставили мы оффсет теперь parameters->Write((uint8_t)3);
Отлично! Мы заменили наше значение, теперь отпускам пакет на свободу return true;
Получилось примерно следущее:
А теперь главный вопрос: Как же быть с SF?
А всё очень просто, мы просто создадим такую же функу как в собейте.
Сначала регистрируем коллбэк функи в mainloop (там где вся инициализация)
SF->getRakNet()->registerRakNetCallback( RakNetScriptHookType::RAKHOOK_TYPE_OUTCOMING_PACKET, OnSendPacket );
Затем создаём функу
bool CALLBACK outcomingData( stRakNetHookParams *params ){
}
Теперь у нас есть удобная структурка в отличии от собейта где мы сразу можем достать ид пакета, вот так: if(params->packetId == ID_PLAYER_SYNC){ … }
Битстрим идёт отдельно как params->bitStream НО! В нём по прежднему лежит пакет айди, не стоит думать что он отдельно! Дальше всё происходит так же только вместа parameters мы пишем params->bitStream
Хук входящей синхры.
Как я уже говорил, пакеты идут не только от нас, но и к нам! Поэтому логично тебе подумать что входящие пакеты тоже можно ловить. И да, это так! Можно стопануть например унок синхру(она нужна для синхронизации пустых машин, исходят когда ты толкаешь машину) и пояснить за позицию например.
Чтобы не ебаться лишний раз с оффсетами мы прочитаем всю структуру разом. Функа для хука входящих пакетов в собейте находится в файле cheat_samp.cpp и является функцией bool OnReceivePacket(Packet *p){...}
Для начала получим пакет айди, он находится в p->data[0] и проверяем
if(p->data[0] == ID_UNOCCUPIED_SYNC){ … }
Затем нам нужно из пакета получить битстрим, делаем это так: BitStream bsUnoData((unsigned char *)p->data, p->length, false);
Получили битстрим затем читаем его в структуру UnoData(назвать можно как угодно хоть huimorzha)
stUnoccupiedData UnoData;
bsUnoData.IgnoreBits(8);
bsUnoData.Read(playerId);
bsUnoData.Read((PCHAR)&UnoData, sizeof(stUnoccupiedData));
Теперь просим пакет пояснить за позицию которую он шлёт, делается это так
if(UnoData.fPosition[2] > 20000 || UnoData.fPosition[2] < -20000){
return false;
}
проверяем если позиция больше 20000 или меньше -20000 значит пакет плохой и тот кто его отправил юзает крашер и хочет нас крашнуть. Значит нам нужно как то игнорировать этот пакет, тоесть не пустить его к нам в клиент дабы избежать краша. Можно просто написать return false; а можно написать p->data[0] = 255; что в принципе даст одно и тоже.
Что же делать в SF? Ну тут опять же всё просто, регистрируем коллбэк в mainloop инициализации:
SF->getRakNet()->registerRakNetCallback( RakNetScriptHookType::RAKHOOK_TYPE_INCOMING_PACKET, OnRecivePacket );
И создаём функу приёма пакета.
bool CALLBACK OnRecivePacket( stRakNetHookParams *params ){
...
}
Далее всё делается ещё проще, битстрим лежит всё там же в params->bitStream и пакет айди тоже. Читаем как исходящий а чтоб не пустить его, так же как в исходящем пишем return false;
На этом по ракнету у меня всё, RPC лень писать, возможно мне припрёт и я напишу про них, удачного кодинга вашего собейта/сфплагина
с вами был zH.F11GAR0
Thanks to:
FYP – for SF and mod_sa source
MasterZero – for motivation to make cheats
GH0ST – for help with sobeit and c++
DR8GUN8V – for testing my shit
0pc0d3r – for good nastroenie and motivation to reverce injenering shit and (?)
Zeta-Hack team – for motivation to fuCK SAMP JAJAJA
Вложения
Последнее редактирование: