Difference between revisions of "Ark Workshop Scripts for Linux"

Line 1: Line 1:
import clr
+
<source lang="python">import clr
+
 
from System.IO import Directory, File, Path, SearchOption
+
from System.IO import Directory, File, Path, SearchOption
from System import Environment, PlatformID, String, Exception
+
from System import Environment, PlatformID, String, Exception
from System.Text.RegularExpressions import Regex, RegexOptions, Match
+
from System.Text.RegularExpressions import Regex, RegexOptions, Match
+
 
#import sys
+
extractedcount=0
#if Environment.OSVersion.Platform == PlatformID.Win32NT :
+
totalfilecount=0
# sys.path.append("C:\\Python27\\Lib")
+
lastfileprogress=0
#else :
+
 
# sys.path.append("/usr/lib/python2.7") 
+
########################################
+
# https://github.com/TheCherry/ark-server-manager #
+
########################################
########################################
+
import struct
# https://github.com/TheCherry/ark-server-manager #
+
import zlib
########################################
+
import sys
import struct
+
 
import zlib
+
def str_to_l(st):
import sys
+
    return struct.unpack('q', st)[0]
+
 
def str_to_l(st):
+
def z_unpack(src, dst):
    return struct.unpack('q', st)[0]
+
    global extractedcount, totalfilecount, lastfileprogress
+
    with open(src, 'rb') as f_src:
def z_unpack(src, dst):
+
        with open(dst, 'wb') as f_dst:
    with open(src, 'rb') as f_src:
+
            f_src.read(8)
        with open(dst, 'wb') as f_dst:
+
            size1 = str_to_l(f_src.read(8))
            f_src.read(8)
+
            f_src.read(8)
            size1 = str_to_l(f_src.read(8))
+
            size2 = str_to_l(f_src.read(8))
            f_src.read(8)
+
            if(size1 == -1641380927):
            size2 = str_to_l(f_src.read(8))
+
                size1 = 131072L
            if(size1 == -1641380927):
+
            runs = (size2 + size1 - 1L) / size1
                size1 = 131072L
+
            array = []
            runs = (size2 + size1 - 1L) / size1
+
            for i in range(runs):
            array = []
+
                array.append(f_src.read(8))
            for i in range(runs):
+
                f_src.read(8)
                array.append(f_src.read(8))
+
            for i in range(runs):
                f_src.read(8)
+
                to_read = array[i]
            for i in range(runs):
+
                compressed = f_src.read(str_to_l(to_read))
                to_read = array[i]
+
                decompressed = zlib.decompress(compressed)
                compressed = f_src.read(str_to_l(to_read))
+
                f_dst.write(decompressed)
                decompressed = zlib.decompress(compressed)
+
    Script.WriteToConsole("Extracted " + dst.Replace(ThisService.RootDirectory, ""))
                f_dst.write(decompressed)              
+
    File.Delete(src)
+
    File.Delete(src + ".uncompressed_size")
#######################################################################
+
    extractedcount=extractedcount+1
# https://github.com/barrycarey/Ark_Mod_Downloader/blob/master/Ark_Mod_Downloader.py #
+
    progress=round((float(extractedcount)/totalfilecount)*100,0)
#######################################################################
+
    if progress > lastfileprogress + 4:
import os
+
      lastfileprogress=progress
import struct
+
      ThisTaskStep.UpdateProgress(progress)               
from collections import OrderedDict
+
 
map_names = []
+
#######################################################################
map_count=0
+
# https://github.com/barrycarey/Ark_Mod_Downloader/blob/master/Ark_Mod_Downloader.py #
temp_mod_path = os.path.join(ThisService.RootDirectory, "ShooterGame/Content/Mods")
+
#######################################################################
meta_data = OrderedDict([])
+
import os
+
import struct
def parse_base_info(modid):
+
from collections import OrderedDict
+
map_names = []
        Script.WriteToConsole("[+] Collecting Mod Details From mod.info")
+
map_count=0
+
temp_mod_path = os.path.join(ThisService.RootDirectory, "ShooterGame/Content/Mods")
        mod_info = os.path.join(temp_mod_path, modid, "mod.info")
+
meta_data = OrderedDict([])
+
 
        if not os.path.isfile(mod_info):
+
def parse_base_info(modid):
            Script.WriteToConsole("[x] Failed to locate mod.info. Cannot Continue.  Aborting")
+
 
            return False
+
        Script.WriteToConsole("[+] Collecting Mod Details From mod.info")
+
 
        with open(mod_info, "rb") as f:
+
        mod_info = os.path.join(temp_mod_path, modid, "mod.info")
            read_ue4_string(f)
+
 
            map_count = struct.unpack('i', f.read(4))[0]
+
        if not os.path.isfile(mod_info):
+
            Script.WriteToConsole("[x] Failed to locate mod.info. Cannot Continue.  Aborting")
            for i in range(map_count):
+
            return False
                cur_map = read_ue4_string(f)
+
 
                if cur_map:
+
        with open(mod_info, "rb") as f:
                    map_names.append(cur_map)
+
            read_ue4_string(f)
+
            map_count = struct.unpack('i', f.read(4))[0]
        return True
+
 
+
            for i in range(map_count):
def parse_meta_data(modid):
+
                cur_map = read_ue4_string(f)
        """
+
                if cur_map:
        Parse the modmeta.info files and extract the key value pairs need to for the .mod file.
+
                    map_names.append(cur_map)
        How To Parse modmeta.info:
+
 
            1. Read 4 bytes to tell how many key value pairs are in the file
+
        return True
            2. Read next 4 bytes tell us how many bytes to read ahead to get the key
+
 
            3. Read ahead by the number of bytes retrieved from step 2
+
def parse_meta_data(modid):
            4. Read next 4 bytes to tell how many bytes to read ahead to get value
+
        """
            5. Read ahead by the number of bytes retrieved from step 4
+
        Parse the modmeta.info files and extract the key value pairs need to for the .mod file.
            6. Start at step 2 again
+
        How To Parse modmeta.info:
        :return: Dict
+
            1. Read 4 bytes to tell how many key value pairs are in the file
        """
+
            2. Read next 4 bytes tell us how many bytes to read ahead to get the key
+
            3. Read ahead by the number of bytes retrieved from step 2
        print("[+] Collecting Mod Meta Data From modmeta.info")
+
            4. Read next 4 bytes to tell how many bytes to read ahead to get value
        print("[+] Located The Following Meta Data:")
+
            5. Read ahead by the number of bytes retrieved from step 4
+
            6. Start at step 2 again
        mod_meta = os.path.join(temp_mod_path, modid, "modmeta.info")
+
        :return: Dict
        if not os.path.isfile(mod_meta):
+
        """
            Script.WriteToConsole("[x] Failed To Locate modmeta.info. Cannot continue without it.  Aborting")
+
 
            return False
+
        print("[+] Collecting Mod Meta Data From modmeta.info")
+
        print("[+] Located The Following Meta Data:")
        with open(mod_meta, "rb") as f:
+
 
+
        mod_meta = os.path.join(temp_mod_path, modid, "modmeta.info")
            total_pairs = struct.unpack('i', f.read(4))[0]
+
        if not os.path.isfile(mod_meta):
+
            Script.WriteToConsole("[x] Failed To Locate modmeta.info. Cannot continue without it.  Aborting")
            for i in range(total_pairs):
+
            return False
+
 
                key, value = "", ""
+
        with open(mod_meta, "rb") as f:
+
 
                key_bytes = struct.unpack('i', f.read(4))[0]
+
            total_pairs = struct.unpack('i', f.read(4))[0]
                key_flag = False
+
 
                if key_bytes < 0:
+
            for i in range(total_pairs):
                    key_flag = True
+
 
                    key_bytes -= 1
+
                key, value = "", ""
