You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

120 lines
4.0 KiB

"""
:class:`GameCoordinator` is used to proxy messages from/to GC.
It takes care of the encapsulation details, but on its own is not
enough to communicate with a given GC.
Example implementation of Dota 2 GC client with inheritance.
.. code:: python
import myDotaModule
from steam.client import SteamClient
from steam.core.msg import GCMsgHdrProto
from steam.client.gc import GameCoordinator
class ExampleDotaClient(GameCoordinator):
def __init__(self, steam):
GameCoordinator.__init__(self, steam, 570)
def _process_gc_message(self, emsg, header, body):
if emsg == 4004: # EMsgGCClientWelcome
message = myDotaModule.gcsdk_gcmessages_pb2.CMsgClientWelcome()
message.ParseFromString(body)
print message
def send_hello(self):
header = GCMsgHdrProto(4006) # EMsgGCClientHello
body = myDotaModule.gcsdk_gcmessages_pb2.CMsgClientHello()
self.send(header, body.SerializeToString())
client = SteamClient()
dota = ExampleDotaClient(client)
client.login()
client.games_played([570])
dota.send_hello()
The above code assumes that we have a ``myDotaModule`` that contains the appropriate
protobufs needed to (de)serialize message for communication with GC.
"""
import logging
import gevent
from eventemitter import EventEmitter
from steam.utils.proto import set_proto_bit, clear_proto_bit, is_proto
from steam.enums.emsg import EMsg
from steam.enums import EResult
from steam.core.msg import GCMsgHdr, GCMsgHdrProto, MsgProto
from steam.client import SteamClient
class GameCoordinator(EventEmitter):
"""
``GameCoordinator`` is used to proxy messages from/to GC
:param steam_client: steam client instance
:type steam_client: :class:`steam.client.SteamClient`
:param app_id: app id of the application
:type app_id: :class:`int`
Incoming messages are emitted as events using their ``EMsg`` as an event identifier.
:param header: message header
:type header: :class:`steam.core.msg.GCMsgHdr`
:param body: raw message body
:type body: :class:`bytes`
"""
def __init__(self, steam_client, app_id):
if not isinstance(steam_client, SteamClient):
raise ValueError("Expected an instance of SteamClient as first argument")
self.steam = steam_client
self.app_id = app_id
self._LOG = logging.getLogger("GC(appid:%d)" % app_id)
# listen for GC messages
self.steam.on(EMsg.ClientFromGC, self._handle_from_gc)
def emit(self, event, *args):
if event is not None:
self._LOG.debug("Emit event: %s" % repr(event))
EventEmitter.emit(self, event, *args)
def send(self, header, body):
"""
Send a message to GC
:param header: message header
:type header: :class:`steam.core.msg.GCMsgHdr`
:param body: serialized body of the message
:type body: :class:`bytes`
"""
message = MsgProto(EMsg.ClientToGC)
message.header.routing_appid = self.app_id
message.body.appid = self.app_id
message.body.msgtype = (set_proto_bit(header.msg)
if header.proto
else header.msg
)
message.body.payload = header.serialize() + body
self.steam.send(message)
def _handle_from_gc(self, msg):
if msg.body.appid != self.app_id:
return
emsg = msg.body.msgtype
if is_proto(emsg):
header = GCMsgHdrProto(emsg, msg.body.payload)
header_size = GCMsgHdrProto._size + header.headerLength
else:
header = GCMsgHdr(emsg, msg.body.payload)
header_size = GCMsgHdr._size
body = msg.body.payload[header_size:]
self._process_gc_message(clear_proto_bit(emsg), header, body)
def _process_gc_message(self, emsg, header, body):
self.emit(emsg, header, body)