Example #1
0
 def handle_unknown_peer(self, msg_params, from_addr, msg_id):
     """ Handle the UNKNOWN_PEER message
    """
     self.known_peers.discard(from_addr)
     yatelog.info(
         'YATESock',
         'Peer %s:%s does not know us, perhaps we timed out?' % from_addr)
Example #2
0
 def handle_login_success(self,buff):
     self.avatar_uuid = buff.unpack_string()
     self.avatar_name = buff.unpack_string()
     self.sock.switch_mode("play")
     yatelog.info('minecraft','Connected to minecraft server %s:%s with display name "%s" and avatar UUID %s' % (self.server_addr[0],self.server_addr[1],self.avatar_name,self.avatar_uuid))
     self.sock.send_client_settings(buffer.Buffer.pack_string('en_GB'), # locale
                                    buffer.Buffer.pack_byte(1),         # view distance
                                    buffer.Buffer.pack_varint(0),       # chat is enabled
                                    buffer.Buffer.pack('?',False),      # disable chat colors
                                    buffer.Buffer.pack_byte(0xFF),      # enable all the displayed skin parts
                                    buffer.Buffer.pack_varint(1))       # right handed, not sure if this matters
Example #3
0
    def __init__(self,
                 bind_ip='127.0.0.1',
                 bind_port=0,
                 handlers={},
                 enable_null_handle=True):
        """ handlers is a dict mapping message type integers to functions that take the params (msg_params,msg_id,from_addr,sock)
           enable_null_handle enables a default "null handler" that does nothing with unhandled message types except logging them to debug
       """
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind((bind_ip, bind_port))
        yatelog.info('YATESock', 'Bound %s:%s' % self.sock.getsockname())
        yatelog.info('YATESock', 'Setting up handlers and queues')
        self.pool = eventlet.GreenPool(1000)
        self.in_queues = {
        }  # packets coming in from remote peer go here after parsing, each message type has an independent queue so we can do QoS-type stuff
        self.out_queues = {}  # packets going out to remote peer go here
        self.parse_q = eventlet.queue.LightQueue(
            0)  # to keep up performance, packets go here before parsing
        self.handlers = {
            MSGTYPE_CONNECT: self.
            handle_connect,  # a couple of standard message handlers, override by passing in new handlers
            MSGTYPE_UNKNOWN_PEER: self.handle_unknown_peer,
            MSGTYPE_CONNECT_ACK: self.handle_connect_ack,
            MSGTYPE_KEEPALIVE: self.handle_keepalive,
            MSGTYPE_KEEPALIVE_ACK: self.handle_keepalive_ack
        }
        self.handlers.update(handlers)
        self.enable_null_handle = enable_null_handle
        self.active = True

        for x in xrange(10):
            self.pool.spawn_n(self.parser_thread)
        for k, v in msgtype_str.items():
            self.in_queues[k] = eventlet.queue.LightQueue(0)
            self.out_queues[k] = eventlet.queue.LightQueue(0)
            setattr(self, 'send_%s' % v[8:].lower(),
                    YATESockSendMethod(k, self))  # black magic
            for x in xrange(2):
                self.pool.spawn_n(self.msg_sender_thread, k)
            for x in xrange(2):
                self.pool.spawn_n(self.msg_reader_thread, k)
            if enable_null_handle:
                if not self.handlers.has_key(k):
                    self.handlers[k] = self.null_handler
        self.known_peers = set(
        )  # if this is a server, this set contains the list of clients, if it's a client this contains only 1 member - the server
        self.last_pack = {
        }  # store the timestamp of the last packet from a particular peer so we can do timeouts
        self.pool.spawn_n(self.recv_thread)
        self.pool.spawn_n(
            self.timeout_thread
        )  # timeout peers all in a central location, giving plenty of time for them to send packets and not timeout
Example #4
0
 def timeout_thread(self):
     """ kill peers that have timed out
    """
     while self.active:
         eventlet.greenthread.sleep(YATE_KEEPALIVE_TIMEOUT)
         cur_time = time.time()
         peer_list = self.known_peers.copy()  # thread safety bitches
         for peer in peer_list:
             if not self.last_pack.has_key(peer):
                 yatelog.warn(
                     'YATESock',
                     'Peer %s:%s never actually sent us a single packet after connecting'
                     % peer)
                 self.known_peers.discard(peer)
             else:
                 if cur_time - self.last_pack[peer] > YATE_KEEPALIVE_TIMEOUT:
                     yatelog.info('YATESock',
                                  'Peer %s:%s has timed out, bye' % peer)
                     self.known_peers.discard(peer)
