Библиотека Python Для Photon Server

За последние несколько месяцев мне пришлось близко познакомиться с фреймворком для разработки клиент-серверных игр.

Фотон .

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

Мы поговорим о библиотеке для работы с Photon Server на Python. Сначала несколько слов о том, зачем это вообще было нужно и почему я не использовал ни одну из уже существующих клиентских библиотек.

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

в теме).

В самом начале было написано небольшое GUI-приложение для работы со всеми сервисными частями приложения, посредством которого решались все эти проблемы.

Но со временем все чаще нам хотелось работать с этими сервисными вещами через консоль, да еще и юниксовскую.

При этом мне не хотелось все перекомпилировать при малейшем изменении кода.

По этой причине от C#, Java и C++ отказались.

Был еще вариант с JavaScript и node.js, но меня давно привлекал Python и очень хотелось с ним познакомиться.

И вот такой счастливый случай.

Поэтому было решено написать библиотеку на этом языке.

Поскольку протокола Photon нет в открытом доступе (или, по крайней мере, я его не нашел), мне пришлось декомпилировать исходные коды клиентской библиотеки, написанные на Java, изучить их и переписать все это дело на Python. Java был выбран потому, что этот язык мне ближе, так как я последние несколько лет занимаюсь разработкой на этом языке.

Как позже выяснилось после разговора с разработчиками Photon, лучше было взять библиотеку на C#, так как она более свежая.

Изначально я хотел написать всё на Python версии 2.7 (на момент написания библиотеки текущая версия была 2.7.9), но столкнувшись с трудностями в реализации некоторых вещей, которые уже были реализованы из коробки в 3.4, я решил идти в ногу со временем.

Исходный код библиотеки можно найти по адресу github .

Давайте посмотрим на небольшой фрагмент кода, использующий эту библиотеку.

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

Во-первых, давайте реализуем интерфейс PeerListener:

  
  
  
  
   

class Connection: def __init__(self, connected=False): self.connected = connected class SimpleListener(PeerListener): def __init__(self, connection): super().

__init__() self.connection = connection def debug_return(self, debug_level, message): print("[{}] - {}".

format(debug_level.name, message)) def on_status_changed(self, status_code): print("[Status changed] - {}".

format(status_code.name)) if status_code is StatusCode.Connect: self.connection.connected = True def on_operation_response(self, op_response): print(op_response) def on_event(self, event_data): print(op_response)

Пока мы никак не будем обрабатывать OperationResponse и Events. Мы просто выведем их в консоль.

Здесь также используется небольшой класс Connection, просто как хранитель статуса соединения.

Он нам понадобится чуть позже.

Теперь напишем сервисный поток, который будет вызывать метод сервиса нашего пира примерно 10 раз в секунду (рекомендация разработчиков):

class ServiceThread(threading.Thread): def __init__(self, pp): threading.Thread.__init__(self) self.pp = pp self._run = False def run(self): self._run = True while self._run: self.pp.service() time.sleep(100.0 / 1000.0) def stop(self): self._run = False

И конечно основная функция:

def main(): connection = Connection() pp = PhotonPeer(enums.ConnectionProtocol.Tcp, SimpleListener(connection)) pp.set_debug_level(DebugLevel.All) pp.connect(your_ip, your_port, your_app_name) service_thread = ServiceThread(pp) service_thread.start() while connection.connected is False: pass # Put your code here service_thread.stop() service_thread.join() pp.disconnect()

Весь исходник здесь

import threading import time from photon import enums from photon.enums import DebugLevel, StatusCode from photon.listener import PeerListener from photon.peer import PhotonPeer class Connection: def __init__(self, connected=False): self.connected = connected def main(): connection = Connection() pp = PhotonPeer(enums.ConnectionProtocol.Tcp, SimpleListener(connection)) pp.set_debug_level(DebugLevel.All) pp.connect(your_ip, your_port, your_app_name) service_thread = ServiceThread(pp) service_thread.start() while connection.connected is False: pass # Put your code here service_thread.stop() service_thread.join() pp.disconnect() class ServiceThread(threading.Thread): def __init__(self, pp): threading.Thread.__init__(self) self.pp = pp self._run = False def run(self): self._run = True while self._run: self.pp.service() time.sleep(100.0 / 1000.0) def stop(self): self._run = False class SimpleListener(PeerListener): def __init__(self, connection): super().

__init__() self.connection = connection def debug_return(self, debug_level, message): print("[{}] - {}".

format(debug_level.name, message)) def on_status_changed(self, status_code): print("[Status changed] - {}".

format(status_code.name)) if status_code is StatusCode.Connect: self.connection.connected = True def on_operation_response(self, op_response): print(op_response) def on_event(self, event_data): print(op_response) if __name__ == "__main__": main()

Отдельно хотелось бы остановиться на сериализации целочисленных типов.

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

def _serialize_byte(out, value, set_type): if set_type: out.extend(bytearray([98])) value = ((value + ((1 << 7) - 1)) % (1 << 8)) - ((1 << 7) - 1) out.extend(struct.pack('>b', value))

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

Ответ прост — аналогичный код здесь для совместимости с результатом сериализации в Java. И напоследок о действующих ограничениях:

  • Поддерживает только протокол TCP
  • Не поддерживает зашифрованное соединение
  • Не поддерживает сбор статистики трафика
Было бы здорово добавить протокол UDP и исправить последние 2 пункта, но на это пока нет времени.

Но исходники открыты, как говорится – все карты в руки.

Хочется надеяться, что мы не единственные, кому это понадобилось и что наша работа кому-то будет полезна.

P.S. Если кто-то обнаружит ошибки/неточности в коде и/или не оптимально написанных разделах (чего я не исключаю в силу моего не очень долгого знакомства с Python), буду безмерно благодарен за указание на них.

Теги: #photon #python #exitgames #python #программирование #Разработка игр

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.