HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > ПРОГРАММИРОВАНИЕ > С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 08.08.2018, 12:46
CleanLegend
Постоянный
Регистрация: 28.03.2013
Сообщений: 495
С нами: 6908018

Репутация: 213
По умолчанию

Введение

RakNet — это сетевой движок, используемый в SA:MP для обмена данными между игроками и сервером. Клиент отправляет пакет серверу, сервер его обрабатывает и рассылает другим игрокам — таким образом это работает.

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

Отправка пакетов

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

C++:





Код:
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, который запрашивает у сервера сменить наш класс (скин) на сервере:

C++:





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


C++:





Код:
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:

C++:





Код:
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:

C++:





Код:
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
 
Ответить с цитированием
Ответ



Предыдущая тема Следующая тема

Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.