Example #5
0
    def switch_mode(self, new_mode=protocol_modes['login']):
        """ Use this to switch protocol mode after a connection is established
           new_mode is the integer describing the new mode to switch to (default is login)
           status is not supported because YATE has no use for it
       """
        if not (type(new_mode) is int): new_mode = protocol_modes[new_mode]
        yatelog.info(
            'MCSock', 'Switching protocol modes: %s to %s' %
            (protocol_modes[self.protocol_mode], protocol_modes[new_mode]))
        oldmode = self.protocol_mode
        self.protocol_mode = new_mode
        if new_mode == protocol_modes['login']:
            self.send_handshake(
                buffer.Buffer.pack_varint(self.protocol_version),
                buffer.Buffer.pack_string(self.endpoint[0]),
                buffer.Buffer.pack('H', self.endpoint[1]),
                buffer.Buffer.pack_varint(protocol_modes['login']),
                protomode=oldmode)

        if self.protocol_mode == protocol_modes['login']:
            self.send_login_start(buffer.Buffer.pack_string(self.display_name))
Example #6
0
   def __init__(self,username=None,password=None,server='127.0.0.1:25565'):
       super(MinecraftDriver,self).__init__(username=username,password=password,server=server)
       self.username    = username
       self.password    = password
       self.avatar_uuid = None
       self.avatar_eid  = 0
       self.avatar_name = username # not always the same, just usually
       server_ip,server_port = server.split(':')
       self.server_addr = (server_ip,int(server_port))
       yatelog.info('minecraft','Minecraft driver starting up')
   
       pack_handlers = {'login_success':           self.handle_login_success,
                        'join_game':               self.handle_join_game,
                        'player_position_and_look':self.handle_player_position_and_look,
                        'chunk_data':              self.handle_chunk_data}

       self.sock = mcsock.MCSocket(self.server_addr,handlers=pack_handlers,display_name=username)
       self.sock.switch_mode(mcsock.protocol_modes['login'])
       self.tick_delay       = (1.0/20.0)
       self.last_tick        = time.time() - self.tick_delay # make sure that we tick after connecting
       self.last_full_update = time.time() - 1.0             # make sure we run a full update after connecting
       self.av_pos           = None # stores the avatar position, in minecraft format also known as (x,z,y) to sane humans
       self.av_pitch         = None
       self.av_yaw           = None
       self.on_ground        = True
       self.world            = smpmap.Dimension(smpmap.DIMENSION_OVERWORLD)
       self.sock.blocking_handlers = False
       yatelog.info('minecraft','Awaiting download of avatar position and terrain data')
       while self.av_pos is None:
          eventlet.greenthread.sleep(self.tick_delay)
          self.minecraft_client_tick()
       yatelog.info('minecraft','Got avatar position, awaiting chunks')
       while self.world.get_block(self.av_pos[0],self.av_pos[2],self.av_pos[1]) is None:
          self.minecraft_client_tick()
          yatelog.debug('minecraft','Waiting for chunk %s' % str(self.get_av_chunk()) )
       yatelog.info('minecraft','Got terrain data, ready to rock')
Example #7
0
 def handle_join_game(self,buff):
     self.avatar_eid = buff.unpack_int()
     yatelog.info('minecraft','We are entity ID %s' % self.avatar_eid)
     self.sock.send_plugin_message(buffer.Buffer.pack_string('MC|Brand'),
                                   buffer.Buffer.pack_string('YATE minecraft driver'))
Example #8
0
 def connect_to(self, addr):
     """ Connect to the specified remote peer - this pretty much only really makes sense for clients
    """
     yatelog.info('YATESock', 'Connecting to peer at %s:%s' % addr)
     msg_id = self.send_connect(to_addr=addr)
     self.handle_connect(tuple(), addr, msg_id)
Example #9
0
 def null_handler(self, msg_params, from_addr, msg_id):
     """ null handler - just dumps the message to log
    """
     yatelog.info(
         'YATESock', 'Null handler dump: message ID %s from %s:%s: %s' %
         (msg_id, from_addr[0], from_addr[1], str(msg_params)))