[RGame Engine] Расширения движка, обработчики команд и событий
roxblnfkКопия моей статьи с ныне мёртвого develnet.ru
В начало
Учимся использовать сеть в движке, отправлять и обрабатывать события сервера.
(Файлы CLASS TRChatTool.php
, CLASS TRCommanderCL.php
, CLASS TRProcEventsCL.php
, CLASS TRCommander.php
и CLASS TRPlayer.php
)
TRPlayer
По праву этот класс — не столько расширение движка, сколько одна из основных его частей. Каждый элемент массива <strong>$Players</strong> является объектом класса <strong>TRPlayer</strong>. Из названия ясно, что это "персональный" класс игрока (пользователя).
Рассмотрим переменные (кроме ссылок на основные объекты других классов):
$GID
(int) - Game ID - игровой идентификатор. Т.е. это ID игрока в массиве$Players
объекта классаTRGame
$CID
(int) - Connection ID - идентификатор сетевого подключения в объекте классаrxnetsv
.$CID
и$GID
очень редко будут совпадать, поэтому не путайте их.$CID
нужен для прямого обращения к подключению пользователя (или для получения некоторой информации касательно этого подключения).$Online
(bool) - статус игрока. Выставляется автоматически сетевым протоколом. Не рекомендуется выставлять "вручную", просто берите его значение для своих нужд. Если вы хотите, чтобы пользователи с offline статусом могли существовать, то редактируйте функциюonDisconnect
классаTRGame
(сейчас они автоматически выбрасываются из памяти).$Status
(int) - обозначает статусное положение клиента на сервере. Уже в первой версии проекта был написан код авторизации. Так вот, при$Status
==0
пользователь является неавторизованным. Такой пользователь может только авторизовываться, а когда авторизуется, то его статус меняется на 1 и пользователь получит доступ к другим возможностям (например чат). В коде будет частенько встречаться какое-нибудь условие с переменной$Status
(если отключится игрок со статусом 0, то об этом ни кто не узнает, см. ф-июkickPlayer()
).$Name
(false/str) - Ну тут ясно, что это имя пользователя после его авторизации.
Функции этого класса связаны напрямую с обслуживанием профиля:
processMe()
— самооброботка подключения, если оно установлено. Сюда входит автоматическая отправка буферизованных данных, и вызов функцииsockRead()
.sockRead()
— получение данных от пользователя и автоматический вызов функцииcommand()
применительно к полученным данным.sockSend()
— сиюсекундная отправка данных, если параметр$stack
==false
, иначе данные идут в буфер программы.command()
— отправка пакетов в классTRCommander
(о классе и пакетах см. ниже).getIP()
— получить внешний IP адрес пользователя. Функция демонстрирует использование переменно$CID
в виде обращения к информации о подключении.
TRCommander
И подошли, наконец-то, к одному из самых интересующих вопросов: как отправить информацию, получить её на другой стороне и обработать нужным мне кодом? И путь нам в классы TRCommanderCL
и TRCommander
. Если во время прочтения следующего ниже текста вы начнёте сомневаться в том, что полностью понимаете прочитанное, то ознакомьтесь сначала с разделом Сетевой протокол движка (точнее с его заметками), может поможет!
После получения пакета, класс сетевого протокола его расшифровывает и аккуратненько у себя складывает. Далее игровой движок, изымает расшифрованный пакет, и посылает на обработчик команд — в класс TRCommander(CL)
. Обработчик (функции processServer()
, processPlayer()
) перед обработкой контента $con
смотрит на команду (заголовок) $com
, указывающую на код, которым будет производиться обработка. Функция обработчика насыщена комментариями, и вам нужно просто в них разобраться, чтобы ориентироваться, куда добавлять свой код.
Вот пример обработки пакета с командой 100500447 — чат сообщение. Контент этого пакета обрабатывается функцией addMessage()
класса TRChatTool
. В данном случае в роли контента должен выступать массив, как указанно в комментарии.
switch($com){ // ........ // чат TRChatTool array(type,time,user,message) case 100500447: return $this->RGame->RChatTool->addMessage($con); }
На этом этапе рекомендуется попробовать выполнить задачку: разместите на форме любой компонент (например, EditBox), добавьте в обработчик сервера и клиента обработку новой (вашей) команды.
В событии изменения значения EditBox'a поставьте отправление пакета, содержащего вашу команду, а в качестве контента возьмите значение EditBox'a (как это сделать - смотрите на примере кода отправки чат-сообщения)
[Как нибудь засниму и вставлю на это место видео с решением этой задачки и поясню некоторые косяки организации кода (нет)]
TRChatTool
Чат-расширение, которое расширяет не движок, а только функционал программы (базовый инструмент для работы с чатами).
Объект этого класса размещается в переменной $RChatTool
объекта класса TRGameClient
. Думаю о нём нечего говорить, там всё должно быть понятно...
TRProcEventsCL
С обработчиком команд вроде ясно - что-то на сервере происходит, об этом надо сказать клиенту => просто создаём новую команду, добавляем туда контент и отправляем... Но разных событий может быть неограниченное количество, а коммандер особо засорять новыми и новыми командами не хочется... Можно, конечно, выделить один заголовок (команду) на группу событий, а какое событие конкретно произошло - объявить в контенте. Например, возьмём команду 1234567890 для событий "пользователь присоединился", "пользователь отсоединился", "пользователь сменил имя" и т.д. В принципе это оптимальное решение. Но под этот случай уже есть готовый код.
Написана удобная система событий (эвентов/ивентов, кому как удобнее), предназначенная для отправки "не обязательной" информации о событиях. К примеру, сообщение о том, что кто-то покинул сервер можно обрабатывать на оставшихся клиентах, а можно и не обрабатывать, в отличие от другой информации — чат-сообщения, например. Т.е. в чат мы обязаны выводить сообщения от других пользователей, но вот "Пользователь 123 покинул нас" можем и не выводить по разным причинам. Ну а серверу ваши ненужные события знать не нужно, поэтому удобная передача событий реализована только от сервера на клиент:
Вот код на сервере, выполняемый при отсоединении пользователя от сервера:
$this->sendEvent(1,'PlayerLeaveServer',array($gid,$Player->Name),false);
Первый параметр "1
" говорит о том, что об этом событии узнают только пользователи со значением параметра $Status
> 1
.
'PlayerLeaveServer'
- название функции класса TRProcEventsCL
, которая будет обрабатывать это событие.
Третий параметр описывает детали события (пока это ID и имя покинувшего сервер).
Попробуйте теперь найти в описании класса TRProcEventsCL
(обработчик событий) функции PlayerLeaveServer()
и PlayerJoinedToServer()
. Допишите их код так, чтобы о входе и выходе пользователя сообщалось в чате.
В случае с этими функциями код добавления сообщения производится всего одной функцией $this->RGame->RChatTool->addMessage()