Advertisement
Guest User

Untitled

a guest
Jan 27th, 2020
318
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.16 KB | None | 0 0
  1. import clr
  2. clr.AddReference("INIFileParser")
  3.  
  4. from System.IO import Directory, File, Path, SearchOption
  5. from System import Environment, PlatformID, String, Exception
  6.  
  7. from IniParser import FileIniDataParser
  8. from IniParser.Model import IniData
  9.  
  10. #Support for parallel extraction
  11. clr.AddReference('System.Core')
  12. from System.Collections.Generic import List
  13. from System import Action
  14. from System.Threading.Tasks import Parallel, ParallelOptions
  15.  
  16. import sys
  17. if Environment.OSVersion.Platform == PlatformID.Win32NT :
  18.   if not Directory.Exists("C:\\Python27\\Lib") :
  19.     raise Exception("Please install Python 2.7")
  20.   sys.path.append("C:\\Python27\\Lib")
  21. else :
  22.   if not Directory.Exists("/usr/lib64/python2.7") :
  23.     raise Exception("Please install Python 2.7")
  24.   sys.path.append("/usr/lib64/python2.7")  
  25.  
  26. extractedcount=0
  27. totalfilecount=0
  28. lastfileprogress=0
  29. ########################################
  30. # https://github.com/TheCherry/ark-server-manager #
  31. ########################################
  32. import struct
  33. import zlib
  34. import sys
  35.  
  36. def str_to_l(st):
  37.     return struct.unpack('q', st)[0]
  38.  
  39. def z_unpack(src, dst):
  40.     global extractedcount, totalfilecount, lastfileprogress
  41.     with open(src, 'rb') as f_src:
  42.         with open(dst, 'wb') as f_dst:
  43.             f_src.read(8)
  44.             size1 = str_to_l(f_src.read(8))
  45.             f_src.read(8)
  46.             size2 = str_to_l(f_src.read(8))
  47.             if(size1 == -1641380927):
  48.                 size1 = 131072L
  49.             runs = (size2 + size1 - 1L) / size1
  50.             array = []
  51.             for i in range(runs):
  52.                 array.append(f_src.read(8))
  53.                 f_src.read(8)
  54.             for i in range(runs):
  55.                 to_read = array[i]
  56.                 compressed = f_src.read(str_to_l(to_read))
  57.                 decompressed = zlib.decompress(compressed)
  58.                 f_dst.write(decompressed)
  59.     Script.WriteToConsole("Extracted " + dst.Replace(ThisService.RootDirectory, ""))
  60.     File.Delete(src)
  61.     File.Delete(src + ".uncompressed_size")
  62.     extractedcount=extractedcount+1
  63.     progress=round((float(extractedcount)/totalfilecount)*100,0)
  64.     if progress > lastfileprogress + 5:
  65.       lastfileprogress=progress
  66.       ThisTaskStep.UpdateProgress(progress)
  67.      
  68. #######################################################################
  69. # https://github.com/barrycarey/Ark_Mod_Downloader/blob/master/Ark_Mod_Downloader.py #
  70. #######################################################################
  71. import os
  72. import struct
  73. from collections import OrderedDict
  74. map_names = []
  75. map_count=0
  76. temp_mod_path = os.path.join(ThisService.RootDirectory, "ShooterGame/Content/Mods")
  77. meta_data = OrderedDict([])
  78.  
  79. def parse_base_info(modid):
  80.         Script.WriteToConsole("[+] Collecting Mod Details From mod.info")
  81.  
  82.         mod_info = os.path.join(temp_mod_path, modid, "mod.info")
  83.  
  84.         if not os.path.isfile(mod_info):
  85.             raise Exception("[x] Failed to locate mod.info. Cannot Continue. Please try again.")
  86.             return False
  87.  
  88.         with open(mod_info, "rb") as f:
  89.             read_ue4_string(f)
  90.             map_count = struct.unpack('i', f.read(4))[0]
  91.  
  92.             for i in range(map_count):
  93.                 cur_map = read_ue4_string(f)
  94.                 if cur_map:
  95.                     map_names.append(cur_map)
  96.  
  97.         return True
  98.  
  99. def parse_meta_data(modid):
  100.         """
  101.        Parse the modmeta.info files and extract the key value pairs need to for the .mod file.
  102.        How To Parse modmeta.info:
  103.            1. Read 4 bytes to tell how many key value pairs are in the file
  104.            2. Read next 4 bytes tell us how many bytes to read ahead to get the key
  105.            3. Read ahead by the number of bytes retrieved from step 2
  106.            4. Read next 4 bytes to tell how many bytes to read ahead to get value
  107.            5. Read ahead by the number of bytes retrieved from step 4
  108.            6. Start at step 2 again
  109.        :return: Dict
  110.        """
  111.  
  112.         print("[+] Collecting Mod Meta Data From modmeta.info")
  113.         print("[+] Located The Following Meta Data:")
  114.  
  115.         mod_meta = os.path.join(temp_mod_path, modid, "modmeta.info")
  116.         if not os.path.isfile(mod_meta):
  117.             raise Exception("[x] Failed To Locate modmeta.info. Cannot continue without it. Please try again.")
  118.             return False
  119.  
  120.         with open(mod_meta, "rb") as f:
  121.  
  122.             total_pairs = struct.unpack('i', f.read(4))[0]
  123.  
  124.             for i in range(total_pairs):
  125.  
  126.                 key, value = "", ""
  127.  
  128.                 key_bytes = struct.unpack('i', f.read(4))[0]
  129.                 key_flag = False
  130.                 if key_bytes < 0:
  131.                     key_flag = True
  132.                     key_bytes -= 1
  133.  
  134.                 if not key_flag and key_bytes > 0:
  135.  
  136.                     raw = f.read(key_bytes)
  137.                     key = raw[:-1].decode()
  138.  
  139.                 value_bytes = struct.unpack('i', f.read(4))[0]
  140.                 value_flag = False
  141.                 if value_bytes < 0:
  142.                     value_flag = True
  143.                     value_bytes -= 1
  144.  
  145.                 if not value_flag and value_bytes > 0:
  146.                     raw = f.read(value_bytes)
  147.                     value = raw[:-1].decode()
  148.  
  149.                 # TODO This is a potential issue if there is a key but no value
  150.                 if key and value:
  151.                     Script.WriteToConsole("[!] " + key + ":" + value)
  152.                     meta_data[key] = value
  153.  
  154.         return True
  155.  
  156. def create_mod_file(modid):
  157.         """
  158.        Create the .mod file.
  159.        This code is an adaptation of the code from Ark Server Launcher.  All credit goes to Face Wound on Steam
  160.        :return:
  161.        """
  162.         if not parse_base_info(modid) or not parse_meta_data(modid):
  163.             return False
  164.  
  165.         print("[+] Writing .mod File")
  166.         with open(os.path.join(temp_mod_path, modid + ".mod"), "w+b") as f:
  167.  
  168.             modid = int(modid)
  169.             f.write(struct.pack('ixxxx', modid))  # Needs 4 pad bits
  170.             write_ue4_string("ModName", f)
  171.             write_ue4_string("", f)
  172.  
  173.             map_count = len(map_names)
  174.             f.write(struct.pack("i", map_count))
  175.  
  176.             for m in map_names:
  177.                 write_ue4_string(m, f)
  178.  
  179.             # Not sure of the reason for this
  180.             num2 = 4280483635
  181.             f.write(struct.pack('I', num2))
  182.             num3 = 2
  183.             f.write(struct.pack('i', num3))
  184.  
  185.             if "ModType" in meta_data:
  186.                 mod_type = b'1'
  187.             else:
  188.                 mod_type = b'0'
  189.  
  190.             # TODO The packing on this char might need to be changed
  191.             f.write(struct.pack('p', mod_type))
  192.             meta_length = len(meta_data)
  193.             f.write(struct.pack('i', meta_length))
  194.  
  195.             for k, v in meta_data.items():
  196.                 write_ue4_string(k, f)
  197.                 write_ue4_string(v, f)
  198.  
  199.         return True
  200.  
  201. def read_ue4_string(file):
  202.         count = struct.unpack('i', file.read(4))[0]
  203.         flag = False
  204.         if count < 0:
  205.             flag = True
  206.             count -= 1
  207.  
  208.         if flag or count <= 0:
  209.             return ""
  210.  
  211.         return file.read(count)[:-1].decode()
  212.  
  213. def write_ue4_string(string_to_write, file):
  214.         string_length = len(string_to_write) + 1
  215.         file.write(struct.pack('i', string_length))
  216.         barray = bytearray(string_to_write, "utf-8")
  217.         file.write(barray)
  218.         file.write(struct.pack('p', b'0'))
  219.  
  220. ###########################################
  221. ###########################################
  222. ###########################################
  223.  
  224. # Only extract files the correct folder depending on operating system
  225. oseditor="WindowsNoEditor" if Environment.OSVersion.Platform == PlatformID.Win32NT else "LinuxNoEditor"
  226. noeditor=Path.Combine(InstallPath, oseditor )
  227. # Extract and delete all .z files
  228. actions = List[Action]()
  229. for zfile in Directory.GetFiles(noeditor, "*.z", SearchOption.AllDirectories):
  230.  file=Path.Combine(Path.GetDirectoryName(zfile), Path.GetFileNameWithoutExtension(zfile))
  231.  action=Action(lambda a=zfile, b=file: z_unpack(a, b))
  232.  actions.Add(action)
  233.  
  234. options=ParallelOptions()
  235. #Extract 2 files at a time.
  236. options.MaxDegreeOfParallelism = 2
  237. totalfilecount=actions.Count
  238. ThisTaskStep.WriteLog(String.Format("Extracting {0} files...", totalfilecount))
  239. ThisTaskStep.UpdateProgress(0)
  240. Parallel.Invoke(options, actions.ToArray())
  241.  
  242. # Move folder to correct location
  243. modfolder=Path.Combine(ThisService.RootDirectory, String.Format("ShooterGame/Content/Mods/{0}", FileId))
  244. Directory.Move(Path.Combine(InstallPath, oseditor), modfolder)
  245.  
  246. # Update ini file
  247. serveros = "WindowsServer" if Environment.OSVersion.Platform == PlatformID.Win32NT else "LinuxServer"
  248. inifile = Path.Combine(ThisService.RootDirectory, String.Format("ShooterGame/Saved/Config/{0}/GameUserSettings.ini", serveros))
  249. ini = FileIniDataParser()
  250. data = ini.ReadFile(inifile)
  251. data["ServerSettings"]["ActiveMods"] = FileIds
  252. ini.WriteFile(inifile, data)
  253.  
  254. #Create .mod
  255. parse_base_info(FileId.ToString())
  256. parse_meta_data(FileId.ToString())
  257. create_mod_file(FileId.ToString())
  258.  
  259. # Delete folder
  260. if Directory.Exists(InstallPath) :
  261.   Directory.Delete(InstallPath, True)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement