Photon Server用のPythonライブラリ

過去数か月にわたって、 Photonクライアント/サーバーゲーム開発フレームワークについて詳しく知る必要がありました。 この記事では、Photonの長所と短所については説明しません。このためには、おそらく複数のフレームワークの経験が必要だからです。 PythonでPhoton Serverを操作するためのライブラリになります。



そもそも、なぜこれが必要なのか、なぜ既存のクライアントライブラリの1つを使用しなかったのかについて、いくつか説明します。



ゲームプロジェクトのサーバー側で作業する過程で、アプリケーションから現在のデータを直接取得したり、ゲームサービスを正常に停止したりするなどのサービスタスクがよくありました(人がいる間はゲームサーバーを取得して切断することはできません)。 当初、アプリケーションのすべてのサービス部分を操作するために、小さなGUIアプリケーションが作成され、これらの問題はすべて解決されました。 しかし、時間が経つにつれて、コンソールやUnixを介してこれらの公式なものを使いたいと思うようになりました。 同時に、最小のコード変更ですべてを再コンパイルしたくありませんでした。 このため、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クラスを使用します。 少し後で役に立つでしょう。



次に、ピアのサービスメソッドを1秒間に約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でのシリアル化の結果との互換性のために、同様のコードがここにあります。



最後に、現在の制限について:



UDPプロトコルを追加し、最後の2つのポイントを管理することは素晴らしいことですが、まだ時間がありません。 しかし、彼らが言うように、ソースコードは公開されています-すべてのカードは手元にあります。 必要なのは私たちだけではなく、私たちの仕事が誰かに役立つことを願っています。



PS誰かがコードのエラー/不正確さ、および/または最適に書かれていないセクションを見つけた場合(Pythonにあまり詳しくないので除外しません)-それらを指摘してくれて非常に感謝します。



All Articles