How to use sendCloseWindow method in fMBT

Best Python code snippet using fMBT_python

tick.py

Source:tick.py Github

copy

Full Screen

...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...

Full Screen

Full Screen

peon-legacy.py

Source:peon-legacy.py Github

copy

Full Screen

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)...

Full Screen

Full Screen

mc.py

Source:mc.py Github

copy

Full Screen

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)...

Full Screen

Full Screen

Automation Testing Tutorials

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.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run fMBT automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful