Advertisement
NickG

Datautils refactor WIP

Nov 4th, 2013
44
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.54 KB | None | 0 0
  1. #About halfway finished refactoring datautils
  2. #Still need to do metadata and obj_data
  3.  
  4. import struct
  5. import zlib
  6. from spock import utils
  7. from spock.mcp import mcdata, nbt
  8.  
  9. endian = '>'
  10.  
  11. # Minecraft varints are 32-bit signed values
  12. # packed into Google Protobuf varints
  13. # TODO: Check that value is no more than 32bits
  14. # TODO: Return meaningful error if it isn't (None?)
  15. def unpack_varint(bbuff):
  16.     total = 0
  17.     shift = 0
  18.     val = 0x80
  19.     while val&0x80:
  20.         val = struct.unpack('B', bbuff.read(1))[0]
  21.         total |= ((val&0x7F)<<shift)
  22.         shift += 7
  23.     if total&0x80000000:
  24.         total = total - (1<<32)
  25.     return total
  26.  
  27. def pack_varint(val):
  28.     total = b''
  29.     if val < 0:
  30.         val = 0xFFFFFFFF+val+1
  31.     while val>=0x80:
  32.         bits = val&0x7F
  33.         val >>= 7
  34.         total += struct.pack('B', (0x80|bits))
  35.     bits = val&0x7F
  36.     total += struct.pack('B', bits)
  37.     return total
  38.  
  39. # Slots are dictionaries that hold info about
  40. # inventory items, they also have funky
  41. # enchantment data stored in gziped NBT structs
  42. def unpack_slot(bbuff):
  43.     slot = {}
  44.     slot['id'] = unpack('short', bbuff)
  45.     if slot[['id'] != -1:
  46.         slot['amount'] = unpack('byte', bbuff)
  47.         slot['damage'] = unpack('short', bbuff)
  48.         length = unpack('short', bbuff)
  49.         if length > 0:
  50.             data = bbuff.recv(length)
  51.             try:
  52.                 ench_bbuff = utils.BoundBuffer(
  53.                     #Adding 16 to the window bits field tells zlib
  54.                     #to take care of the gzip headers for us
  55.                     zlib.decompress(data, 16+zlib.MAX_WBITS)
  56.                 )
  57.                 assert(unpack('byte', ench_bbuff) == nbt.TAG_COMPOUND)
  58.                 name = nbt.TAG_String(buffer = ench_bbuff)
  59.                 ench = nbt.TAG_Compound(buffer = ench_bbuff)
  60.                 ench.name = name
  61.                 slot['enchants'] = ench
  62.             except:
  63.                 slot['enchant_data'] = data
  64.     return slot
  65.  
  66. def pack_slot(slot):
  67.     o = pack('short', data['id'])
  68.     if data['id'] != -1:
  69.         o += pack('byte', data['amount'])
  70.         o += pack('short', data['damage'])
  71.         if 'enchantment_data' in data:
  72.             o += pack('short', len(data['enchant_data']))
  73.             o += data['enchant_data']
  74.         elif 'enchants' in data:
  75.             ench = data['enchants']
  76.             bbuff = utils.BoundBuffer()
  77.             TAG_Byte(ench.id)._render_buffer(bbuff)
  78.             TAG_String(ench.name)._render_buffer(bbuff)
  79.             ench._render_buffer(bbuff)
  80.             #Python zlib.compress doesn't provide wbits for some reason
  81.             #So we'll use a compression object instead, no biggie
  82.             compress = zlib.compressobj(wbits = 16+zlib.MAX_WBITS)
  83.             ench = compress.compress(bbuff.flush())
  84.             ench += compress.flush()
  85.             o += pack('short', len(ench))
  86.             o += ench
  87.         else:
  88.             o += pack('short', -1)
  89.     return o
  90.  
  91. def unpack_metadata(bbuff):
  92.     metadata = []
  93.     x = unpack(bbuff, 'ubyte')
  94.     while x != 127:
  95.         key = x & 0x1F # Lower 5 bits
  96.         ty = x >> 5 # Upper 3 bits
  97.         if ty == 0: val = unpack(bbuff, 'byte')
  98.         if ty == 1: val = unpack(bbuff, 'short')
  99.         if ty == 2: val = unpack(bbuff, 'int')
  100.         if ty == 3: val = unpack(bbuff, 'float')
  101.         if ty == 4: val = unpack(bbuff, 'string')
  102.         if ty == 5:
  103.             val = {}
  104.             val["id"] = unpack(bbuff, 'short')
  105.             val["count"] = unpack(bbuff, 'byte')
  106.             val["damage"] = unpack(bbuff, 'short')
  107.         if ty == 6:
  108.             val = []
  109.             for i in range(3):
  110.                 val.append(unpack(bbuff, 'int'))
  111.         metadata.append((key, (ty, val)))
  112.         x = unpack(bbuff, 'byte')
  113.     return metadata
  114.  
  115. def pack_metadata(metadata):
  116.     pass
  117.  
  118. def unpack_obj_data(bbuff):
  119.     pass
  120.  
  121. def pack_obj_data(obj_data):
  122.     pass
  123.  
  124.  
  125. def unpack(data_type, bbuff):
  126.     if data_type in mcdata.data_types:
  127.         format = mcdata.data_types[data_type]
  128.         return struct.unpack(endian+format[0], bbuff.recv(format[1]))[0]
  129.  
  130.     if data_type == "string":
  131.         return bbuff.recv(unpack(bbuff, 'short')).decode('utf-8')
  132.  
  133.     if data_type == 'varint':
  134.         return unpack_varint(bbuff)
  135.  
  136.     if data_type == 'metadata':
  137.         return unpack_metadata(bbuff)
  138.  
  139. def pack(data_type, data):
  140.     if data_type in mcdata.data_types:
  141.         format = mcdata.data_types[data_type]
  142.         return struct.pack(endian+format[0], data)
  143.    
  144.     if data_type == "string":
  145.         return pack("short", len(data)) + data.encode('utf-8')
  146.  
  147.     if data_type == "slot":
  148.         return pack_slot(data)
  149.                
  150.     if data_type == "metadata":
  151.         o = ''
  152.         for key, tmp in data:
  153.             ty, val = tmp
  154.             x = key | (ty << 5)
  155.             o += pack('ubyte', x)
  156.  
  157.             if ty == 0: o += pack('byte', val)
  158.             if ty == 1: o += pack('short', val)
  159.             if ty == 2: o += pack('int', val)
  160.             if ty == 3: o += pack('float', val)
  161.             if ty == 4: o += pack('string', val)
  162.             if ty == 5:
  163.                 o += pack('short', val['id'])
  164.                 o += pack('byte', val['count'])
  165.                 o += pack('short', val['damage'])
  166.             if ty == 6:
  167.                 for i in range(3):
  168.                     o += pack('int', val[i])
  169.         o += pack('byte', 127)
  170.         return o
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement