Best Python code snippet using fMBT_python
tick.py
Source:tick.py  
...150        if r.isCraftedBy(c):151            slots[0].stack = copy.copy(r.outputs)152            break153    154def sendCloseWindow(app, windowId: int):155    if hasattr(app, 'server'):156        server: ServerState = app.server157        player = server.getLocalPlayer()158        if windowId != 0:159            server.openWindows.pop(windowId)160        if player.entityId in server.craftSlots:161            craftSlots = server.craftSlots.pop(player.entityId)162            for craftSlot in craftSlots[1:]:163                player.pickUpItem(app, craftSlot.stack)164    else:165        network.c2sQueue.put(network.CloseWindowC2S(windowId))166def sendUseItem(app, hand: int):167    if hasattr(app, 'server'):168        server: ServerState = app.server...peon-legacy.py
Source:peon-legacy.py  
1#!/usr/bin/python2import mc3import astar4import json5import re6from scipy.spatial.distance import cityblock, euclidean7import pickle8import csv9import collections10import functools11import math12import Queue13import socket14import struct15import sys16import threading17import time18import random19import itertools20import logging21import optparse22import atexit23import os24class MoveException(Exception):25  pass26class MineCraftBot(mc.MineCraftProtocol):27  def __init__(self, host, port, username, password=None, fighting=True):28    super(MineCraftBot, self).__init__()29    self._host = host30    self._port = port31    self._username = username32    self._password = password33    self._serverId = None34    self._status = 'idle'35    self._health = 036    self._food = 037    self._food_saturation = 038    self._xp_bar = -139    self._xp_level = -140    self._xp_total = -141    self._available_enchantments = {}42    self._open_window_id = 043    self._held_slot_num = 044    self.world = mc.World()45    self.windows = {}46    self._pos = mc.Position(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1)47    self._entityId = None48    self._levelType = None49    self._serverMode = None50    self._dimension = None51    self._difficulty = None52    self._maxPlayers = None53    self._cursor_slot = mc.Slot(itemId=-1, count=None, meta=None, data=None) 54    self._action_id = itertools.count(1)55    self._confirmations = {}56    self.bot_file = os.path.join('/tmp', self._username)57    self._threadFuncs.extend([58        #self._DoCrashThread,59        #self._DoWatchdogThread,60        self._DoPositionUpdateThread,61        ])62    if fighting:63      self._threadFuncs.append(self._DoFightingThread)64    self._handlers = {65        '\x00': self.OnKeepAlive,66        '\x01': self.OnLogin,67        '\x02': self.OnHandshake,68        '\x03': self.OnChatMessage,69        '\x05': self.OnEntityEquipment,70        '\x08': self.OnUpdateHealth,71        '\x0d': self.OnPlayerPositionLook,72        '\x14': self.OnSpawnNamedEntity,73        '\x18': self.OnSpawnMob,74        '\x1d': self.OnDestroyEntity,75        '\x1f': self.OnEntityRelativeMove,76        '\x21': self.OnEntityLookRelativeMove,77        '\x22': self.OnEntityTeleport,78        '\x2b': self.OnSetExperience,79        '\x33': self.world.MapChunk,80        '\x34': self.OnMultiBlockChange,81        '\x35': self.OnBlockChange,82        '\x64': self.OnOpenWindow,83        '\x67': self.OnSetSlot,84        '\x68': self.OnSetWindowItems,85        '\x69': self.OnUpdateWindowProperty,86        '\x6a': self.OnConfirmTransaction,87        }88    self._block_names, self._block_ids = self.get_blocktypes()89    if os.path.isfile(self.bot_file):90      raise Exception("%s is already logged in" % self._username)91    open(self.bot_file, 'w').close()92    atexit.register(self.delbotfile)93    if password is None:94      self.Login()95    else:96      self.Login(authenticate=True)97    #self.FloatDown()98  def get_blocktypes(self, filename='blocktypes.csv'):99    c = [ l for l in csv.DictReader(open(filename), skipinitialspace=True) ]100    block_names = dict([(int(l['dec']), l['type']) for l in c ])101    block_ids = dict([(l['type'], int(l['dec'])) for l in  c ])102    return block_names, block_ids103  def delbotfile(self):104    os.remove(self.bot_file)105  def Login(self, authenticate=False):106    self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)107    self._sock.connect((self._host, self._port))108    self._sockGeneration += 1109    self.StartThreads()110    if authenticate:111      self._sessionId = self.GetSessionId(self._username, self._password)112      logging.info('sessionId: %d', self._sessionId)113      self.SendHandshake(self._username, self._host, self._port)114      self.WaitFor(lambda: self._serverId is not None)115      logging.info('serverId: %d', self._serverId)116      logging.info('joinserver status: %s', str(self.JoinServer(self._username, self._sessionId, self._serverId)))117    logging.info('sending login. server: %s username: %s', self._host, self._username)118    self.SendLogin(self._username)119  def _DoCrashThread(self):120    time.sleep(60)121    while self._sock is not None:122      self._buf = '\x1bADIDEA'123      time.sleep(1)124  def _DoWatchdogThread(self):125    try:126      myGeneration = self._sockGeneration127      time.sleep(5)128      while all(t.is_alive() for t in self._threads):129        time.sleep(1)130      deadTime = time.time()131      self._sock = None132      self._sendQueue.put(None)133      self._sendQueue = None134      def OtherThreadIsAlive():135        return len([t for t in self._threads if t.is_alive()]) > 1136      while OtherThreadIsAlive() and time.time() - deadTime < 5:137        time.sleep(1)138      if OtherThreadIsAlive():139        time.sleep(3)140      self._buf = ''141      self._sendQueue = Queue.Queue(10)142      self._pos = mc.Position(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1)143      self.world = mc.World()144      self.windows = {}145      self.Login()146      self.FloatDown()147    finally:148      logging.error("Watchdog thread exiting, %s", str(myGeneration))149  def _DoPositionUpdateThread(self):150    try:151      self.WaitFor(lambda: self._pos.x != 0.0 and self._pos.y != 0.0)152      myGeneration = self._sockGeneration153      while myGeneration == self._sockGeneration:154        time.sleep(0.010)155        self.SendPositionLook()156        if os.getppid() != self.parentPID:157          logging.erro("Position update thread exiting, %s", srt(myGeneration))158    finally:159      os.kill(self.parentPID, 0)160  def _DoFightingThread(self):161    HOSTILE_MOBS = set([50, 51, 52, 53, 54, 55, 56, 58, 59, 61, 62, 63])162    try:163      self.WaitFor(lambda: self._pos.x != 0.0 and self._pos.y != 0.0)164      while True:165        time.sleep(0.10)166        if os.getppid() != self.parentPID:167          logging.erro("Fighting thread exiting, %s", srt(myGeneration))168        for eid, entity in self.world._entities.items():169          if entity._type in HOSTILE_MOBS:170            if euclidean(entity._pos.xzy(), self._pos.xzy()) <= 4:171              self.attack_entity(eid)172    finally:173      os.kill(self.parentPID, 0)174  def OnKeepAlive(self, token):175    self.Send(176        '\x00' +177        struct.pack('!i', token)178        )179  def SendPositionLook(self, pos=None):180    if pos is None:181      pos = self._pos182    self.SendPlayerPositionAndLook(pos.x, pos.y, pos.stance, pos.z, pos.yaw, pos.pitch, pos.on_ground) 183  def OnLogin(self, entityId, levelType, serverMode, dimension, difficulty, maxPlayers):184      self._entityId = entityId185      self._levelType = levelType186      self._serverMode = serverMode187      self._dimension = dimension188      self._difficulty = difficulty189      self._maxPlayers = maxPlayers190  def OnHandshake(self, serverId):191      self._serverId = serverId192  def OnChatMessage(self, chat):193    logging.info("Chat: %s", chat)194    m = re.match('<\w+> peon, (.*)', chat)195    if m is not None:196        self.run_cmd(m.group(1))197  def OnEntityEquipment(self, entity_id, slot_num, item_id, damage):198    return199  def OnUpdateHealth(self, health, food, food_saturation):200    self._health = health201    self._food= food202    self._food_saturation = food_saturation203    if health <= 0:204      self.WaitFor(lambda: self._dimension is not None)205      self.SendRespawn(self._dimension, self._difficulty, self._levelType)206  def OnPlayerPositionLook(self, x, stance, y, z, yaw, pitch, onGround):207    pos = mc.Position(x, y, stance, z, yaw, pitch, onGround)208    self.SendPositionLook(pos)209    self._pos = mc.Position(x, y, stance, z, yaw, pitch, 1)210  def OnSpawnNamedEntity(self, eid, player_name, x, y, z, yaw, pitch, current_item):211    self.world._entities[eid] = mc.Entity(212      eid, 0, x, y, z, yaw, pitch, player_name=player_name, current_item=current_item)213  def OnSpawnMob(self, eid, etype, x, y, z, yaw, pitch, head_yaw, metadata):214    self.world._entities[eid] = mc.Entity(215      eid, etype, x, y, z, yaw, pitch, head_yaw=head_yaw, metadata=metadata)216  def OnDestroyEntity(self, eid):217    if eid in self.world._entities:218      del self.world._entities[eid]219  def OnEntityRelativeMove(self, eid, x, y, z):220    if eid in self.world._entities:221      self.world._entities[eid].Move(x, y, z)222  def OnEntityLookRelativeMove(self, eid, x, y, z, yaw, pitch):223    if eid in self.world._entities:224      self.world._entities[eid].Move(x, y, z)225  def OnEntityTeleport(self, eid, x, y, z, yaw, pitch):226    if eid in self.world._entities:227      self.world._entities[eid].Teleport(x, y, z)228  def OnEntityHeadLook(self, eid, head_yaw):229    if eid in self.world._entities:230      self.world._entities[eid]._head_yaw = head_yaw231  def OnEntityStatus(self, eid, status):232    if eid in self.world._entities and status == 3:233      del self.world._entities[eid]234  def OnSetExperience(self, bar, level, total):235    self._xp_bar = bar236    self._xp_level = level237    self._xp_total = total238  def OnMultiBlockChange(self, blocks):239    for x, z, y, newType, newMeta in blocks:240      self.world.SetBlock(x, z, y, newType, newMeta)241  def OnBlockChange(self, x, y, z, newType, newMeta):242    self.world.SetBlock(x, z, y, newType, newMeta)243  def OnOpenWindow(self, window_id, inventory_type, window_title, num_slots):244    self._open_window_id = window_id245    if window_id not in self.windows:246      time.sleep(1)247    if window_id in self.windows:248      self.windows[window_id].inventory_type = inventory_type249      self.windows[window_id].window_title = window_title250  def OnCloseWindow(self, window_id):251    self._open_window_id = 0252  def OnMapChunks(self, chunk):253    self._chunks[chunk.chunkX, chunk.chunkZ] = chunk254  def OnSetSlot(self, windowId, slotIndex, slot):255    if windowId == -1 and slotIndex == -1:256      self._cursor_slot = slot257    elif windowId in self.windows:258      self.windows[windowId].SetSlot(slotIndex, slot)259  def OnSetWindowItems(self, windowId, slots):260    window = mc.Window(windowId, slots)261    self.windows[windowId] = window262  def OnUpdateWindowProperty(self, window_id, window_property, value):263    self._available_enchantments[window_property] = value264  def OnConfirmTransaction(self, window_id, action_id, accepted):265    self._confirmations[action_id] = mc.Confirmation(window_id, action_id, accepted)266    if not accepted:267        self.SendConfirmTransaction(window_id, action_id, accepted)268  def break_block(self, x, z, y, face=1, retries=3, auto_move=True):269    xzy = mc.Xzy(x, z, y)270    if auto_move:271      m= self.iter_nearest_moveable(xzy)272      block = m.next()273      while euclidean(xzy, block) <= 6:274        if self.nav_to(*block): break275        block = m.next()276      else:277        logging.error('too far to break block')278        return False279    blocktype = self.world.GetBlock(*xzy)280    if blocktype is not None:281      self.get_best_tool(blocktype)282    for i in range(retries):283      logging.debug('sending dig command for: %s', str(xzy))284      self.SendPlayerDigging(0, x, y, z, face)285      time.sleep(0.1)286      self.SendPlayerDigging(2, x, y, z, face)287      if self.WaitFor(lambda: self.world.GetBlock(x, z, y) == 0, timeout=5):288        return True289    else:290      logging.error('could not break block: %s, type: %d', str(xzy), blocktype)291      return False292  def nav_to(self, x, z, y): 293    if not self.WaitFor(lambda: self._pos.x != 0.0 and self._pos.y != 0.0):294      logging.error('current position could not be found')295      return False296    botXzy = self._pos.xzy()297    nextXzy = mc.Xzy(x, z, y)298    if botXzy == nextXzy:299      return True300    distance = cityblock(botXzy, nextXzy)301    path = self.find_path(nextXzy, limit=min(sys.maxint, distance**2))302    if path is None:303      logging.error('could not find path')304      return False305    for step in path:306      if not self.MoveTo(*step):307        logging.error('could not make it to: %s failed at: %s', str(nextXzy), str(step))308        return False309    return True310  def MoveTo(self, x, z, y, speed=4.25, onGround=True):311    x+=0.5312    z+=0.5313    def MyDist(x, z, y):314      return abs(pos.x - x) + abs(pos.z - z) + abs(pos.y - y)315    def Go(x=None, z=None, y=None):316      logging.debug('moving to: (%d, %d, %d)', x, z, y)317      self._pos = mc.Position(x, y, y+1, z, yaw, 0, onGround)318    pos = self._pos319    yaw = pos.yaw320    if z - pos.z > .9:321      yaw = 0322    if z - pos.z < - .9:323      yaw = 180324    if x - pos.x > .9:325      yaw = 270326    if x - pos.x < - .9:327      yaw = 90328    tau = 0.010329    delta = speed * tau330    while MyDist(x, z, y) > (delta * 2):331      if pos.x - x > 0:332        new_x = pos.x - delta333      else:334        new_x = pos.x + delta335      if pos.z - z > 0:336        new_z = pos.z - delta337      else:338        new_z = pos.z + delta339      if pos.y - y > 0:340        new_y = pos.y - delta341      else:342        new_y = pos.y + delta343      Go(new_x, new_z, new_y)344      time.sleep(tau)345      if (self._pos.x, self._pos.z, self._pos.y) != (new_x, new_z, new_y):346        logging.error('did not move: %s', str(self._pos.xzy()))347        return False348      pos = self._pos349    Go(x, z, y)350    time.sleep(tau)351    if (self._pos.x, self._pos.z, self._pos.y) != (x, z, y):352      logging.error('did not move: %s', str(self._pos.xzy()))353      return False354    return True355  def FloatDown(self):356    logging.debug('floating down')357    logging.debug('waiting for pos to load')358    self.WaitFor(lambda: self._pos.x != 0.0 and self._pos.y != 0.0)359    logging.debug('waiting for block to load')360    self.WaitFor(lambda: self.world.GetBlock(361      self._pos.x, self._pos.z, self._pos.y) is not None)362    pos = self._pos.xzy()363    logging.debug('waiting for block to load')364    self.MoveTo(*pos)365    for y in range(pos.y + 1, 0, -1):366      pos = pos._replace(y=y)367      logging.debug('floating down: %s', str(pos))368      if self.world.IsStandable(*pos):369        logging.info('floating down: %s', str(pos))370        self.MoveTo(*pos)371        return372  def attack_entity(self, eid, times=5, delay=0.01):373    for i in xrange(times):374      self.SendUseEntity(self._entityId, eid, 1)375      time.sleep(delay)376  def get_best_tool(self, blockType):377    best_tools = (378        (set([1,4,14,15,16,48,61,87,89,98,109,112,113,114]), set([257, 278])), # pickaxe379        (set([2,3,12,13,88]), set([256, 277])), # shovel380        (set([5,17,18,47,53,54,58,64,72,106,107,125,126]), set([258, 279])), # axe381      )382    for blocktypes, tool_ids in best_tools:383      if blockType in blocktypes:384        for tool_id in tool_ids:385          if self.equip_tool(tool_id):386            return True387        return False388    return False389  def change_held_slot(self, slot_num):390    self.SendHeldItemChange(slot_num)391    self._held_slot_num = slot_num392  def get_slot(self, window_id, slot_num):393    return self.windows[window_id]._slots[slot_num]394  def click_slot(self, window_id, slot_num, right_click=0, shift=0):395    action_id = self._action_id.next()396    if slot_num in range(len(self.windows[window_id]._slots)):397      slot_data = self.get_slot(window_id, slot_num)398    else:399      slot_data = mc.Slot(itemId=-1, count=None, meta=None, data=None) 400    self.SendClickWindow(window_id, slot_num, right_click, action_id, shift, slot_data)401    if self.WaitFor(lambda: action_id in self._confirmations.keys(), timeout=5):402      if self._confirmations[action_id].accepted:403        if shift == 0:404          if slot_num in range(len(self.windows[window_id]._slots)):405            self.windows[window_id]._slots[slot_num] = self._cursor_slot406          self._cursor_slot = slot_data407        return True408    return False409  def find_tool(self, tool_id, window_id=0, storage_only=False, inventory_only=False, held_only=False, no_data=False):410    if storage_only:411      start = 0412      end = len(self.windows[window_id]._slots) - 35413    elif inventory_only:414      start = len(self.windows[window_id]._slots) - 36415      end = len(self.windows[window_id]._slots)416    elif held_only:417      start = len(self.windows[window_id]._slots) - 9418      end = len(self.windows[window_id]._slots)419    else:420      start = 0421      end = len(self.windows[window_id]._slots)422    for i, slot in enumerate(self.windows[window_id]._slots[start:end], start):423      if slot.itemId == tool_id and (not no_data or slot.data is None):424        return i425      elif tool_id is None and slot.itemId != -1 and (not no_data or slot.data is None):426        return i427    return None428  def equip_tool(self, tool_id):429    if self.get_slot(0, self._held_slot_num+36).itemId == tool_id: return True430    slot_num = self.find_tool(tool_id, held_only=True)431    if slot_num is not None:432      self.change_held_slot(slot_num-36)433      return True434    slot_num = self.find_tool(tool_id, inventory_only=True)435    if slot_num is None: 436      logging.debug('could not find tool_id: %d', tool_id)437      return False438    open_slot_num = self.find_tool(-1, held_only=True)439    if open_slot_num is None:440      held_slot_num = random.randrange(36,45)441      if not self.click_slot(0, held_slot_num, shift=True):442        logging.debug('could not move held item to inventory: %d', held_slot_num)443        return False444    if not self.click_slot(0, slot_num): 445      logging.debug('could not click on slot num: %d', slot_num)446      return False447    if not self.click_slot(0, open_slot_num):448      logging.debug('could not click on slot num: %d', open_slot_num)449      return False450  def run_cmd(self, cmd):451        args = cmd.split()452        if len(args) == 0:453            return454        elif cmd == 'where are you?':455            self.SendChat('x: %d, y: %d, z: %d' % (self._pos.x, self._pos.y, self._pos.z))456  def dig_area(self, bbox, home=None, dump=False, dig_height=0, ignore_blocktypes = [0]):457    logging.info('going to dig: %s', str(bbox))458    time.sleep(3)459    best_against = {460      'pick': [1,4,14,15,16],461      'shovel': [2,3,12,13]462      }463    last_block_type = -1 464    y_range = range(max(bbox['y']), min(bbox['y']), -1)465    z_range = range(min(bbox['z']), max(bbox['z']))466    random.shuffle(z_range)467    x_range = range(min(bbox['x']), max(bbox['x']))468    for y in y_range:469        for z in z_range:470           for x in x_range:471                blockXzy = mc.Xzy(x, z, y)472                if self.world.GetBlock(*blockXzy) is None:473                    logging.info("Waiting for chunks to load...")474                    self.nav_to(x, z, max(bbox['y']))475                    self.WaitFor(lambda: self.world.GetBlock(*blockXzy) is not None)476                blockType = self.world.GetBlock(*blockXzy)477                if blockType in ignore_blocktypes:478                    continue479                if last_block_type != blockType:480                    last_block_type = blockType481                    for tool_name, block_list in best_against.iteritems():482                        if blockType in block_list:483                            if not self.get_best_tool(blockType, tool_name) and home is not None:484                              logging.info('going home to get better tools: %s', str(home))485                              self.nav_to(*home)486                              while not self.get_best_tool(blockType, tool_name):487                                  self.remove_non_tools()488                                  self.move_tools_to_held()489                                  time.sleep(10)490                              self.nav_to(x, z, y + dig_height)491                self.nav_to(x, z, y + dig_height)492                if self.break_block(x, z, y):493                  sys.stdout.write('.')494                else:495                  sys.stdout.write('!')496                sys.stdout.flush()497  def dig_to(self, x, z, y):498    self.MoveTo(*self._pos.xzy())499    path = self.find_path(mc.Xzy(x,z,y), reachable_test=self.world.IsDiggable)500    if path is None:501      logging.error('could not find path')502      return False503    logging.debug('path: %s', str(path))504    for p in path:505      logging.debug('dig: %s, type: %d', str(p), self.world.GetBlock(*p))506      if self.break_block(*p, auto_move=False) and self.break_block(p.x, p.z, p.y + 1, auto_move=False):507        if not self.MoveTo(*p):508          logging.error('could not move to: %s made it to: %s', str(p), str(self._pos.xzy()))509          return False510      else:511        logging.error('could not reach: %s made it to: %s', str((x,z,y)), str(self._pos.xzy()))512        return False513    #logging.info('done')514    return True515  def find_path(self, end, reachable_test=None, limit=None):516    if limit is None:517      limit = cityblock(self._pos.xzy(), end)**2518    def iter_moveable_adjacent(start):519      l = []520      for xzy, block_type in self.world.IterAdjacent(*start):521        if reachable_test(*xzy):522          l.append(xzy)523      return l524    def at_goal(xzy):525      if xzy == end:526        return True527      else:528        return False529    def distance(a, b):530      return cityblock(a, b)531    def distance_to_goal(a):532      return cityblock(a, end)533    if reachable_test is None:534      reachable_test = self.world.IsMoveable535    pos = self._pos.xzy()536    logging.debug('looking for path from: %s to: %s', str(pos), str(end))537    path = astar.astar(538        pos, iter_moveable_adjacent, at_goal, 0, 539        distance, distance_to_goal, limit=limit)540    logging.debug('path: %s', str(path))541    return path542  def get_adjacent_blocks(self, block, min_height=0, max_height=255):543    blocks = []544    for offset_y in range(-1, 2):545      for offset_x in range(-1, 2):546        for offset_z in range(-1, 2):547          x = block.x + offset_x548          z = block.z + offset_z549          y = block.y + offset_y550          if y > 0 and y <= max_height and y >= min_height:551            blocks.append(mc.Xzy(x, z, y))552    for xzy in blocks:553      yield xzy554  def iter_find_blocktype(self, types, start=None):555    if start is None:556      start = self._pos557    start_x, start_z = int(start.x / 16), int(start.z / 16)558    s=self._iter_spiral()559    offset_x, offset_z = s.next()560    cx, cz = start_x + offset_x, start_z + offset_z561    while (cx, cz) in self.world._chunks:562      logging.info('chunk: %s', str((cx, cz)))563      for i, b in enumerate(self.world._chunks[(cx, cz)]._blocks): 564        if b in types:565          logging.info('blocktype: %d', b)566          y, r = divmod(i, 256)567          z, x = divmod(r, 16)568          yield mc.Xzy(x + cx*16, z + cz*16, y)569      offset_x, offset_z = s.next()570      cx, cz = start_x + offset_x, start_z + offset_z571  def _iter_spiral(self):572    x = 0573    y = 0574    dx = 0575    dy = -1576    while True:577      yield (x, y)578      if x == y or (x < 0 and x == -y) or (x > 0 and x == 1-y):579        dx, dy = -dy, dx580      x, y = x+dx, y+dy581  def iter_find_nearest_blocktype(self, start, types=[15], max_height=96, min_height=0):582    height_dict = {583      14: 32, #gold584      15: 64, #iron585      56: 17, #diamonds586    }587    if max_height is None:588      if set(types).issubset(height_dict.keys()):589        max_height = max([h for t, h in height_dict.items() if t in types])590      else:591        max_height = 96592    checked_blocks = set([])593    unchecked_blocks = collections.deque([start])594    block_type = 0595    while len(unchecked_blocks) != 0:596      block = unchecked_blocks.popleft()597      checked_blocks.add(block)598      for block in self.get_adjacent_blocks(block, min_height=min_height, max_height=max_height):599        if block not in checked_blocks and block not in unchecked_blocks and self.world.GetBlock(*block) is not None:600          unchecked_blocks.append(block)601      block_type = self.world.GetBlock(*block)602      if block_type in types:603        yield block604  def help_find_blocks(self, types=[14, 56], chat=True, start=None):605    LAVA = set([10,11])606    if start is None:607      start = self._pos.xzy()608    else:609      self.nav_to(start.x, start.z, 200)610    logging.info('waiting for world to load...')611    self.WaitFor(lambda: self.world.GetBlock(self._pos.x, self._pos.z, self._pos.y) is not None)612    block_iter = self.iter_find_blocktype(types, start=start)613    while True:614      block = block_iter.next()615      if block.y <= 5: continue616      if LAVA.issubset([blocktype for xzy, blocktype in bot.world.IterAdjacent(*block)]): continue617      blocktype = self.world.GetBlock(*block)618      logging.info('%s, %s', str(block), str(self._block_names[blocktype]))619      if chat:620        self.SendChat('%s. type: %s' % (str(block), self._block_names[blocktype]))621      try:622        while not self.WaitFor(lambda: self.world.GetBlock(*block) not in types):623          pass624      except KeyboardInterrupt:625        try:626          print 'break again to stop'627          time.sleep(1)628          continue629        except KeyboardInterrupt:630          return631  def get_player_position(self, player_name):632    for entity in self.world._entities.values():633      if entity._player_name == player_name:634        return entity._pos.xzy()635  def move_to_player(self, player_name):636    xzy = self.get_player_position(player_name)637    logging.info('moving to player: %s at: %s', player_name, str(xzy))638    if xzy is not None:639      self.nav_to(*xzy)640  def click_inventory_block(self, xzy):641    if self._open_window_id != 0:642      return False643    s = mc.Slot(itemId=-1, count=None, meta=None, data=None)644    self.SendPlayerBlockPlacement(xzy.x, xzy.y, xzy.z, 1,  s)645    if self.WaitFor(lambda: self._open_window_id != 0):646      if self.WaitFor(lambda: self._open_window_id in self.windows):647        return True648    return False649  def iter_nearest(self, start):650    checked_blocks = set([])651    unchecked_blocks = collections.deque([start])652    while len(unchecked_blocks) != 0:653      block = unchecked_blocks.popleft()654      checked_blocks.add(block)655      for block in self.get_adjacent_blocks(block):656        if block not in checked_blocks and block not in unchecked_blocks and self.world.GetBlock(*block) is not None:657          unchecked_blocks.append(block)658        yield block659  def iter_nearest_moveable(self, start):660    for block in self.iter_nearest(start):661      if self.world.IsMoveable(*block):662        yield block663  def iter_nearest_radius(self, start, radius):664    block = self.iter_nearest(start)665    while euclidean(start, block.next()) <= radius:666      yield block.next()667  def place_block(self, xzy):668    def get_block_direction(a, b):669      if a.y < b.y: return 0670      elif a.y > b.y: return 1671      elif a.z < b.z: return 2672      elif a.z > b.z: return 3673      elif a.x < b.x: return 4674      elif a.x > b.x: return 5675    SOLID = set(range(1, 5) + [7] + range(12, 27))676    m= self.iter_nearest_moveable(xzy)677    block = m.next()678    while euclidean(xzy, block) <= 6:679      if self.nav_to(*block): break680      block = m.next()681    else:682      logging.error('too far to place block')683      return False684    slot = self.get_slot(0, self._held_slot_num+36)685    for block, blocktype in self.world.IterAdjacent(*xzy):686      if blocktype in SOLID:687        direction = get_block_direction(xzy, block)688        logging.debug('sending block placement command: %s, direction: %d, slot_data: %s', str(block), direction, str(slot))689        self.SendPlayerBlockPlacement(block.x, block.y, block.z, direction,  slot)690        if self.WaitFor(lambda: self.world.GetBlock(*xzy) == slot.itemId, timeout=5):691          return True692        else:693          logging.error('placed blocktype did not change')694          return False695    else:696      logging.error('could not find solid adjacent block')697      return False698  def fill_adjacent_liquid(self, xzy):699    LIQUID = set(range(8,12))700    SOLID = set([1,3,4])701    for block, blocktype in self.world.IterAdjacent(*xzy):702      if blocktype in LIQUID:703        solid_blocktype = SOLID.intersection(self.get_inventory_ids())704        if len(solid_blocktype) == 0: return False705        if not self.equip_tool(solid_blocktype): return False706        if not self.place_block(block): return False707        return True708  def close_window(self):709    window_id = self._open_window_id710    self._open_window_id = 0711    self.SendCloseWindow(window_id)712    if window_id != 0:713      del self.windows[window_id]714    time.sleep(1)715  def enchant(self, tool_id, max_distance=100):716    ENCHANTMENT_TABLE=116717    pos = self._pos.xzy()718    logging.info('finding nearest enchanting table')719    table = self.iter_find_nearest_blocktype(pos, types=[ENCHANTMENT_TABLE]).next()720    if cityblock(pos, table) > max_distance:721      logging.error('too far from enchanting table') 722      return False723    logging.info('moving to enchanting table')724    if not self.nav_to(*table):725      logging.error('did not make it to enchanting table')726      return False727    self.close_window()728    logging.info('opening enchantment window')729    if not self.click_inventory_block(table):730      logging.error('could not open enchantment window')731      return False732    window_id = self._open_window_id733    logging.info('looking for tool')734    slot_num = self.find_tool(tool_id, window_id=window_id, inventory_only=True, no_data=True)735    if slot_num is None:736      logging.error('could not find tool to enchant')737      return False738    if not self.click_slot(window_id, slot_num):739      logging.error('could not grab tool to enchant')740      return False741    logging.info('looking for best enchantment level')742    target_level = min(self._xp_level, 50)743    while target_level not in self._available_enchantments.values():744      if not self.click_slot(window_id, 0):745        logging.error('failed to place tool on enchanting table')746        return False747      if self._cursor_slot.itemId == -1:748        self.WaitFor(lambda: sum(self._available_enchantments.values()) != 0, timeout=5)749        logging.debug('enchantment level: %d', max(self._available_enchantments.values()))750    enchantment_num = [ k for k, v in self._available_enchantments.items() if v == target_level ][0]751    logging.info('enchanting item')752    self.SendEnchantItem(self._open_window_id, enchantment_num)753    if not self.WaitFor(lambda: self.windows[window_id]._slots[0].data is not None, timeout=5):754      logging.error('enchant tool command failed')755      return False756    if not self.click_slot(window_id, 0):757      logging.error('could not grab enchanted tool')758      return False759    if not self.click_slot(window_id, slot_num):760      logging.error('could not place enchanted tool in inventory')761      return False762    logging.info('closing enchantment window')763    self.close_window()764    return True765  def eat(self, target_food_level=20):766    logging.info('eating')767    BREAD = 297768    if not self.equip_tool(BREAD):769      logging.debug('could not equip bread')770      return False771    slot = self.get_slot(0, self._held_slot_num+36)772    if slot is None:773      return False774    while slot.itemId == BREAD and slot.count > 0 and self._food < target_food_level:775      self.SendPlayerBlockPlacement(-1, -1, -1, -1, slot)776      time.sleep(1)777      slot = self.get_slot(0, self._held_slot_num+36)778    time.sleep(1)779    self.SendPlayerDigging(5, 0, 0, 0, 255)780    logging.debug('food level: %d, bread slot: %s', self._food, str(slot))781    if self._food == target_food_level:782      return True783    else:784      return False785  def get_inventory(self):786    return [ (slot_num, item) for slot_num, item in enumerate(self.windows[0]._slots) if item.itemId != -1 ]787  def get_inventory_ids(self):788    return [ item.itemId for slot_num, item in enumerate(self.windows[0]._slots) if item.itemId != -1 ]789  def drop_items(self, item_ids, invert=False, single=False):790    if self._open_window_id != 0:791      return False792    if len(item_ids) == 0:793      drop_list = [ slot_num for slot_num, item in self.get_inventory() ]794    elif invert:795      drop_list = [ slot_num for slot_num, item in self.get_inventory() if item.itemId not in item_ids ]796    else:797      drop_list = [ slot_num for slot_num, item in self.get_inventory() if item.itemId in item_ids ]798    for slot_num in drop_list:799      if slot_num >= 9:800        if not self.click_slot(0, slot_num):801          return False802        if not self.click_slot(0, -999):803          return False804      if single:805        return True806    else:807      return True808  def find_chest_with_item(self, tool_id, timeout=60):809    start_time = time.time()810    self.close_window()811    for chest_block in self.iter_find_blocktype([self._block_ids['chest']]):812      self.nav_to(*chest_block)813      if self.click_inventory_block(chest_block):814        if tool_id in [ item.itemId for item in self.windows[self._open_window_id]._slots ]:815          self.close_window()816          return chest_block817      self.close_window()818    if time.time() > start_time + timeout:819      logging.error('timed out looking for tool')820      self.close_window()821      return None822  def get_item_from_chest(self, tool_id, chest_block, ignore_special=False):823    if not self.click_inventory_block(chest_block): return False824    source_slot_num = self.find_tool(tool_id, window_id=self._open_window_id, storage_only=True, no_data=ignore_special)825    source_tool_id = self.windows[self._open_window_id]._slots[source_slot_num].itemId826    if source_slot_num is None: return False827    if not self.click_slot(self._open_window_id, source_slot_num, shift=1): return False828    if tool_id is None:829      self.close_window()830      return source_tool_id831    else:832      self.close_window()833      return True834  def put_item_into_chest(self, tool_id, chest_block):835    if self.click_inventory_block(chest_block):836      source_slot_num = self.find_tool(tool_id, window_id=self._open_window_id, inventory_only=True)837      target_slot_num = self.find_tool(-1, window_id=self._open_window_id, storage_only=True)838      if source_slot_num is not None and target_slot_num is not None:839        if self.click_slot(self._open_window_id, source_slot_num):840          if self.click_slot(self._open_window_id, target_slot_num):841            self.close_window()842            return True843    self.close_window()844    return False845if __name__ == '__main__':846  parser = optparse.OptionParser()847  parser.add_option("-s", "--server", dest="server", default="localhost",848                        help="server", metavar="SERVER")849  parser.add_option("-P", "--port", dest="port", default=25565, type="int",850                        help="port", metavar="PORT")851  parser.add_option("-u", "--user", dest="user",852                        help="user to login as", metavar="USER")853  parser.add_option("-p", "--pass", dest="password",854                        help="password", metavar="PASSWORD")855  parser.add_option("-b", "--bbox", dest="bbox", default='jungle',856                        help="digging bbox", metavar="BBOX")857  parser.add_option("-r", "--return-base", dest="return_base", default='base',858                        help="base to return to for better tools", metavar='BASE')859  parser.add_option('-v', '--verbose', dest='verbose', action='count',860                  help="Increase verbosity (specify multiple times for more)")861  (options, args) = parser.parse_args()862  if options.verbose >= 1: log_level = logging.DEBUG863  else: log_level = logging.INFO864  logging.basicConfig(level=log_level)865  with open('sites.json') as f:866    sites = json.load(f)867    bboxes = sites['bboxes']868    return_bases = sites['return_bases']869  bbox = bboxes[options.bbox]870  home = return_bases[options.return_base] 871  server = options.server872  port = options.port873  password = options.password874  if options.user is not None: 875    username = options.user876  else:877    bot_names = ['peon', 'serf', 'grunt', 'slave', 'drudge', 'farmboy', 'peasant']878    for name in bot_names:879      if not os.path.isfile(os.path.join('/tmp', name)):880        username = name881        break882    else:883      raise Exception('All usernames are logged in')884  if len(args) > 0: 885    cmd = args.pop(0)886    if cmd in ['kill', 'terraform']:887      import scrap888      funcs = {'kill': scrap.kill, 'terraform': scrap.terraform}889      users = {'kill': 'merlin', 'terraform': 'bob'}890      fighting = {'kill': False, 'terraform': True}891      server = 'mc.gmendiola.com'892      bot = MineCraftBot(server, port, users[cmd], password=password, fighting=fighting[cmd])893      bot.WaitFor(lambda: bot._pos.x != 0.0 and bot._pos.y != 0.0)894      time.sleep(5)895      funcs[cmd](bot)896    elif cmd == 'explore':897      username = 'dora'898      bot = MineCraftBot(server, port, username, password=password)899      bot.WaitFor(lambda: bot._pos.x != 0.0 and bot._pos.y != 0.0)900      time.sleep(2)901      import scrap902      scrap.explore(bot)903    if cmd == 'test':904      bot = MineCraftBot(server, port, username, password=password)905      bot.WaitFor(lambda: bot._pos.x != 0.0 and bot._pos.y != 0.0)906      logging.info('bot ready')907    elif cmd == 'help':908      types = [14,15,16,56]909      bot = MineCraftBot(server, port, username, password=password)910      time.sleep(5)911      print bot._pos.xzy()912      start = bot.get_player_position('magahet')913      if start is None:914        x = float(raw_input('x: ').strip())915        z = float(raw_input('z: ').strip())916        start = mc.Xzy(x, z, 0)917      bot.help_find_blocks(start, types=types)918    elif cmd == 'dig':919      bot = MineCraftBot(server, port, username, password=password)...mc.py
Source:mc.py  
1import array2import collections3import Queue4import struct5import sys6import os7import threading8import time9import urllib10import urllib211import zlib12import math13import logging14class Slot(collections.namedtuple('Slot', ('itemId', 'count', 'meta', 'data'))):15  pass16class Window(object):17  def __init__(self, windowId, slots):18    self._slots = slots19    self._count = len(slots)20    self.inventory_type = None21    self.window_title = None22  def GetMainInventory(self):23    return self._slots[-36:-9]24  def GetHeld(self):25    return self._slots[-9:]26  def SetSlot(self, index, slot):27    self._slots[index] = slot28class Xzy(collections.namedtuple('Xzy', ('x', 'z', 'y'))):29  def __new__(cls, *args, **kwargs):30    args = map(math.floor, args)31    args = map(int, args)32    for k, v in kwargs.iteritems():33      kwargs[k] = int(math.floor(v))34    return super(Xzy, cls).__new__(cls, *args, **kwargs)35  def Offset(self, x=0, z=0, y=0):36    return Xzy(self.x + x, self.z + z, self.y + y)37class World(object):38  def __init__(self):39    self._chunks = {}40    self._entities= {}41    pass42  def MapChunk(self, chunk):43    self._chunks[chunk.chunkX, chunk.chunkZ] = chunk44  def SetBlock(self, x, z, y, newType, newMeta):45    chunk = self._chunks.get((int(x/16), int(z/16)))46    if not chunk:47      return None48    return chunk.SetBlock(int(x), int(z), int(y), newType, newMeta)49  def GetBlock(self, x, z, y):50    chunk = self._chunks.get((int(x/16), int(z/16)))51    if chunk is None:52      return None53    return chunk.GetBlock(int(x), int(z), int(y))54  def IsJumpable(self, x, z, y):55    SOLID = set(range(1, 5) + [7] + range(12, 27))56    return (57        (self.GetBlock(x, z, y - 2) in SOLID or58         self.GetBlock(x, z, y - 1) in SOLID) and59        self.GetBlock(x, z, y)     not in SOLID and60        self.GetBlock(x, z, y + 1) == 061        )62  def IsMoveable(self, x, z, y):63    NON_SOLID = set([0,6,27,28,31,32,37,38,39,40,50,55,59,63,65,66,68,69,70,72,75,76,78,93,94,96,106,111,115,])64    standable = (65        self.GetBlock(x, z, y) in NON_SOLID and66        self.GetBlock(x, z, y + 1) in NON_SOLID67    )68    return standable69  def IsStandable(self, x, z, y):70    SOLID = set(range(1, 5) + [7] + range(12, 27))71    standable = (72        self.GetBlock(x, z, y - 1) in SOLID and73        self.GetBlock(x, z, y)     == 0 and74        self.GetBlock(x, z, y + 1) == 075    )76    return standable77  def IsDiggable(self, x, z, y):78    UNDIGGABLE= set([7])79    NON_SOLID = set(range(8, 14))80    if self.GetBlock(x, z, y) in UNDIGGABLE or self.GetBlock(x, z, y + 1) in UNDIGGABLE:81      return False82    for xzy, block_type in self.IterAdjacent(x, z, y):83      if block_type in NON_SOLID:84        return False85    for xzy, block_type in self.IterAdjacent(x, z, y + 1):86      if block_type in NON_SOLID:87        return False88    return True89  def IterAdjacent(self, x, z, y):90    adjacents = [91        Xzy(x, z, y - 1),92        Xzy(x + 1, z, y),93        Xzy(x - 1, z, y),94        Xzy(x, z - 1, y),95        Xzy(x, z + 1, y),96        Xzy(x, z, y + 1),97        ]98    for xzy in adjacents:99      yield xzy, self.GetBlock(*xzy)100  def find_nearest_standable(self, xzy, within=100):101    maxD = 100102    d = {}103    d[xzy] = 0104    queue = [xzy]105    while queue:106      current_xzy = queue.pop(0)107      xzyD = d[current_xzy]108      if xzyD > maxD:109        break110      if self.IsStandable(*current_xzy) and cityblock(xzy, current_xzy) < within:111        return xzy112      for xzyAdj, blockAdj in self.IterAdjacent(*xzy):113        if xzyAdj in d:114          continue115        if self.IsJumpable(*xzyAdj):116          d[xzyAdj] = xzyD + 1117          queue.append(xzyAdj)118    return None119  def FindNearestStandable(self, xzy, condition):120    maxD = 100121    d = {}122    d[xzy] = 0123    queue = [xzy]124    while queue:125      xzy = queue.pop(0)126      xzyD = d[xzy]127      if xzyD > maxD:128        break129      if self.IsStandable(*xzy) and condition(xzy):130        return xzy131      for xzyAdj, blockAdj in self.IterAdjacent(*xzy):132        if xzyAdj in d:133          continue134        if self.IsJumpable(*xzyAdj):135          d[xzyAdj] = xzyD + 1136          queue.append(xzyAdj)137    return None138  def FindPath(self, xzyA, xzyB):139    xzyA = Xzy(*xzyA)140    xzyB = Xzy(*xzyB)141    d = {}142    d[xzyA] = 0143    queue = [xzyA]144    while queue and xzyB not in d:145      xzy = queue.pop(0)146      xzyD = d[xzy]147      for xzyAdj, blockAdj in self.IterAdjacent(*xzy):148        if xzyAdj not in d and self.IsMoveable(*xzyAdj):149          d[xzyAdj] = xzyD + 1150          queue.append(xzyAdj)151    if xzyB not in d:152      return None153    path = [xzyB]154    while path[-1] != xzyA:155      for xzyAdj, blockAdj in self.IterAdjacent(*path[-1]):156        if xzyAdj in d and d[xzyAdj] < d[path[-1]]:157          path.append(xzyAdj)158          break159    path.reverse()160    return path161class Position(collections.namedtuple('Position',162    ('x', 'y', 'stance', 'z', 'yaw', 'pitch', 'on_ground'))):163  def xzy(self):164      return Xzy(self.x, self.z, self.y)165class Confirmation(collections.namedtuple('Confirmation', ('window_id', 'action_id', 'accepted'))):166  pass167class Entity(object):168  def __init__(self, eid, etype, x, y, z, yaw, pitch, player_name=None, current_item=None, head_yaw=0, metadata=None):169    self._eid = eid170    self._type= etype171    self._pos = Position(x/32, y/32, (y/32)+1, z/32, yaw, pitch, 1)172    self._player_name = player_name173    self._current_item = current_item174    self._head_yaw = head_yaw175    self._metadata = metadata176  def Move(self, dx, dy, dz):177    if None not in self._pos.xzy():178      x = self._pos.x + (dx/32.0)179      z = self._pos.z + (dz/32.0)180      y = self._pos.y + (dy/32.0)181      yaw = self._pos.yaw182      pitch = self._pos.pitch183      self._pos = Position(x, y, y+1, z, yaw, pitch, 1)184  def Teleport(self, x, y, z):185    yaw = self._pos.yaw186    pitch = self._pos.pitch187    self._pos = Position(x/32.0, y/32.0, (y/32.0)+1, z/32.0, yaw, pitch, 1)188class ChunkColumn(object):189  def __init__(self, chunkX, chunkZ,190      blockData, blockMeta, lightData, skyLightData, addArray, biomeData):191    self.chunkX = chunkX192    self.chunkZ = chunkZ193    self._blocks = blockData194    self._meta = blockMeta195    self._light = lightData196    self._skylight = skyLightData197    self._addArray = addArray198    self._skyLightData = skyLightData199    self._biome = biomeData200  def _GetOffset(self, x, z, y):201    x, z, y = int(x), int(z), int(y)202    return (       (x - self.chunkX * 16) +203            (16 *  (z - self.chunkZ * 16)) +204            (256 * (y))205           )206  def SetBlock(self, x, z, y, newType, newMeta):207    # TODO: what about extra 4 bits?208    offset = self._GetOffset(x, z, y)209    self._blocks[offset] = (newType & 0xff)210    return newType211  def GetBlock(self, x, z, y):212    offset = self._GetOffset(x, z, y)213    if offset < len(self._blocks):214      blocktype = self._blocks[offset]215      return blocktype216class MineCraftProtocol(object):217  def __init__(self):218    self._sock = None219    self._sockGeneration = 0220    self._recvCondition = threading.Condition()221    self._buf = ""222    self._sendQueue = Queue.Queue(10)223    self.parentPID = os.getppid()224    self._threads = []225    self._threadFuncs = [226        self._DoReadThread,227        self._DoSendThread,228        ]229    self._parsers = {230        '\x00': self.ParseKeepAlive,231        '\x01': self.ParseLogin,232        '\x02': self.ParseHandshake,233        '\x03': self.ParseChatMessage,234        '\x04': self.ParseTimeUpdate,235        '\x05': self.ParseEntityEquipment,236        '\x06': self.ParseSpawn,237        #'\x07': client only238        '\x08': self.ParseUpdateHealth,239        '\x09': self.ParseRespawn,240        '\x10': self.ParseHeldItemChange,241        #'\x0a': client only242        #'\x0b': client only243        '\x0c': self.ParsePlayerLook,244        '\x0d': self.ParsePlayerPositionLook,245        #'\x0e': client only246        #'\x0f': client only247        #'\x10': client only248        '\x11': self.ParseUseBed,249        '\x12': self.ParseAnimation,250        #'\x13': client only251        '\x14': self.ParseSpawnNamedEntity,252        '\x15': self.ParseSpawnDroppedItem,253        '\x16': self.ParseCollectItem,254        '\x17': self.ParseSpawnObjectVehicle,255        '\x18': self.ParseSpawnMob,256        '\x19': self.ParseSpawnPainting,257        '\x1a': self.ParseSpawnExperienceOrb,258        #'\x1b': self.ParseStanceUpdate,259        '\x1c': self.ParseEntityVelocity,260        '\x1d': self.ParseDestroyEntity,261        '\x1e': self.ParseEntity,262        '\x1f': self.ParseEntityRelativeMove,263        '\x20': self.ParseEntityLook,264        '\x21': self.ParseEntityRelativeLookAndMove,265        '\x22': self.ParseEntityTeleport,266        '\x23': self.ParseEntityHeadLook,267        '\x26': self.ParseEntityStatus,268        '\x27': self.ParseAttachEntity,269        '\x28': self.ParseEntityMetadata,270        '\x29': self.ParseEntityEffect,271        '\x2a': self.ParseRemoveEntityEffect,272        '\x2b': self.ParseSetExperience,273        '\x32': self.ParseMapColumnAllocation,274        '\x33': self.ParseMapChunks,275        '\x34': self.ParseMultiBlockChange,276        '\x35': self.ParseBlockChange,277        '\x36': self.ParseBlockAction,278        '\x3c': self.ParseExplosion,279        '\x3d': self.ParseSoundParticleEffect,280        '\x46': self.ParseChangeGameState,281        '\x47': self.ParseThunderbolt,282        '\x64': self.ParseOpenWindow,283        '\x65': self.ParseCloseWindow,284        '\x67': self.ParseSetSlot,285        '\x68': self.ParseSetWindowItems,286        '\x69': self.ParseUpdateWindowProperty,287        '\x6a': self.ParseConfirmTransaction,288        '\x6b': self.ParseCreativeInventoryAction,289        '\x82': self.ParseUpdateSign,290        '\x83': self.ParseItemData,291        '\x84': self.ParseUpdateTileEntity,292        '\xc8': self.ParseIncrementStatistic,293        '\xc9': self.ParsePlayerListItem,294        '\xca': self.ParsePlayerAbility,295        '\xff': self.ParseKick,296        }297    self._interesting = set([298        #'\x00', #KeepAlive299        #'\x01', #Login300        #'\x02', #Handshake301        #'\x03', #ChatMessage302        #'\x04', #TimeUpdate303        #'\x05', #EntityEquipment304        #'\x06', #Spawn305        #'\x08', #UpdateHealth306        #'\x09', #Respawn307        #'\x0e', #PlayerDigging308        #'\x10', #HeldItemChange309        #'\x0c', #PlayerLook310        #'\x0d', #PlayerPositionLook311        #'\x11', #UseBed312        #'\x12', #Animation313        #'\x14', #SpawnNamedEntity314        #'\x15', #SpawnDroppedItem315        #'\x16', #CollectItem316        #'\x17', #SpawnObjectVehicle317        #'\x18', #SpawnMob318        #'\x19', #SpawnPainting319        #'\x1a', #SpawnExperienceOrb320        #'\x1b', #StanceUpdate321        #'\x1c', #EntityVelocity322        #'\x1d', #DestroyEntity323        #'\x1f', #EntityRelativeMove324        #'\x20', #EntityLook325        #'\x21', #EntityRelativeLookAndMove326        #'\x22', #EntityTeleport327        #'\x23', #EntityHeadLook328        #'\x26', #EntityStatus329        #'\x27', #AttachEntity330        #'\x28', #EntityMetadata331        #'\x29', #EntityEffect332        #'\x2a', #RemoveEntityEffect333        #'\x2b', #SetExperience334        #'\x32', #MapColumnAllocation335        #'\x33', #MapChunks336        #'\x34', #MultiBlockChange337        #'\x35', #BlockChange338        #'\x36', #BlockAction339        #'\x3c', #Explosion340        #'\x3d', #SoundParticleEffect341        #'\x46', #ChangeGameState342        #'\x47', #Thunderbolt343        #'\x64', #OpenWindow344        #'\x65', #CloseWindow345        #'\x67', #SetSlot346        #'\x68', #SetWindowItems347        #'\x69', #UpdateWindowProperty348        #'\x6a', #ConfirmTransaction349        #'\x6b', #CreativeInventoryAction350        #'\x82', #UpdateSign351        #'\x83', #ItemData352        #'\x84', #UpdateTileEntity353        #'\xc8', #IncrementStatistic354        #'\xc9', #PlayerListItem355        #'\xca', #PlayerAbility356        #'\xff', #Kick357        ])358    self._handlers = {}359  ##############################################################################360  # minecraft.net methods361  def GetSessionId(self, username, password):362    data = urllib.urlencode((363        ('user', username),364        ('password', password),365        ('version', '1337'),366        ))367    sessionString = urllib2.urlopen('https://login.minecraft.net/', data).read()368    return sessionString.split(':')[3]369  def JoinServer(self, username, sessionId, serverId):370    data = urllib.urlencode((371        ('user', username),372        ('sessionId', sessionId),373        ('serverId', serverId),374        ))375    url = 'http://session.minecraft.net/game/joinserver.jsp?' + data376    return urllib2.urlopen(url).read()377  ##############################################################################378  # Thread functions379  def StartThreads(self):380    self._threads = []381    for func in self._threadFuncs:382      thread = threading.Thread(target=func)383      thread.daemon = True384      thread.start()385      self._threads.append(thread)386    return self387  def _DoReadThread(self):388    try:389      myGeneration = self._sockGeneration390      while myGeneration == self._sockGeneration:391        self.RecvPacket()392        if os.getppid() != self.parentPID:393          pass394          #print "ReadThread exiting", myGeneration395          #sys.exit()396    finally:397      os.kill(self.parentPID, 0)398  def _DoSendThread(self):399    try:400      myGeneration = self._sockGeneration401      sock = self._sock402      queue = self._sendQueue403      while myGeneration == self._sockGeneration and self._sock is not None:404        sock.sendall(queue.get())405        if os.getppid() != self.parentPID:406          pass407          #print "SendThread exiting", myGeneration408    finally:409      os.kill(self.parentPID, 0)410  ##############################################################################411  # Protocol convenience methods412  def Send(self, packet):413    if packet[0] in self._interesting:414    #if True:415      sys.stderr.write('\nSending packet: %s\n' % hex(ord(packet[0])))416    self._sendQueue.put(packet)417  def Read(self, size):418    while len(self._buf) < size:419      recieved = self._sock.recv(4096)420      self._buf += recieved421    ret = self._buf[:size]422    self._buf = self._buf[size:]423    return ret424  def RecvPacket(self):425    ilk = self.Read(1)426    try:427      parsed = self._parsers[ilk]()428      if ilk in self._interesting:429        logging.debug('Parsed packet: %s (buf: %d)', hex(ord(ilk)), len(self._buf))430      handler = self._handlers.get(ilk)431      if handler:432        handler(*parsed)433      with self._recvCondition:434        self._recvCondition.notifyAll()435    except KeyError:436      sys.stderr.write('unknown packet: %s\n' % hex(ord(ilk)))437      raise438      i = ''439      while i != '\x00':440        i = self.Read(1)441        sys.stderr.write('%s  ' % hex(ord(i)))442      sys.stderr.write('back on track\n')443  def WaitFor(self, what, timeout=10):444    start = time.time()445    with self._recvCondition:446      while not what() and time.time() - start < timeout:447        self._recvCondition.wait(timeout=1)448    return what()449  def PackString(self, string):450    return struct.pack('!h', len(string)) + string.encode('utf_16_be')451  def PackSlot(self, slot_data):452    itemId, count, meta, data = slot_data453    packet = struct.pack('!h', itemId)454    if itemId == -1:455      return packet456    packet += (struct.pack('!b', count) +457      struct.pack('!h', meta)458      )459    if ((256 <= itemId <= 259) or460        (267 <= itemId <= 279) or461        (283 <= itemId <= 286) or462        (290 <= itemId <= 294) or463        (298 <= itemId <= 317) or464        itemId == 261 or itemId == 359 or itemId == 346):465      if data is None:466        packet += struct.pack('!h', -1)467      else:468        packet += struct.pack('!h', len(data)) + data469    return packet470  def UnpackInt8(self):471    value, = struct.unpack('!b', self.Read(1))472    return value473  def UnpackUint8(self):474    value, = struct.unpack('!B', self.Read(1))475    return value476  def UnpackInt16(self):477    value, = struct.unpack('!h', self.Read(2))478    return value479  def UnpackInt32(self):480    value, = struct.unpack('!i', self.Read(4))481    return value482  def UnpackInt64(self):483    value, = struct.unpack('!q', self.Read(8))484    return value485  def UnpackFloat(self):486    value, = struct.unpack('!f', self.Read(4))487    return value488  def UnpackDouble(self):489    value, = struct.unpack('!d', self.Read(8))490    return value491  def UnpackBool(self):492    value, = struct.unpack('?', self.Read(1))493    return value494  def UnpackString(self):495    strlen = self.UnpackInt16()496    string = self.Read(strlen * 2).decode('utf_16_be')497    return string498  def UnpackSlot(self):499    itemId = self.UnpackInt16()500    if itemId == -1:501      return Slot(itemId, None, None, None)502    itemCount = self.UnpackInt8()503    meta = self.UnpackInt16()  # damage, or block meta504    data = None505    # These certain items are capable of having meta/enchantments506    if ((256 <= itemId <= 259) or507        (267 <= itemId <= 279) or508        (283 <= itemId <= 286) or509        (290 <= itemId <= 294) or510        (298 <= itemId <= 317) or511        itemId == 261 or itemId == 359 or itemId == 346):512      arraySize = self.UnpackInt16()513      if arraySize != -1:514        data = self.Read(arraySize)515    return Slot(itemId, itemCount, meta, data)516  517  def UnpackMetadata(self):518    metadata = {}519    x = self.UnpackUint8()520    while x != 127:521        index = x & 0x1F # Lower 5 bits522        ty    = x >> 5   # Upper 3 bits523        if ty == 0: val = self.UnpackInt8()524        if ty == 1: val = self.UnpackInt16()525        if ty == 2: val = self.UnpackInt32()526        if ty == 3: val = self.UnpackFloat()527        if ty == 4: val = self.UnpackString()528        if ty == 5:529            val = {}530            val["id"]     = self.UnpackInt16()531            val["count"]  = self.UnpackInt8()532            val["damage"] = self.UnpackInt16()533        if ty == 6:534            val = []535            for i in range(3):536                val.append(self.UnpackInt32())537        metadata[index] = (ty, val)538        x = self.UnpackInt8()539    return metadata540  ##############################################################################541  # Parsers542  def ParseKick(self):543    sys.stderr.write('Kicked: ' + self.UnpackString() + '\n')544    raise Exception()545  def ParseHandshake(self):546    return (self.UnpackString(),)547  def ParseChatMessage(self):548    chat = self.UnpackString()549    return (chat,)550  def ParseKeepAlive(self):551    return (self.UnpackInt32(),)552  def ParseLogin(self):553    entityId = self.UnpackInt32()554    trash = self.UnpackString()555    levelType = self.UnpackString()556    serverMode = self.UnpackInt32()557    dimension = self.UnpackInt32()558    difficulty = self.UnpackInt8()559    trash = self.UnpackUint8()560    maxPlayers = self.UnpackUint8()561    return (entityId, levelType, serverMode, dimension, difficulty, maxPlayers)562  def ParseSpawn(self):563    return (564        self.UnpackInt32(),565        self.UnpackInt32(),566        self.UnpackInt32(),567        )568  def ParseUpdateHealth(self):569    return (570        self.UnpackInt16(),571        self.UnpackInt16(),572        self.UnpackFloat(),573        )574  def ParseRespawn(self):575    return (576        self.UnpackInt32(),577        self.UnpackInt8(),578        self.UnpackInt8(),579        self.UnpackInt16(),580        self.UnpackString(),581        )582  def ParseHeldItemChange(self):583    return (584        self.UnpackInt16(),585        )586  def ParsePlayerLook(self):587    return (588        self.UnpackFloat(),589        self.UnpackFloat(),590        self.UnpackInt8(),591        )592  def ParsePlayerPositionLook(self):593    return (594        self.UnpackDouble(),595        self.UnpackDouble(),596        self.UnpackDouble(),597        self.UnpackDouble(),598        self.UnpackFloat(),599        self.UnpackFloat(),600        self.UnpackInt8(),601        )602  def ParseUseBed(self):603    return (604        self.UnpackInt32(),605        self.UnpackInt8(),606        self.UnpackInt32(),607        self.UnpackInt8(),608        self.UnpackInt32(),609        )610  def ParseAnimation(self):611    return (612        self.UnpackInt32(),613        self.UnpackInt8(),614        )615  def ParseSpawnNamedEntity(self):616    return (617        self.UnpackInt32(),618        self.UnpackString(),619        self.UnpackInt32(),620        self.UnpackInt32(),621        self.UnpackInt32(),622        self.UnpackInt8(),623        self.UnpackInt8(),624        self.UnpackInt16(),625        )626  def ParseSpawnDroppedItem(self):627    return (628        self.UnpackInt32(),629        self.UnpackInt16(),630        self.UnpackInt8(),631        self.UnpackInt16(),632        self.UnpackInt32(),633        self.UnpackInt32(),634        self.UnpackInt32(),635        self.UnpackInt8(),636        self.UnpackInt8(),637        self.UnpackInt8(),638        )639  def ParseCollectItem(self):640    return (641        self.UnpackInt32(),642        self.UnpackInt32(),643        )644  def ParseSpawnObjectVehicle(self):645    return (646        self.UnpackInt32(),647        self.UnpackInt8(),648        self.UnpackInt32(),649        self.UnpackInt32(),650        self.UnpackInt32(),651        self.UnpackInt32(),652        self.UnpackInt16(),653        self.UnpackInt16(),654        self.UnpackInt16(),655        )656  def ParseSpawnMob(self):657    return (658        self.UnpackInt32(),659        self.UnpackInt8(),660        self.UnpackInt32(),661        self.UnpackInt32(),662        self.UnpackInt32(),663        self.UnpackInt8(),664        self.UnpackInt8(),665        self.UnpackInt8(),666        self.UnpackMetadata(),667        )668  def ParseSpawnPainting(self):669    return (670        self.UnpackInt32(),671        self.UnpackString(),672        self.UnpackInt32(),673        self.UnpackInt32(),674        self.UnpackInt32(),675        self.UnpackInt32(),676        )677  def ParseSpawnExperienceOrb(self):678    return (679        self.UnpackInt32(),680        self.UnpackInt32(),681        self.UnpackInt32(),682        self.UnpackInt32(),683        self.UnpackInt16(),684        )685  def ParseStanceUpdate(self):686    return (687        self.UnpackFloat(),688        self.UnpackFloat(),689        self.UnpackFloat(),690        self.UnpackFloat(),691        self.UnpackBool(),692        self.UnpackBool(),693        )694  def ParseEntityVelocity(self):695    return (696        self.UnpackInt32(),697        self.UnpackInt16(),698        self.UnpackInt16(),699        self.UnpackInt16(),700        )701  def ParseDestroyEntity(self):702    return (703        self.UnpackInt32(),704        )705  def ParseEntity(self):706    return (707        self.UnpackInt32(),708        )709  def ParseEntityRelativeMove(self):710    return (711        self.UnpackInt32(),712        self.UnpackInt8(),713        self.UnpackInt8(),714        self.UnpackInt8(),715        )716  def ParseEntityLook(self):717    return (718        self.UnpackInt32(),719        self.UnpackInt8(),720        self.UnpackInt8(),721        )722  def ParseEntityRelativeLookAndMove(self):723    return (724        self.UnpackInt32(),725        self.UnpackInt8(),726        self.UnpackInt8(),727        self.UnpackInt8(),728        self.UnpackInt8(),729        self.UnpackInt8(),730        )731  def ParseEntityTeleport(self):732    return (733        self.UnpackInt32(),734        self.UnpackInt32(),735        self.UnpackInt32(),736        self.UnpackInt32(),737        self.UnpackInt8(),738        self.UnpackInt8(),739        )740  def ParseEntityHeadLook(self):741    return (742        self.UnpackInt32(),743        self.UnpackInt8(),744        )745  def ParseEntityStatus(self):746    return (747        self.UnpackInt32(),748        self.UnpackInt8(),749        )750  def ParseAttachEntity(self):751    return (752        self.UnpackInt32(),753        self.UnpackInt32(),754        )755  def ParseEntityMetadata(self):756    return (757        self.UnpackInt32(),758        self.UnpackMetadata(),759        )760  def ParseEntityEffect(self):761    return (762        self.UnpackInt32(),763        self.UnpackInt8(),764        self.UnpackInt8(),765        self.UnpackInt16(),766        )767  def ParseRemoveEntityEffect(self):768    return (769        self.UnpackInt32(),770        self.UnpackInt8(),771        )772  def ParseSetExperience(self):773    return (774        self.UnpackFloat(),775        self.UnpackInt16(),776        self.UnpackInt16(),777        )778  def ParsePlayerAbility(self):779    return (780        self.UnpackInt8(),781        self.UnpackInt8(),782        self.UnpackInt8(),783        self.UnpackInt8(),784        )785  def ParseIncrementStatistic(self):786    return (787        self.UnpackInt32(),788        self.UnpackInt8(),789        )790  def ParsePlayerListItem(self):791    return (792        self.UnpackString(),793        self.UnpackInt8(),794        self.UnpackInt16(),795        )796  def ParseTimeUpdate(self):797    return (798        self.UnpackInt64(),)799  def ParseEntityEquipment(self):800    return (801        self.UnpackInt32(),802        self.UnpackInt16(),803        self.UnpackInt16(),804        self.UnpackInt16(),805        )806  def ParseMapColumnAllocation(self):807    return (808        self.UnpackInt32(),809        self.UnpackInt32(),810        self.UnpackInt8(),811        )812  def ParseMapChunks(self):813    chunkX = self.UnpackInt32()814    chunkZ = self.UnpackInt32()815    withBiome = self.UnpackInt8()816    primaryBitMap = self.UnpackInt16()817    addBitMap = self.UnpackInt16()818    arraySize = self.UnpackInt32()819    trash = self.UnpackInt32()  # "unused"820    compressed = self.Read(arraySize)821    data = [zlib.decompress(compressed)]822    #print len(data[0]), hex(primaryBitMap)823    def PopByteArray(size):824      if len(data[0]) < size:825        raise Exception('data not big enough!')826      ret = array.array('B', data[0][:size])827      data[0] = data[0][size:]828      return  ret829    blocks = array.array('B')830    for i in range(16):831      if primaryBitMap & (1 << i):832        blocks.extend(PopByteArray(4096))833      else:834        blocks.extend([0] * 4096)835    meta = []836    for i in range(16):837      if primaryBitMap & (1 << i):838        meta.append(PopByteArray(2048))839      else:840        meta.append(array.array('B', [0] * 2048))841    light = []842    for i in range(16):843      if primaryBitMap & (1 << i):844        light.append(PopByteArray(2048))845      else:846        light.append(array.array('B', [0] * 2048))847    skylight = []848    for i in range(16):849      if primaryBitMap & (1 << i):850        skylight.append(PopByteArray(2048))851      else:852        skylight.append(array.array('B', [0] * 2048))853    addArray = []854    for i in range(16):855      if addBitMap & (1 << i):856        addArray.append(PopByteArray(2048))857      else:858        addArray.append(array.array('B', [0] * 2048))859    if withBiome:860      biome = PopByteArray(256)861    else:862      biome = None863    if len(data[0]) > 0:864      raise Exception('Unused bytes!')865    return (ChunkColumn(chunkX, chunkZ,866        blocks, meta, light, skylight, addArray, biome),)867    return [chunkX, chunkZ, blocks, meta, light, skylight, addArray, biome]868    ret = [869        self.UnpackInt32(),870        self.UnpackInt32(),871        self.UnpackInt8(),872        self.UnpackInt16(),873        self.UnpackInt16(),874        ]875    arraySize = self.UnpackInt32()876    ret.append(self.UnpackInt32())  # "unused"877    ret.append(self.Read(arraySize))878    return ret879  def ParseMultiBlockChange(self):880    blocks = []881    chunkX = self.UnpackInt32()882    chunkZ = self.UnpackInt32()883    count = self.UnpackInt16()884    size = self.UnpackInt32()885    if count *4 != size:886      pass887      #print "WTF:", count, size888    for i in range(count):889      record = self.UnpackInt32()890      meta = record & 0xf # 4 bits891      record >> 4892      blockId = record & 0xfff # 12 bits893      record >> 12894      y = record & 0xf # 8 bits895      record >> 8896      relativeZ  = record & 0xf # 4 bits897      record >> 4898      relativeX  = record & 0xf # 4 bits899      record >> 4900      blocks.append((chunkX * 16 + relativeX,901                     chunkZ * 16 + relativeZ,902                     y,903                     blockId,904                     meta))905    return (blocks,)906  def ParseBlockChange(self):907    return (908        self.UnpackInt32(),909        self.UnpackInt8(),910        self.UnpackInt32(),911        self.UnpackInt8(),912        self.UnpackInt8(),913        )914  def ParseExplosion(self):915    x = self.UnpackDouble()916    y = self.UnpackDouble()917    z = self.UnpackDouble()918    unknown = self.UnpackFloat()919    record_count = self.UnpackInt32()920    records = []921    for i in range(record_count):922      records.append(self.Read(3))923    return (x, y, z, unknown, record_count, records)924  def ParseSoundParticleEffect(self):925    return (926        self.UnpackInt32(),927        self.UnpackInt32(),928        self.UnpackInt8(),929        self.UnpackInt32(),930        self.UnpackInt32(),931        )932  def ParseChangeGameState(self):933    return (934        self.UnpackInt8(),935        self.UnpackInt8(),936        )937  def ParseThunderbolt(self):938    return (939        self.UnpackInt32(),940        self.UnpackBool(),941        self.UnpackInt32(),942        self.UnpackInt32(),943        self.UnpackInt32(),944        )945  def ParseOpenWindow(self):946    return (947        self.UnpackInt8(),948        self.UnpackInt8(),949        self.UnpackString(),950        self.UnpackInt8(),951        )952  def ParseCloseWindow(self):953    return (954        self.UnpackInt8(),955        )956  def ParseBlockAction(self):957    return (958        self.UnpackInt32(),959        self.UnpackInt16(),960        self.UnpackInt32(),961        self.UnpackInt8(),962        self.UnpackInt8(),963        )964  def ParseSetSlot(self):965    return (966        self.UnpackInt8(),967        self.UnpackInt16(),968        self.UnpackSlot(),969        )970  def ParseSetWindowItems(self):971    windowId = self.UnpackInt8()972    slotCount = self.UnpackInt16()973    # enchantment table lies about its custom slot count974    if windowId != 0 and slotCount == 9:975      slotCount = 1 + 27 + 9976    slots = []977    for i in range(slotCount):978      slots.append(self.UnpackSlot())979    return (windowId, slots)980  def ParseUpdateWindowProperty(self):981    return (982        self.UnpackInt8(),983        self.UnpackInt16(),984        self.UnpackInt16(),985        )986  def ParseConfirmTransaction(self):987    return (988        self.UnpackInt8(),989        self.UnpackInt16(),990        self.UnpackBool(),991        )992  def ParseCreativeInventoryAction(self):993    return (994        self.UnpackInt16(),995        self.UnpackSlot(),996        )997  def ParseUpdateTileEntity(self):998    return (999        self.UnpackInt32(),1000        self.UnpackInt16(),1001        self.UnpackInt32(),1002        self.UnpackInt8(),1003        self.UnpackInt32(),1004        self.UnpackInt32(),1005        self.UnpackInt32(),1006        )1007  def ParseUpdateSign(self):1008    return (1009        self.UnpackInt32(),1010        self.UnpackInt16(),1011        self.UnpackInt32(),1012        self.UnpackString(),1013        self.UnpackString(),1014        self.UnpackString(),1015        self.UnpackString(),1016        )1017  def ParseItemData(self):1018    item_type = self.UnpackInt16()1019    item_id = self.UnpackInt16()1020    array_length = self.UnpackInt8()1021    text = self.Read(arrayLength)1022    return (item_type, item_id, array_length, text)1023  ##############################################################################1024  # Senders1025  def SendLogin(self, username):1026    packet = (1027        '\x01' +1028        struct.pack('!i', 29) +1029        self.PackString(username) +1030        self.PackString('') +1031        struct.pack('!i', 0) +1032        struct.pack('!i', 0) +1033        struct.pack('!b', 0) +1034        struct.pack('!B', 0) +1035        struct.pack('!B', 0)1036        )1037    self.Send(packet)1038  def SendHandshake(self, username, server, port):1039    self.Send(1040        '\x02' +1041        self.PackString(u'%s;%s;%d' % (username, server, port))1042        )1043  def SendChat(self, msg):1044    self.Send(1045        '\x03' +1046        self.PackString(u'%s' % (msg))1047        )1048  def SendUseEntity(self, user, target, mouse_button):1049    self.Send(1050        '\x07' +1051        struct.pack('!i', user) +1052        struct.pack('!i', target) +1053        struct.pack('!b', mouse_button)1054        )1055  def SendRespawn(self, dimension, difficulty, levelType):1056    packet = (1057        '\x09' +1058        struct.pack('!i', dimension) +1059        struct.pack('!b', difficulty) +1060        struct.pack('!b', 0) +1061        struct.pack('!h', 256) +1062        self.PackString(levelType)1063        )1064    self.Send(packet)1065  def SendPlayer(self, on_ground):1066    ''' Tell server whether player is on the ground '''1067    self.Send(1068        '\x0a' +1069        struct.pack('!b', on_ground)1070        )1071  def SendPlayerPosition(self, x, y, stance, z, on_ground):1072    self.Send(1073        '\x0b' +1074        struct.pack('!ddddb', x, y, stance, z, on_ground)1075        )1076  def SendPlayerLook(self, yaw, pitch, on_ground):1077    self.Send(1078        '\x0c' +1079        struct.pack('!ffb', yaw, pitch, on_ground)1080        )1081  def SendPlayerPositionAndLook(self, x, y, stance, z, yaw, pitch, on_ground):1082    self.Send(1083        '\x0d' +1084        struct.pack('!ddddffb', x, y, stance, z, yaw, pitch, on_ground)1085        )1086  def SendPlayerDigging(self, status, x, y, z, face):1087    self.Send(1088        '\x0e' +1089        struct.pack('!b', status) +1090        struct.pack('!i', x) +1091        struct.pack('!b', y) +1092        struct.pack('!i', z) +1093        struct.pack('!B', face) # trying unsigned 1094        )1095  def SendPlayerBlockPlacement(self, x, y, z, direction, held_item):1096    self.Send(1097        '\x0f' +1098        struct.pack('!i', x) +1099        struct.pack('!b', y) +1100        struct.pack('!i', z) +1101        struct.pack('!b', direction)+1102        self.PackSlot(held_item)1103        )1104  def SendHeldItemChange(self, slot_id):1105    #print 'SendHeldItemChange:', (slot_id)1106    packet = (1107        '\x10' +1108        struct.pack('!h', slot_id)1109        )1110    self.Send(packet)1111  def SendAnimation(self, eid, animation):1112    self.Send(1113        '\x12' +1114        struct.pack('!i', eid) +1115        struct.pack('!b', animation)1116        )1117  def SendEntityAction(self, eid, action_id):1118    self.Send(1119        '\x13' +1120        struct.pack('!i', eid) +1121        struct.pack('!b', action_id)1122        )1123  def SendCloseWindow(self, window_id):1124    self.Send(1125        '\x65' +1126        struct.pack('!b', window_id)1127        )1128  def SendClickWindow(self, window_id, slot_id, right_click, action_number, shift, slot_data):1129    #print 'SendClickWindow:', window_id, slot_id, right_click, action_number, shift, slot_data1130    packet = (1131        '\x66' +1132        struct.pack('!b', window_id) +1133        struct.pack('!h', slot_id) +1134        struct.pack('!b', right_click) +1135        struct.pack('!h', action_number) +1136        struct.pack('!b', shift) +1137        self.PackSlot(slot_data)1138        )1139    self.Send(packet)1140  def SendConfirmTransaction(self, window_id, action_number, accepted):1141    self.Send(1142        '\x6a' +1143        struct.pack('!b', window_id) +1144        struct.pack('!h', action_number) +1145        struct.pack('!b', accepted)1146        )1147  def SendCreativeInventoryAction(self, slot, clicked_item):1148    self.Send(1149        '\x6b' +1150        struct.pack('!h', slot) +1151        self.PackSlot(clicked_item)1152        )1153  def SendEnchantItem(self, window_id, enchantment):1154    self.Send(1155        '\x6c' +1156        struct.pack('!b', window_id) +1157        struct.pack('!b', enchantment)1158        )1159  def SendUpdateSign(self, x, y, z, text1, text2, text3, text4):1160    self.Send(1161        '\x82' +1162        struct.pack('!i', x) +1163        struct.pack('!h', y) +1164        struct.pack('!i', z) +1165        self.PackString(text1) +1166        self.PackString(text2) +1167        self.PackString(text3) +1168        self.PackString(text4)1169        )1170  def SendPlayerAbilities(self, invulnerability, is_flying, can_fly, instant_destroy):1171    self.Send(1172        '\xca' +1173        struct.pack('!b', invulnerability) +1174        struct.pack('!b', is_flying) +1175        struct.pack('!b', can_fly) +1176        struct.pack('!b', instant_destroy)1177        )1178  def SendListPing(self):1179    self.Send(1180        '\xfe'1181        )1182  def SendDisconnect(self, reason=''):1183    self.Send(1184        '\xff' +1185        self.PackString(reason)...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
