Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming / GameProg / RPG_Programming_2ed.pdf
Скачиваний:
240
Добавлен:
12.02.2016
Размер:
12.06 Mб
Скачать

Глава 5. Работа с сетью с DirectPlay

Вы снова используете идентификатор игрока и указатель на его

контекст, которые уже видели ранее. Вопросы вызывает только последнее поле, dwReason. Почему игрок покинул игру? Было ли это обычное

завершение игры, или было внезапно разорвано соединение, может была прервана сессия или игрок был принудительно отключен? Каждой из этих

причин соответствует макрос из перечисленных в таблице 5.8. Вы можете использовать значение в поле dwReason как считаете нужным.

Таблица 5.8. Причины отключения

Макрос

Описание

 

 

DPNDESTROYPLAYERREASON_NORMAL

Обычное отключение

 

игрока.

DPNDESTROYPLAYERREASON_CONNECTIONLOST

Отключение игрока из-за

 

разрыва соединения.

DPNDESTROYPLAYERREASON_SESSIONTERMINATED

Удаление игрока из-за

 

завершения сессии.

DPNDESTROYPLAYERREASON_HOSTDESTROYPLAYER

Принудительное

 

удаление игрока

 

сервером.

 

 

Для принудительного отключения игрока вы используете функцию

IDirectPlay8Server::DestroyClient:

HRESULT IDirectPlay8Server::DestroyClient(

const DPNID

pdnidClient,

//

Идентификатор игрока

const void *const pDestroyInfo, //

NULL

const

DWORD

dwDestroyInfoSize,

//

0

const

DWORD

dwFlags);

//

0

Здесь нет ничего нового — просто укажите идентификатор игрока. Вот как выполняется отключение:

pDPServer->DestroyClient(dpnidPlayerID, NULL, 0, 0);

Другой способ отключения игрока — завершение сессии. Об этом мы поговорми чуть позже в разделе «Завершение сессии на главном узле».

Получение данных

Игровые данные передаются в виде зависящих от приложения сообщений, но

они всегда заключены в сообщения типа

DPN_MSGID_RECEIVE,

использующих структуры данных DPNMSG_RECEIVE:

typedef struct _DPNMSG_RECEIVE {

 

DWORD dwSize;

// Размер структуры

DPNID dpnidSender;

// Идентификатор отправителя

PVOID pvPlayerContext;

// Указатель на контекст игрока

PBYTE pReceiveData;

// Буфер принятых данных

DWORD dwReceivedDataSize; // Размер принятых данных

DPNHANDLE hBufferHandle;

// Дескриптор буфера данных

} DPNMSG_RECEIVE;

 

 

 

 

 

282

netlib.narod.ru

 

Джим Адамс

Чтобы обработать данные, обращайтесь к ним через указатель pReceiveData, используя, если необходимо, дескриптор памяти Windows hBufferHandle. Сперва это кажется бессмысленным, но в

действительности гарантирует, что сообщение будет храниться в памяти, пока вы не будете готовы работать с данными.

В качестве примера предположим, что будет принято 16 байт данных. Эти данные представляют состояние игрока в игре. Для доступа к данным выполните приведение типа к указателю на структуру данных и работайте с данными, как показано в следующем примере:

#define MSG_PLAYERSTATE 0x101

typedef struct { DWORD dwType;

DWORD dwXPos, dwYPos, dwHealth; } sPlayerState;

// Обработчик сообщений

HRESULT WINAPI ServerMsgHandler(PVOID pvUserContext,

DWORD dwMessageId, PVOID pMsgBuffer)

{

IDirectPlay8Server *pDPServer; HRESULT hr;

DPNMSG_RECEIVE *pReceive; sPlayerState *pState;

if((pDPServer = (IDirectPlay8Server*)pvUserContext)) == NULL) return E_FAIL;

switch(dwMessageId) { case DPN_MSGID_RECEIVE:

pReceive = (DPNMSG_RECEIVE*)pMsgBuffer;

// Приведение буфера данных к типу сообщения pState = (sPlayerState*)pReceive->pReceivedData; if(pState->dwType == MSG_PLAYERSTATE) {

// Делаем что нам надо со структурой данных

}

return S_OK;

}

return E_FAIL;

}

Иногда поступает очень много сообщений и вы не можете обработать их все при получении. В таком случае можно поместить их в очередь. Когда

вы закончите работать с данными в памяти, передайте дескриптор функции

IDirectPlay8Server::ReturnBuffer:

HRESULT IDirectPlay8Server::ReturnBuffer(

const

DPNHANDLE hBufferHandle, //

Дескриптор буфера

const

DWORD dwFlags);

//

0

netlib.narod.ru

283

Глава 5. Работа с сетью с DirectPlay

Чтобы DirectPlay знал, что освобождать память не надо, после