+
 
                if not key_flag and key_bytes > 0:
+
                key_bytes = struct.unpack('i', f.read(4))[0]
+
                key_flag = False
                    raw = f.read(key_bytes)
+
                if key_bytes < 0:
                    key = raw[:-1].decode()
+
                    key_flag = True
+
                    key_bytes -= 1
                value_bytes = struct.unpack('i', f.read(4))[0]
+
 
                value_flag = False
+
                if not key_flag and key_bytes > 0:
                if value_bytes < 0:
+
 
                    value_flag = True
+
                    raw = f.read(key_bytes)
                    value_bytes -= 1
+
                    key = raw[:-1].decode()
+
 
                if not value_flag and value_bytes > 0:
+
                value_bytes = struct.unpack('i', f.read(4))[0]
                    raw = f.read(value_bytes)
+
                value_flag = False
                    value = raw[:-1].decode()
+
                if value_bytes < 0:
+
                    value_flag = True
                # TODO This is a potential issue if there is a key but no value
+
                    value_bytes -= 1
                if key and value:
+
 
                    Script.WriteToConsole("[!] " + key + ":" + value)
+
                if not value_flag and value_bytes > 0:
                    meta_data[key] = value
+
                    raw = f.read(value_bytes)
+
                    value = raw[:-1].decode()
        return True
+
 
+
                # TODO This is a potential issue if there is a key but no value
def create_mod_file(modid):
+
                if key and value:
        """
+
                    Script.WriteToConsole("[!] " + key + ":" + value)
        Create the .mod file.
+
                    meta_data[key] = value
        This code is an adaptation of the code from Ark Server Launcher.  All credit goes to Face Wound on Steam
+
 
        :return:
+
        return True
        """
+
 
        if not parse_base_info(modid) or not parse_meta_data(modid):
+
def create_mod_file(modid):
            return False
+
        """
+
        Create the .mod file.
        print("[+] Writing .mod File")
+
        This code is an adaptation of the code from Ark Server Launcher.  All credit goes to Face Wound on Steam
        with open(os.path.join(temp_mod_path, modid + ".mod"), "w+b") as f:
+
        :return:
+
        """
            modid = int(modid)
+
        if not parse_base_info(modid) or not parse_meta_data(modid):
            f.write(struct.pack('ixxxx', modid))  # Needs 4 pad bits
+
            return False
            write_ue4_string("ModName", f)
+
 
            write_ue4_string("", f)
+
        print("[+] Writing .mod File")
+
        with open(os.path.join(temp_mod_path, modid + ".mod"), "w+b") as f:
            map_count = len(map_names)
+
 
            f.write(struct.pack("i", map_count))
+
            modid = int(modid)
+
            f.write(struct.pack('ixxxx', modid))  # Needs 4 pad bits
            for m in map_names:
+
            write_ue4_string("ModName", f)
                write_ue4_string(m, f)
+
            write_ue4_string("", f)
+
 
            # Not sure of the reason for this
+
            map_count = len(map_names)
            num2 = 4280483635
+
            f.write(struct.pack("i", map_count))
            f.write(struct.pack('I', num2))
+
 
            num3 = 2
+
            for m in map_names:
            f.write(struct.pack('i', num3))
+
                write_ue4_string(m, f)
+
 
            if "ModType" in meta_data:
+
            # Not sure of the reason for this
                mod_type = b'1'
+
            num2 = 4280483635
            else:
+
            f.write(struct.pack('I', num2))
                mod_type = b'0'
+
            num3 = 2
+
            f.write(struct.pack('i', num3))
            # TODO The packing on this char might need to be changed
+
 
            f.write(struct.pack('p', mod_type))
+
            if "ModType" in meta_data:
            meta_length = len(meta_data)
+
                mod_type = b'1'
            f.write(struct.pack('i', meta_length))
+
            else:
+
                mod_type = b'0'
            for k, v in meta_data.items():
+
 
                write_ue4_string(k, f)
+
            # TODO The packing on this char might need to be changed
                write_ue4_string(v, f)
+
            f.write(struct.pack('p', mod_type))
+
            meta_length = len(meta_data)
        return True
+
            f.write(struct.pack('i', meta_length))
+
 
def read_ue4_string(file):
+
            for k, v in meta_data.items():
        count = struct.unpack('i', file.read(4))[0]
+
                write_ue4_string(k, f)
        flag = False
+
                write_ue4_string(v, f)
        if count < 0:
+
 
            flag = True
+
        return True
            count -= 1
+
 
+
def read_ue4_string(file):
        if flag or count <= 0:
+
        count = struct.unpack('i', file.read(4))[0]
            return ""
+
        flag = False
+
        if count < 0:
        return file.read(count)[:-1].decode()
+
            flag = True
+
            count -= 1
def write_ue4_string(string_to_write, file):
+
 
        string_length = len(string_to_write) + 1
+
        if flag or count <= 0:
        file.write(struct.pack('i', string_length))
+
            return ""
        barray = bytearray(string_to_write, "utf-8")
+
 
        file.write(barray)
+
        return file.read(count)[:-1].decode()
        file.write(struct.pack('p', b'0'))
+
 
+
def write_ue4_string(string_to_write, file):
###########################################
+
        string_length = len(string_to_write) + 1
###########################################
+
        file.write(struct.pack('i', string_length))
###########################################
+
        barray = bytearray(string_to_write, "utf-8")
+
        file.write(barray)
# Always use Windows files. Linux files cause the game server to crash at startup.
+
        file.write(struct.pack('p', b'0'))
oseditor="WindowsNoEditor"
+
 
noeditor=Path.Combine(InstallPath, oseditor )
+
###########################################
+
###########################################
# Extract and delete all .z files
+
###########################################
for zfile in Directory.GetFiles(noeditor, "*.z", SearchOption.AllDirectories):
+
# If the content folder doesn't exist use downloads
 +
if not Directory.Exists(InstallPath) :
 +
  InstallPath=InstallPath.Replace("/content/", "/downloads/")
 +
 
 +
# Always use Windows files. Linux files cause the game server to crash at startup.
 +
oseditor="WindowsNoEditor"
 +
noeditor=Path.Combine(InstallPath, oseditor )
 +
 
 +
# Extract and delete all .z files
 +
zfiles=Directory.GetFiles(noeditor, "*.z", SearchOption.AllDirectories);
 +
totalfilecount=zfiles.Count
 +
for zfile in zfiles:
 
   file=Path.Combine(Path.GetDirectoryName(zfile), Path.GetFileNameWithoutExtension(zfile))
 
   file=Path.Combine(Path.GetDirectoryName(zfile), Path.GetFileNameWithoutExtension(zfile))
 
   z_unpack(zfile, file)
 
   z_unpack(zfile, file)
Line 210: Line 221:
 
   File.Delete(zfile)
 
   File.Delete(zfile)
 
   File.Delete(zfile + ".uncompressed_size")
 
   File.Delete(zfile + ".uncompressed_size")
+
 
# Move folder to correct location. Delete if it already exists.
+
# Move folder to correct location. Delete if it already exists.
modfolder=Path.Combine(ThisService.RootDirectory, String.Format("ShooterGame/Content/Mods/{0}", FileId))
+
modfolder=Path.Combine(ThisService.RootDirectory, String.Format("ShooterGame/Content/Mods/{0}", FileId))
if Directory.Exists(modfolder) :
+
if Directory.Exists(modfolder) :
  Directory.Delete(modfolder, True)
+
  Directory.Delete(modfolder, True)
Directory.Move(Path.Combine(InstallPath, oseditor), modfolder)
+
Directory.Move(Path.Combine(InstallPath, oseditor), modfolder)
+
 
# Update ini file
+
# Update ini file
serveros = "WindowsServer" if Environment.OSVersion.Platform == PlatformID.Win32NT else "LinuxServer"
+
serveros = "WindowsServer" if Environment.OSVersion.Platform == PlatformID.Win32NT else "LinuxServer"
inifile = Path.Combine(ThisService.RootDirectory, String.Format("ShooterGame/Saved/Config/{0}/GameUserSettings.ini", serveros))
+
inifile = Path.Combine(ThisService.RootDirectory, String.Format("ShooterGame/Saved/Config/{0}/GameUserSettings.ini", serveros))
pattern="ActiveMods[ \t]*=[ \t]*(?<ActiveMods>[0-9, \t]*)"
+
pattern="ActiveMods[ \t]*=[ \t]*(?<ActiveMods>[0-9, \t]*)"
filecontents = File.ReadAllText(inifile)
+
filecontents = File.ReadAllText(inifile)
match = Regex.Match(filecontents, pattern, RegexOptions.IgnoreCase)
+
match = Regex.Match(filecontents, pattern, RegexOptions.IgnoreCase)
if match.Success :
+
if match.Success :
  activemods = match.Groups["ActiveMods"].Value
+
  activemods = match.Groups["ActiveMods"].Value
  if String.IsNullOrEmpty(activemods) or activemods.IndexOf(FileId.ToString()) == -1 :
+
  if String.IsNullOrEmpty(activemods) or activemods.IndexOf(FileId.ToString()) == -1 :
    if activemods.Length > 0 :
+
    if activemods.Length > 0 :
      activemods = activemods + ","
+
      activemods = activemods + ","
      activemods = activemods + FileId.ToString()
+
      activemods = activemods + FileId.ToString()
      filecontents=filecontents.Replace(match.Groups["ActiveMods"].Value, activemods)
+
      filecontents=filecontents.Replace(match.Groups["ActiveMods"].Value, activemods)
    else :
+
    else :
      activemods = FileId.ToString()
+
      activemods = FileId.ToString()
      filecontents = filecontents.Substring(0, match.Groups["ActiveMods"].Index) + activemods + filecontents.Substring(match.Groups["ActiveMods"].Index)
+
      filecontents = filecontents.Substring(0, match.Groups["ActiveMods"].Index) + activemods + filecontents.Substring(match.Groups["ActiveMods"].Index)
    File.WriteAllText(inifile, filecontents)
+
    File.WriteAllText(inifile, filecontents)
+
 
#Create .mod
+
#Create .mod
parse_base_info(FileId.ToString())
+
parse_base_info(FileId.ToString())
parse_meta_data(FileId.ToString())
+
parse_meta_data(FileId.ToString())
create_mod_file(FileId.ToString())
+
create_mod_file(FileId.ToString())
+
 
# Delete folder
+
# Delete folder
if Directory.Exists(InstallPath) :
+
if Directory.Exists(InstallPath) :
  Directory.Delete(InstallPath, True)
+
  Directory.Delete(InstallPath, True)</source>

Revision as of 17:10, 9 June 2020

import clr

from System.IO import Directory, File, Path, SearchOption
from System import Environment, PlatformID, String, Exception
from System.Text.RegularExpressions import Regex, RegexOptions, Match

extractedcount=0
totalfilecount=0
lastfileprogress=0

########################################
# https://github.com/TheCherry/ark-server-manager #
########################################
import struct
import zlib
import sys

def str_to_l(st):
    return struct.unpack('q', st)[0]

def z_unpack(src, dst):
    global extractedcount, totalfilecount, lastfileprogress
    with open(src, 'rb') as f_src:
        with open(dst, 'wb') as f_dst:
            f_src.read(8)
            size1 = str_to_l(f_src.read(8))
            f_src.read(8)
            size2 = str_to_l(f_src.read(8))
            if(size1 == -1641380927):
                size1 = 131072L
            runs = (size2 + size1 - 1L) / size1
            array = []
            for i in range(runs):
                array.append(f_src.read(8))
                f_src.read(8)
            for i in range(runs):
                to_read = array[i]
                compressed = f_src.read(str_to_l(to_read))
                decompressed = zlib.decompress(compressed)
                f_dst.write(decompressed)
    Script.WriteToConsole("Extracted " + dst.Replace(ThisService.RootDirectory, ""))
    File.Delete(src)
    File.Delete(src + ".uncompressed_size")
    extractedcount=extractedcount+1
    progress=round((float(extractedcount)/totalfilecount)*100,0)
    if progress > lastfileprogress + 4:
      lastfileprogress=progress
      ThisTaskStep.UpdateProgress(progress)                

#######################################################################
# https://github.com/barrycarey/Ark_Mod_Downloader/blob/master/Ark_Mod_Downloader.py #
#######################################################################
import os
import struct
from collections import OrderedDict
map_names = []
map_count=0
temp_mod_path = os.path.join(ThisService.RootDirectory, "ShooterGame/Content/Mods")
meta_data = OrderedDict([])

def parse_base_info(modid):

        Script.WriteToConsole("[+] Collecting Mod Details From mod.info")

        mod_info = os.path.join(temp_mod_path, modid, "mod.info")

        if not os.path.isfile(mod_info):
            Script.WriteToConsole("[x] Failed to locate mod.info. Cannot Continue.  Aborting")
            return False

        with open(mod_info, "rb") as f:
            read_ue4_string(f)
            map_count = struct.unpack('i', f.read(4))[0]

            for i in range(map_count):
                cur_map = read_ue4_string(f)
                if cur_map:
                    map_names.append(cur_map)

        return True

def parse_meta_data(modid):
        """
        Parse the modmeta.info files and extract the key value pairs need to for the .mod file.
        How To Parse modmeta.info:
            1. Read 4 bytes to tell how many key value pairs are in the file
            2. Read next 4 bytes tell us how many bytes to read ahead to get the key
            3. Read ahead by the number of bytes retrieved from step 2
            4. Read next 4 bytes to tell how many bytes to read ahead to get value
            5. Read ahead by the number of bytes retrieved from step 4
            6. Start at step 2 again
        :return: Dict
        """

        print("[+] Collecting Mod Meta Data From modmeta.info")
        print("[+] Located The Following Meta Data:")

        mod_meta = os.path.join(temp_mod_path, modid, "modmeta.info")
        if not os.path.isfile(mod_meta):
            Script.WriteToConsole("[x] Failed To Locate modmeta.info. Cannot continue without it.  Aborting")
            return False

        with open(mod_meta, "rb") as f:

            total_pairs = struct.unpack('i', f.read(4))[0]

            for i in range(total_pairs):

                key, value = "", ""

                key_bytes = struct.unpack('i', f.read(4))[0]
                key_flag = False
                if key_bytes < 0:
                    key_flag = True
                    key_bytes -= 1

                if not key_flag and key_bytes > 0:

                    raw = f.read(key_bytes)
                    key = raw[:-1].decode()

                value_bytes = struct.unpack('i', f.read(4))[0]
                value_flag = False
                if value_bytes < 0:
                    value_flag = True
                    value_bytes -= 1

                if not value_flag and value_bytes > 0:
                    raw = f.read(value_bytes)
                    value = raw[:-1].decode()

                # TODO This is a potential issue if there is a key but no value
                if key and value:
                    Script.WriteToConsole("[!] " + key + ":" + value)
                    meta_data[key] = value

        return True

def create_mod_file(modid):
        """
        Create the .mod file.
        This code is an adaptation of the code from Ark Server Launcher.  All credit goes to Face Wound on Steam
        :return:
        """
        if not parse_base_info(modid) or not parse_meta_data(modid):
            return False

        print("[+] Writing .mod File")
        with open(os.path.join(temp_mod_path, modid + ".mod"), "w+b") as f:

            modid = int(modid)
            f.write(struct.pack('ixxxx', modid))  # Needs 4 pad bits
            write_ue4_string("ModName", f)
            write_ue4_string("", f)

            map_count = len(map_names)
            f.write(struct.pack("i", map_count))

            for m in map_names:
                write_ue4_string(m, f)

            # Not sure of the reason for this
            num2 = 4280483635
            f.write(struct.pack('I', num2))
            num3 = 2
            f.write(struct.pack('i', num3))

            if "ModType" in meta_data:
                mod_type = b'1'
            else:
                mod_type = b'0'

            # TODO The packing on this char might need to be changed
            f.write(struct.pack('p', mod_type))
            meta_length = len(meta_data)
            f.write(struct.pack('i', meta_length))

            for k, v in meta_data.items():
                write_ue4_string(k, f)
                write_ue4_string(v, f)

        return True

def read_ue4_string(file):
        count = struct.unpack('i', file.read(4))[0]
        flag = False
        if count < 0:
            flag = True
            count -= 1

        if flag or count <= 0:
            return ""

        return file.read(count)[:-1].decode()

def write_ue4_string(string_to_write, file):
        string_length = len(string_to_write) + 1
        file.write(struct.pack('i', string_length))
        barray = bytearray(string_to_write, "utf-8")
        file.write(barray)
        file.write(struct.pack('p', b'0'))

###########################################
###########################################
###########################################
# If the content folder doesn't exist use downloads
if not Directory.Exists(InstallPath) :
  InstallPath=InstallPath.Replace("/content/", "/downloads/")

# Always use Windows files. Linux files cause the game server to crash at startup.
oseditor="WindowsNoEditor"
noeditor=Path.Combine(InstallPath, oseditor )

# Extract and delete all .z files
zfiles=Directory.GetFiles(noeditor, "*.z", SearchOption.AllDirectories);
totalfilecount=zfiles.Count
for zfile in zfiles:
  file=Path.Combine(Path.GetDirectoryName(zfile), Path.GetFileNameWithoutExtension(zfile))
  z_unpack(zfile, file)
  Script.WriteToConsole("Extracted " + file)
  File.Delete(zfile)
  File.Delete(zfile + ".uncompressed_size")

# Move folder to correct location. Delete if it already exists.
modfolder=Path.Combine(ThisService.RootDirectory, String.Format("ShooterGame/Content/Mods/{0}", FileId))
if Directory.Exists(modfolder) :
  Directory.Delete(modfolder, True)
Directory.Move(Path.Combine(InstallPath, oseditor), modfolder)

# Update ini file
serveros = "WindowsServer" if Environment.OSVersion.Platform == PlatformID.Win32NT else "LinuxServer"
inifile = Path.Combine(ThisService.RootDirectory, String.Format("ShooterGame/Saved/Config/{0}/GameUserSettings.ini", serveros))
pattern="ActiveMods[ \t]*=[ \t]*(?<ActiveMods>[0-9, \t]*)"
filecontents = File.ReadAllText(inifile)
match = Regex.Match(filecontents, pattern, RegexOptions.IgnoreCase)
if match.Success :
  activemods = match.Groups["ActiveMods"].Value
  if String.IsNullOrEmpty(activemods) or activemods.IndexOf(FileId.ToString()) == -1 :
    if activemods.Length > 0 :
      activemods = activemods + ","
      activemods = activemods + FileId.ToString()
      filecontents=filecontents.Replace(match.Groups["ActiveMods"].Value, activemods)
    else :
      activemods = FileId.ToString()
      filecontents = filecontents.Substring(0, match.Groups["ActiveMods"].Index) + activemods + filecontents.Substring(match.Groups["ActiveMods"].Index)
    File.WriteAllText(inifile, filecontents)

#Create .mod
parse_base_info(FileId.ToString())
parse_meta_data(FileId.ToString())
create_mod_file(FileId.ToString())

# Delete folder
if Directory.Exists(InstallPath) :
  Directory.Delete(InstallPath, True)
Retrieved from "https://help.tcadmin.com/index.php?title=Ark_Workshop_Scripts_for_Linux&oldid=2171"