mcrpc.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. import collections
  2. import glob
  3. import hashlib
  4. import json
  5. import os
  6. import re
  7. import shutil
  8. import sys
  9. from distutils.dir_util import copy_tree
  10. from pprint import pprint
  11. from zipfile import ZipFile
  12. import requests
  13. from appdirs import user_cache_dir
  14. PLATFORM = sys.platform
  15. if PLATFORM.startswith('linux'):
  16. PATH_DOTMC = os.path.join(os.path.expanduser('~'), '.minecraft')
  17. elif PLATFORM.startswith('darwin'):
  18. PATH_DOTMC = os.path.join(os.path.expanduser('~'), 'Library', 'Application Support', 'minecraft')
  19. elif PLATFORM.startswith('win32'):
  20. PATH_DOTMC = os.path.join(os.path.expandvars(r'%APPDATA%'), '.minecraft')
  21. APPNAME = "mcrpc"
  22. PATH_CACHE = user_cache_dir(APPNAME)
  23. PATH_CACHE_JARS = os.path.join(PATH_CACHE, 'jars')
  24. PATH_RP_DIR = os.path.join(PATH_DOTMC, 'resourcepacks')
  25. PATH_TARGET = os.path.join(PATH_CACHE, 'target')
  26. PATH_DEFAULT = os.path.join(PATH_CACHE, 'default')
  27. LINK_VM = 'https://launchermeta.mojang.com/mc/game/version_manifest_v2.json'
  28. BUF_SIZE = 65536
  29. SESSION = requests.Session()
  30. def choose_rp():
  31. list_rp = os.listdir(PATH_RP_DIR)
  32. list_rp_checked = []
  33. list_rp.sort()
  34. print('\nSelect the Resource Pack you want to compare:')
  35. for item in list_rp:
  36. if item[-4:] == '.zip':
  37. with ZipFile(os.path.join(PATH_RP_DIR, item), 'r') as zip1:
  38. if 'pack.mcmeta' in zip1.namelist():
  39. list_rp_checked.append(item)
  40. elif os.path.isdir(os.path.join(PATH_RP_DIR, item)):
  41. if os.path.isfile(os.path.join(PATH_RP_DIR, item, 'pack.mcmeta')):
  42. list_rp_checked.append(item)
  43. if len(list_rp_checked) == 0:
  44. print('No valid resource packs. Install one and try again.')
  45. exit(1)
  46. for i, item in enumerate(list_rp_checked, 1):
  47. print(" [{}] {}".format(i, item))
  48. print('Resource Pack choice: ', end='')
  49. choice_rp_num = input()
  50. choice_rp = None
  51. for i, item in enumerate(list_rp_checked, 1):
  52. if i == int(choice_rp_num):
  53. choice_rp = item
  54. return(choice_rp)
  55. def choose_mcv(low=None):
  56. json_vm = SESSION.get(LINK_VM)
  57. json_vm.raise_for_status()
  58. json_vm = json_vm.json()
  59. print('\nSee non-stable versions? (y/n)')
  60. choice_stable = input()
  61. if low == True:
  62. print('\nSelect the lower Minecraft Version:')
  63. elif low == False:
  64. print('\nSelect the higher Minecraft Version:')
  65. else:
  66. print('\nSelect the Minecraft Version you want to compare against:')
  67. i = 1
  68. counter_size = 0
  69. choice_mcv_num = ''
  70. skip_display = False
  71. while True:
  72. for item in json_vm['versions']:
  73. counter_size += 1
  74. if counter_size > len(json_vm['versions']):
  75. skip_display = True
  76. if choice_stable == 'n' or choice_stable == 'N':
  77. if not item['type'] == 'release':
  78. continue
  79. if not skip_display:
  80. print(" [{}] {}".format(i, item['id']))
  81. if i % 25 == 0:
  82. print('(Hit Enter to show more versions) Minecraft Version choice: ', end='')
  83. choice_mcv_num = input()
  84. if choice_mcv_num.isdigit():
  85. break
  86. i += 1
  87. if choice_mcv_num.isdigit():
  88. break
  89. choice_mcv = None
  90. i = 1
  91. for item in json_vm['versions']:
  92. if choice_stable == 'n' or choice_stable == 'N':
  93. if not item['type'] == 'release':
  94. continue
  95. if i == int(choice_mcv_num):
  96. choice_mcv = item
  97. i += 1
  98. return(choice_mcv)
  99. def setup_compare_folders(rp, mcv):
  100. if os.path.exists(PATH_TARGET):
  101. shutil.rmtree(PATH_TARGET)
  102. if os.path.exists(PATH_DEFAULT):
  103. shutil.rmtree(PATH_DEFAULT)
  104. if not isinstance(rp, collections.abc.Mapping):
  105. path_rp = os.path.join(PATH_RP_DIR, rp)
  106. if path_rp[-4:] == ".zip":
  107. with ZipFile(path_rp) as zip1:
  108. for file in zip1.namelist():
  109. if file.startswith('assets/'):
  110. zip1.extract(file, path=PATH_TARGET)
  111. else:
  112. copy_tree(os.path.join(path_rp, 'assets'), os.path.join(PATH_TARGET, 'assets'))
  113. else:
  114. path_client = os.path.join(PATH_CACHE_JARS, '{}.jar'.format(rp['id']))
  115. with ZipFile(path_client) as zip2:
  116. for file in zip2.namelist():
  117. if file.startswith('assets/'):
  118. zip2.extract(file, path=PATH_TARGET)
  119. path_client = os.path.join(PATH_CACHE_JARS, '{}.jar'.format(mcv['id']))
  120. with ZipFile(path_client) as zip3:
  121. for file in zip3.namelist():
  122. if file.startswith('assets/'):
  123. zip3.extract(file, path=PATH_DEFAULT)
  124. def get_client(mcv):
  125. json_version = SESSION.get(mcv['url'])
  126. json_version.raise_for_status()
  127. json_version = json_version.json()
  128. link_client = json_version['downloads']['client']['url']
  129. sha_client = json_version['downloads']['client']['sha1']
  130. sha1 = hashlib.sha1()
  131. sha_calculated = None
  132. if not os.path.exists(PATH_CACHE_JARS):
  133. os.makedirs(PATH_CACHE_JARS)
  134. path_client = os.path.join(PATH_CACHE_JARS, '{}.jar'.format(mcv['id']))
  135. if os.path.exists(path_client):
  136. with open(path_client, 'rb') as f:
  137. while True:
  138. data = f.read(BUF_SIZE)
  139. if not data:
  140. break
  141. sha1.update(data)
  142. sha_calculated = sha1.hexdigest()
  143. if not sha_calculated == sha_client:
  144. with open(path_client, 'wb') as f:
  145. print('Downloading client.jar…')
  146. download = SESSION.get(link_client)
  147. f.write(download.content)
  148. def compare(rp, mcv):
  149. if isinstance(rp, collections.abc.Mapping):
  150. # Comparing 2 minecraft versions
  151. get_client(rp)
  152. get_client(mcv)
  153. else:
  154. # Comparing a resource pack against a minecraft version
  155. get_client(mcv)
  156. setup_compare_folders(rp, mcv)
  157. dir_left = os.path.join(PATH_DEFAULT, '**', '*.*')
  158. dir_right = os.path.join(PATH_TARGET, '**', '*.*')
  159. files_left = glob.glob("{}".format(dir_left), recursive=True)
  160. files_right = glob.glob("{}".format(dir_right), recursive=True)
  161. if PLATFORM.startswith('linux') or PLATFORM.startswith('darwin'):
  162. pattern = re.compile(r".*/assets/(.*)")
  163. elif PLATFORM.startswith('win32'):
  164. pattern = re.compile(r".*\\assets\\(.*)")
  165. for i, file in enumerate(files_left):
  166. files_left[i] = pattern.sub("\g<1>", file)
  167. for i, file in enumerate(files_right):
  168. files_right[i] = pattern.sub("\g<1>", file)
  169. missing_files = [x for x in files_left if x not in files_right]
  170. choose_output(missing_files)
  171. def choose_output(list_of_files):
  172. print('\nTotal missing files:', len(list_of_files))
  173. while True:
  174. print('\n [1] Display list of files')
  175. print(' [2] Save list to file')
  176. print(' [3] Quit')
  177. print('Choice: ', end='')
  178. choice_output = input()
  179. if choice_output == '1':
  180. print('\nMissing files:')
  181. for file in sorted(list_of_files):
  182. print(" {}".format(file))
  183. elif choice_output == '2':
  184. filename = 'missing_files.txt'
  185. with open(filename, 'w') as f:
  186. for file in sorted(list_of_files):
  187. f.write(file)
  188. f.write(os.linesep)
  189. print('\nSaved as:')
  190. print(os.path.join(os.getcwd(), filename))
  191. elif choice_output == '3':
  192. exit(0)
  193. else:
  194. print('\nInvalid choice!')
  195. if __name__ == '__main__':
  196. while True:
  197. print('\n[1] Compare a resource pack against a minecraft version')
  198. print('[2] Compare a minecraft version against another minecraft version')
  199. print('Choice: ', end='')
  200. choice_logic = input()
  201. if choice_logic == '1':
  202. compare(choose_rp(), choose_mcv())
  203. break
  204. elif choice_logic == '2':
  205. compare(choose_mcv(low=True), choose_mcv(low=False))
  206. break
  207. else:
  208. print('\nInvalid choice!')