завершения обработки сообщения верните значение

DPNSUCCESS_PENDING, вместо S_OK или E_FAIL.

Отправка сообщений сервера

Что хорошего в сети, которая не может передавать данные? Чтобы сервер отправил данные подключенному клиенту вам надо использовать функцию SendTo, которая отправляет данные отдельному игроку, всем игрокам сразу

или игрокам, относящимся к указанной группе. Взгляните на прототип функции SendTo:

HRESULT IDirectPlay8Server::SendTo(

//

Идентификатор игрока или группы,

const DPNID dpnid,

 

//

которым отправляется сообщение

 

//

Для отправки сообщения всем

 

//

игрокам используйте

 

//

DPNID_ALL_PLAYERS_GROUP

const DPN_BUFFER_DESC *const pBufferDesc, // См. описание

const DWORD cBufferDesc,

//

1

const DWORD dwTimeOut,

//

Время ожидания отправки

 

//

сообщения (в миллисекундах)

 

//

0 - если время ожидания

void *const pvAsyncContext,

//

не задано

//

Предоставленный пользователем

 

//

контекст

DPNHANDLE *const phAsyncHandle, //

NULL для синхронной операции

const DWORD dwFlags);

//

См. описание

Функция SendTo выглядит подавляюще. Вам необходимо учесть

безопасность, метод доставки и регулировку потока. Вы должны указать идентификатор игрока, которому хотите отправить сообщение, а также указатель на структуру DPN_BUFFER_DESC. Определение этой простой

структуры выглядит так:

typedef struct _DPN_BUFFER_DESC {

DWORD dwBufferSize;

//

Размер передаваемых данных

BYTE *pBufferData;

//

Указатель на передаваемые данные

} DPN_BUFFER_DESC;

 

 

Здесь вы задаете размер и указатель на данные, которые хотите отправить. Затем в функции SendTo идет параметр cBufferDesc, которому присваивается значение 1. Далее в dwTimeOut устанавливается

значение, определяющее период времени (в миллисекундах), который функция будет ждать, прежде чем вернет ошибку (со времени отправки данных). Если вы не хотите использовать эту возможность, просто укажите в данном параметре 0.

Аргумент pvAsyncContext — это задаваемый пользователем

контекст, используемый для указания на информацию, которую вы хотите получить, когда операция отправки будет завершена. Он похож на контекст игрока, поскольку упрощает доступ к информации.

284

netlib.narod.ru

Джим Адамс

Для использования асинхронной отправки вы предоставляете аргумент phAsyncHandle, куда будет записан дескриптор, который позже можно

использовать для отмены операции отправки. Осталось рассмотреть dwFlags. Взгляните на таблицу5.9, где приведен список макросов, которые

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

Таблица 5.9. Флаги поведения SendTo

Макрос

Описание

 

 

DPNSEND_SYNC

Синхронная отправка данных. Не возвращаем

 

управление, пока данные не отправлены.

DPNSEND_NOCOPY

DPNSEND_NOCOMPLETE

Заставляет DirectPlay не делать внутреннюю копию отправляемых данных. Это самый эффективный метод отправки данных; однако отложенные данные могут быть изменены прежде чем DirectPlay получит шанс отправить их.

Указывает DirectPlay, что не надо уведомлять сервер, когда операция отправки завершена.

DPSEND_COMPLETEONPROCESS

DPSEND_GUARANTEED DPNSEND_PRIORITY_HIGH

DPNSEND_PRIORITY_LOW

DPNSEND_NOLOOPBACK

DPNSEND_NONSEQUENCIAL

Заставляет DirectPlay отправлять сообщение

DPN_MSGID_SEND_COMPLETE, когда данные

отправлены и проверены системой на месте назначения. Это замедляет работу, но позволяет гарантировать, что данные

доставлены. Вместе с этим флагом вы должны указывать флаг DPSEND_GUARANTEED.

Использование гарантированной доставки.

Задает высокий приоритет для сообщения. Используется для отметки важных сообщений, которые должны быть пропущены через механизм фильтрации.

Задает низкий приоритет для сообщения. Используйте этот флаг для отметки не слишком важных сообщений, которые могут быть отброшены механизмом фильтрации.

Подавляет сообщение DPN_MSGID_RECEIVE

на сервере, если вы отправляете данные группе в которую входит игрок сервера.

Заставляет систему назначения принимать сообщения в том порядке, в котором они были отправлены (а не быть перепутанными из-за задержек в сети). Непоследовательный прием может замедлить работу удаленной стороны, поскольку потребуется отслеживать, буферизовать и переупорядочивать сетевые сообщения, чтобы они были доставлены в том порядке в котором их отправляли.

netlib.narod.ru

285

Соседние файлы в папке GameProg