Guest User

Untitled

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