imthe666st

ACNH Item id list script

Mar 27th, 2020
1,288
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.62 KB | None | 0 0
  1. #from Msbt import MsbtFile
  2. class MsbtFile(object):
  3.  
  4.     def __init__(self, path, clean=True):
  5.         #print(path)
  6.         self.path = path
  7.         self.data = list()
  8.         with open(path, mode='rb') as file:
  9.             self.data = file.read()
  10.  
  11.         if self.read_position(0, 8) != b'MsgStdBn':
  12.             print('Invalid signature of file {}!'.format(path))
  13.             return
  14.        
  15.         pointer = 0x20
  16.         def read_pointer(length):
  17.             nonlocal pointer
  18.             p_data = self.read_position(pointer, length)
  19.             pointer += length
  20.             return p_data
  21.        
  22.         # reading sections
  23.         self.lbl1_labels = list()
  24.         self.txt2_strings = list()
  25.         for _ in range(self.get_section_count()):
  26.             pos = pointer
  27.             try:
  28.                 while self.data[pointer] == b'\xab'[0]:
  29.                     pointer += 1
  30.                 signature = read_pointer(4)
  31.                 signature = signature.decode('utf-8')
  32.             except:
  33.                 #print(signature)
  34.                 signature = 'UNK1'
  35.            
  36.             section_size = int.from_bytes(read_pointer(4), 'little')
  37.             #print('Signature: {}'.format(signature))
  38.             #print('signature in file {}:{:08X} {}'.format(path, pos, signature))
  39.  
  40.             if signature == 'LBL1': # label
  41.                 read_pointer(8) # padding
  42.                 lbl1_pos = pointer
  43.                 entry_count = int.from_bytes(read_pointer(4), 'little')
  44.                 #print('\tLBL1 has {} entries [{:08X}]'.format(entry_count, pointer))
  45.                 groups = list()
  46.                 for entry in range(entry_count):
  47.                     groups.append((int.from_bytes(read_pointer(4), 'little'), int.from_bytes(read_pointer(4), 'little')))
  48.                     # number of labels, offset
  49.                
  50.                 for num_labels, offset in groups:
  51.                     group_labels = list()
  52.                     pointer = lbl1_pos + offset
  53.                     #print('\tGroup#{} has {} labels [{:08X}]'.format(group_num, num_labels, pointer))
  54.                     for _ in range(num_labels):
  55.                         length = int.from_bytes(read_pointer(1), 'little')
  56.                         name = read_pointer(length)
  57.                         #print(name)
  58.                         index = int.from_bytes(read_pointer(4), 'little')
  59.                         group_labels.append((index, name))
  60.  
  61.  
  62.                     self.lbl1_labels.append(group_labels)
  63.                 #print(pointer, lbl1_pos + section_size)
  64.  
  65.             elif signature == 'TXT2': # text
  66.                 read_pointer(8) # padding
  67.                 txt2_pos = pointer
  68.                 entry_count = int.from_bytes(read_pointer(4), 'little')
  69.                 offsets = [int.from_bytes(read_pointer(4), 'little') for _ in range(entry_count)]
  70.                 for entry in range(entry_count):
  71.                     startPos = offsets[entry] + txt2_pos
  72.                     endPos = txt2_pos + offsets[entry+1] if entry + 1 < entry_count else txt2_pos + section_size
  73.                     length = endPos - startPos
  74.                     self.txt2_strings.append(self.read_position(startPos, length)) # add decoding!! .decode(self.get_encoding_name())
  75.                
  76.                 # seek to end of section
  77.                 pointer = txt2_pos + section_size
  78.  
  79.             #elif signature in ['NLI1', 'ATR1', 'ATO1', 'TSY1']:
  80.             #   print('signature in file {}:{} {}'.format(path, pos, signature))
  81.             else:
  82.                 read_pointer(8) # padding
  83.                 read_pointer(section_size) # skip over it
  84.                 #print('{:08X}'.format(pointer))
  85.        
  86.         #print('Processing lbl1')
  87.         self.lbl1_labels_flat = list()
  88.         for group in self.lbl1_labels:
  89.             for item in group:
  90.                 item = (item[0], item[1].decode('utf-8'))
  91.                 self.lbl1_labels_flat.append(item)
  92.         self.lbl1_labels_flat.sort(key=lambda x: x[0])
  93.        
  94.         #print('Processing txt2', len(self.txt2_strings))
  95.         self.txt2_strings_decoded = list()
  96.        
  97.         for txt2_string in self.txt2_strings:
  98.             if txt2_string[0:4] == b'\x0e\x002\x00':
  99.                 i = 0
  100.                 while i < len(txt2_string) and txt2_string[i] != b'\xcd'[0]:
  101.                     i += 1
  102.                 i += 1
  103.                 if i < len(txt2_string):
  104.                     txt2_string = txt2_string[i:]
  105.  
  106.             txt2_string = txt2_string[:-2]
  107.             try:
  108.                 s = txt2_string.decode(self.get_encoding_name())
  109.                 s = s.replace('\x0en\x1e\x00', '<N>')
  110.                 self.txt2_strings_decoded.append(s)
  111.                 #print(s)
  112.             except KeyboardInterrupt:
  113.                 exit()
  114.             except:
  115.                 print(txt2_string, 'Exception')
  116.  
  117.  
  118.  
  119.  
  120.     # other stuff
  121.  
  122.     def read_position(self, position, length):
  123.         return self.data[position:(position+length)]
  124.    
  125.     def get_byte_order_mark(self):
  126.         return self.read_position(0x8, 2)
  127.    
  128.     def get_encoding(self):
  129.         return int.from_bytes(self.read_position(0xC, 1), 'little')
  130.    
  131.     def get_encoding_name(self):
  132.         encoding = self.get_encoding()
  133.         if encoding == 0:
  134.             return 'utf-8'
  135.         elif encoding == 1:
  136.             return 'utf-16le'
  137.         elif encoding == 2:
  138.             return 'utf-16be'
  139.    
  140.     def get_version(self):
  141.         return int.from_bytes(self.read_position(0xD, 1), 'little')
  142.    
  143.     def get_section_count(self):
  144.         return int.from_bytes(self.read_position(0xE, 2), 'little')
  145.    
  146.     def get_filesize(self):
  147.         return int.from_bytes(self.read_position(0x10, 4), 'little')
  148.  
  149.  
  150. if __name__ == "__main__":
  151.     import os
  152.     # normal item ids
  153.     base_path = os.path.join(*'romfs_unpacked/Message/String_EUen'.split('/'))
  154.     load_msbt = lambda path: (lambda _path: [MsbtFile(os.path.join(_path, msbt)) for msbt in os.listdir(_path)])(os.path.join(*path.split('/')))
  155.     msbt_files = load_msbt(os.path.join(base_path, 'item'))
  156.    
  157.     # load clothing.
  158.     outfitName = load_msbt(os.path.join(base_path, 'Outfit/GroupName'))
  159.     outfitColor = load_msbt(os.path.join(base_path, 'Outfit/GroupColor'))
  160.     #print(len(outfitName))
  161.     # create a small dictionary of <int, str> of the group names
  162.     outfitNameMapping = dict()
  163.     # (Type, type_Id) -> GroupName
  164.    
  165.     outfits = dict()
  166.     # (type, Id) -> (GroupName, Color)
  167.     for msbt in outfitName:
  168.         outfitType = msbt.path.split('_')[-1].split('.')[0]
  169.         for label, (_, item_label) in zip(msbt.txt2_strings_decoded, msbt.lbl1_labels_flat):
  170.             outfitNameMapping[(outfitType, int(item_label))] = label
  171.    
  172.     for msbt in outfitColor:
  173.         outfitType = msbt.path.split('_')[-1].split('.')[0]
  174.         outfits[outfitType] = dict()
  175.         for label, (_, item_label) in zip(msbt.txt2_strings_decoded, msbt.lbl1_labels_flat):
  176.             group_id, _, item_id = item_label.split('_')
  177.             group_id = int(group_id)
  178.             item_id = int(item_id)
  179.             outfits[outfitType][item_id] = (outfitNameMapping[(outfitType, group_id)], label)
  180.  
  181.     # Name, Internal name, Id? sure
  182.     with open('item_ids.txt', 'w', encoding='utf-16') as file:
  183.         for msbt in msbt_files:
  184.             file.write('{}\n'.format(msbt.path))
  185.             for item_name, (_, item_label) in zip(msbt.txt2_strings_decoded, msbt.lbl1_labels_flat):
  186.                 # get item id
  187.                 item_id = item_label.split('_')[-1]
  188.                 if item_id == 'pl':
  189.                     continue
  190.                 item_id = int(item_id)
  191.                 try:
  192.                     file.write('{}, {} [{}]\n'.format(item_name, hex(item_id)[2:], item_label))
  193.                 except:
  194.                     print(item_name, hex(item_id)[2:], item_label)
  195.             file.write('\n')
  196.        
  197.         for outfitType, outfitDict in outfits.items():
  198.             file.write('Outfits/{}\n'.format(outfitType))
  199.             for item_id, (outfitName, outfitColor) in outfitDict.items():
  200.                 file.write('{}, {}, [{} | {}]\n'.format(outfitName, hex(item_id)[2:], outfitName, outfitColor))
  201.            
  202.             file.write('\n')
Advertisement
Add Comment
Please, Sign In to add comment