LeaPhant / skyblock-stats

A beautiful SkyBlock profile viewer 🌹
https://sky.lea.moe
MIT License
168 stars 33 forks source link

Where is inventory parser #52

Closed isXander closed 4 years ago

isXander commented 4 years ago

Hey! I was looking to make a discord bot similar to this so I was thinking I could translate your nbt parser to python but can't seem to find the code that does it. Could you link the file and line number?

LeaPhant commented 4 years ago

src/lib.js#L227

notnotmelon commented 4 years ago

Here's a version already in python if you still need it It also doesn't use any nonstandard libraries

`from base64 import b64decode as one from gzip import decompress as two from io import BytesIO as three from struct import unpack def decode_inventory_data(raw, backpack=False): if backpack: raw = three(two(raw))
else: raw = three(two(one(raw))) # Unzip raw string from the api

def read(type, length):
    if type in 'chil':
        return int.from_bytes(raw.read(length), byteorder='big')
    if type == 's':
        return raw.read(length).decode('utf-8')
    return unpack(f'>{type}', raw.read(length))[0]

def parse_list():
    subtype = read('c', 1)
    payload = []
    for _ in range(read('i', 4)):
        parse_next_tag(payload, subtype)
    return payload

def parse_compound():
    payload = {}
    while parse_next_tag(payload) != 0:  # Parse tags until we find an endcap (type == 0)
        pass  # Nothing needs to happen here
    return payload

payloads = {
    1: lambda: read('c', 1),  # Byte
    2: lambda: read('h', 2),  # Short
    3: lambda: read('i', 4),  # Int
    4: lambda: read('l', 8),  # Long
    5: lambda: read('f', 4),  # Float
    6: lambda: read('d', 8),  # Double
    7: lambda: raw.read(read('i', 4)),  # Byte Array
    8: lambda: read('s', read('h', 2)),  # String
    9: parse_list,  # List
    10: parse_compound,  # Compound
    11: lambda: [read('i', 4) for _ in range(read('i', 4))],  # Int Array
    12: lambda: [read('l', 8) for _ in range(read('i', 4))]  # Long Array
}

def parse_next_tag(dictionary, tag_id=None):
    if tag_id is None:  # Are we inside a list?
        tag_id = read('c', 1)
        if tag_id == 0:  # Is this the end of a compound?
            return 0
        name = read('s', read('h', 2))

    payload = payloads[tag_id]()
    if isinstance(dictionary, dict):
        dictionary[name] = payload
    else:
        dictionary.append(payload)

raw.read(3)  # Remove file header (we ingore footer)
root = {}
parse_next_tag(root)
return root`
isXander commented 4 years ago

Here's a version already in python if you still need it It also doesn't use any nonstandard libraries

`from base64 import b64decode as one from gzip import decompress as two from io import BytesIO as three from struct import unpack def decode_inventory_data(raw, player=None, backpack=False): if backpack: raw = three(two(raw)) else: raw = three(two(one(raw))) # Unzip raw string from the api

def read(type, length):
  if type in 'chil':
      return int.from_bytes(raw.read(length), byteorder='big')
  if type == 's':
      return raw.read(length).decode('utf-8')
  return unpack(f'>{type}', raw.read(length))[0]

def parse_list():
  subtype = read('c', 1)
  payload = []
  for _ in range(read('i', 4)):
      parse_next_tag(payload, subtype)
  return payload

def parse_compound():
  payload = {}
  while parse_next_tag(payload) != 0:  # Parse tags until we find an endcap (type == 0)
      pass  # Nothing needs to happen here
  return payload

payloads = {
  1: lambda: read('c', 1),  # Byte
  2: lambda: read('h', 2),  # Short
  3: lambda: read('i', 4),  # Int
  4: lambda: read('l', 8),  # Long
  5: lambda: read('f', 4),  # Float
  6: lambda: read('d', 8),  # Double
  7: lambda: raw.read(read('i', 4)),  # Byte Array
  8: lambda: read('s', read('h', 2)),  # String
  9: parse_list,  # List
  10: parse_compound,  # Compound
  11: lambda: [read('i', 4) for _ in range(read('i', 4))],  # Int Array
  12: lambda: [read('l', 8) for _ in range(read('i', 4))]  # Long Array
}

def parse_next_tag(dictionary, tag_id=None):
  if tag_id is None:  # Are we inside a list?
      tag_id = read('c', 1)
      if tag_id == 0:  # Is this the end of a compound?
          return 0
      name = read('s', read('h', 2))

  payload = payloads[tag_id]()
  if isinstance(dictionary, dict):
      dictionary[name] = payload
  else:
      dictionary.append(payload)

raw.read(3)    # Remove file header (we ingore footer)
root = {}
parse_next_tag(root)
return root`

What variable does raw have to be? String doesnt work

notnotmelon commented 4 years ago

It must be a binary string (created with b"")

b"H4sIAAAAAAAAAO3OzwqCQBgE8PFvugS9TefEig6p4KXzhpssaMa6Uj2R7+GDRXrq3H3mNAwffD8BxHC0ALB14erKCR0EaTfc7U7As7L2EJ90pY6NrPv56iOwqnT/aOQ7hn/ujIrm1cF6Gm/T2KRFlhV5BD+XrUI0j4kx3RMCm8PLGplYa/R1sKqPlm8IkrIsLoCLcC9bWSssnQ466KCDDjrooIMOOuiggw466KCDDjrooIMOOuj41/HLFzShx7n+FwAA"