0

I am somewhat new to programming. I did not go to school to learn about it, but do read a lot online to learn more about coding.

In general, if I know a concept then I can usually figure it out with google.

Obvious from the post, I like to play games and so I thought one day while configuring some settings for a mod, I realized that the information was extremely difficult to dig up. I thought that I could try to solve it by writing a python script (no real success writing scripts before this point).

The following is the general workflow that I wrote up before tackling it in python:

  1. Replace base path up to 'Mods' with '/Game/Mods'
  2. Find all paths to files in Mods folder
  3. Rename all mod files ending in uasset. E.g. filname.uasset -> filename.filename
  4. Parse Mod's name from binary file in Mod subdirectory, replace integer name with text name for all related paths. E.g. mod name 899987403 -> Primal_Fear_Bosses

Example before (ubuntu path): /mnt/c/Program Files (x86)/Steam/steamapps/common/ARK/ShooterGame/Content/Mods/899987403/Vanilla/Projectiles/Manticore/Proj/PFBProjManticoreQuill.uasset

& after with script: /Game/Mods/Primal_Fear_Bosses/Vanilla/Projectiles/Manticore/Proj/PFBProjManticoreQuill.PFBProjManticoreQuill,

*Note: align the "/Mods/" section for both lines to see the key difference.

Anyways, I was familiar with a lot of concepts at that point, so I did a lot of googling and wrote the following script (first ever), "Generate_Resource_Pulling_List_for_S+.py":

import os
import sys
from fnmatch import fnmatch
import re


# define the directory that mods are installed in
# ubuntu path
# modDir = "C:/Program Files (x86)/Steam/steamapps/common/ARK/ShooterGame/Content/Mods"
# windows path
modDir = "C:\Program Files (x86)\Steam\steamapps\common\ARK\ShooterGame\Content\Mods\\"
stringPattern = r"\w+(.mod)"
regexPattern = re.compile(stringPattern)
modFolders = [mod for mod in os.listdir(modDir) if not regexPattern.match(mod)]

# loop through mod list and append directory to mod installation path
for items in modFolders:
    modPath = "%s%s" % (modDir, items)

    # parse mod name from meta file, store for later
    modMetaFilePath = "%s\%s" % (modPath, "modmeta.info")
    validPath = os.path.exists(modMetaFilePath)
    if not validPath:
        print('x is:', validPath)
        pass
    try:
        modFile = open(modMetaFilePath, "rb")
        binaryContent = modFile.read(-1)
        modFile.close()
        # if len == 0:
        #     print('length:', len(binaryContent))
        #     break
        # print(type(binaryContent))
        text = binaryContent.decode('UTF-8')
        try:
            parsedModName = text.split('Mods/')[1].split('/')[0]
            if not parsedModName:
                break
        except ValueError as e:
            pass
    except Exception as e:
        pass

    for path, subdirs, files in os.walk(modPath):
        # for i in range(len(subdirs)):
        #     print('Number of Sub Directories: ', len(subdirs))
        #     print('Current Directory Number in ', path, ': ', subdirs[i])
        for name in files:
            pattern = "*.uasset"
            if fnmatch(name, pattern):
                try:
                    path = os.path.normpath(path) + '\\'
                    if not path:
                        continue
                    try:
                        basePath = os.path.join('\\Game\\Mods\\', parsedModName)
                    except Exception as e:
                        pass
                        print('failed here:', str(e))
                    strippedBasePath = os.path.dirname(path).split(items)[1]
                    if not strippedBasePath:
                        print('failed at this point stripped path', strippedBasePath, '\n\t', 'path', path)
                        continue
                    revisedFileName = os.path.join(
                        os.path.basename(name).split('.')[0] + '.' + os.path.basename(name).split('.')[0] + ',')
                    finalPath = "%s%s\%s" % (basePath, strippedBasePath, revisedFileName)
                    flippedSlashFinalPath = finalPath.replace("\\", "/")
                    print(flippedSlashFinalPath)
                    with open("out.txt", "a") as external_file:
                        add_text = flippedSlashFinalPath
                        external_file.write(add_text)
                        external_file.close()
                except Exception as e:
                    print('Something happened', str(e))

I initially installed an Ubuntu environment on Windows because I am unfamiliar with command line/bash/scripting in Windows as seen in the mod path (slashes are reversed and commands are different). I am much more familiar with MacOS and generally work in Linux environments and terminals.

I thought that this script would be usable by others with a bit of programming knowledge, but it is not the most user friendly.

In any case, this was my first attempt at writing something and trying to use good practices.

As another side project to practice more coding, I rewrote it and implemented more complex concepts.

Here is the refactored version:

import os
import sys
from fnmatch import fnmatch
import re
import winreg

stringPattern = r"\w+(.mod)"
regexPattern = re.compile(stringPattern)


class Mod(object):
    def __init__(self):
        pass
        self.steam_path = None
        self.mod_folders = []
        self.mod_path = None
        self.mod_path_list = []
        self.mod_meta_path_list = []
        self.full_mod_path = None
        self.mod_meta = None
        self.resource_path = None

    @property
    def GetSteamPath(self):
        try:
            steam_key = "SOFTWARE\WOW6432Node\Valve\Steam"
            hkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, steam_key)
        except ValueError as e:
            hkey = None
            print(e.sys.exc_info())
        try:
            steam_path = winreg.QueryValueEx(hkey, "InstallPath")
        except ValueError as e:
            steam_path = None
            print(e.sys.exc_info())
        winreg.CloseKey(hkey)
        self.steam_path = steam_path[0]
        return self.steam_path

    def GetArkModPath(self):
        mod_dir = self.GetSteamPath[:] + "\steamapps\common\ARK\ShooterGame\Content\Mods\\"
        self.mod_folders = [mod for mod in os.listdir(mod_dir) if not regexPattern.match(mod)]
        mod_path_list = []
        count = 1
        while count < len(self.mod_folders):
            for mod in self.mod_folders:
                self.full_mod_path = ("%s%s\\" % (mod_dir, mod))
                mod_path_list.append(self.full_mod_path)
                self.mod_path_list = mod_path_list
                if not mod:
                    break
                # else:
                #     print('Test1', format(mod_path_list))
            return self.mod_path_list
            count += 1

    def GetModResourceList(self, mod_path_list):
        mod_folder_index = 0
        for mod_path in mod_path_list:
            mod_meta_path = "%s%s" % (mod_path, "modmeta.info")
            self.mod_meta_path_list.append(mod_meta_path)
            validPath = os.path.exists(mod_meta_path)
            if not validPath:
                # print('No Mod Meta File found at: ', mod_meta_path)
                continue
            try:
                mod_file = open(mod_meta_path, "rb")
                binary_content = mod_file.read(-1)
                mod_file.close()
                text = binary_content.decode('UTF-8')
                try:
                    parsed_mod_name = text.split('Mods/')[1].split('/')[0]
                    if not parsed_mod_name:
                        break
                except ValueError as e:
                    pass
            except Exception as e:
                pass
            for path, subdirs, files in os.walk(mod_path):
                # for i in range(len(subdirs)):
                    # print('Number of Sub Directories: ', len(subdirs))
                    # print('Current Directory Number in ', path, ': ', subdirs[i])
                for uasset_file in files:
                    pattern = "*.uasset"
                    if fnmatch(uasset_file, pattern):
                        try:
                            path = os.path.normpath(path) + '\\'
                            if not path:
                                continue
                            try:
                                base_path = os.path.join('\\Game\\Mods\\', parsed_mod_name)
                            except Exception as e:
                                pass
                                print('failed here:', str(e))
                            stripped_base_path = os.path.dirname(path).split(self.mod_folders[mod_folder_index])[1]
                            resource_name = os.path.join(
                                os.path.basename(uasset_file).split('.')[0] + '.' + os.path.basename(uasset_file).split('.')[0] + ',')
                            full_path = "%s%s\%s" % (base_path, stripped_base_path, resource_name)
                            resource_path = full_path.replace("\\", "/")
                            self.resource_path = resource_path
                            # to see what text is written to the file, uncomment print here
                            print(self.resource_path)
                            with open("test_out.txt", "a") as external_file:
                                add_text = self.resource_path
                                external_file.write(add_text)
                                external_file.close()
                        except Exception as e:
                            print('Error: ', str(e))
                            # return self.resource_path[]
            mod_folder_index += 1

ark = Mod()
ark_mods = ark.GetArkModPath()
ark.GetModResourceList(ark_mods)

This revised one is much more user friendly and does not necessarily require input or modification of variables. I tried to avoid requiring arguments passed in a method call because I wanted to automate the script as necessary without any input from user.

If you have Ark installed with some mods, then you may be able to actually use or test the scripts. I'm curious if they work for others. FYI, not all paths are usable. It might be best to delete/remove some or just pick out the ones you want. Can't really figure out the best way to identify this.

I struggled with creating an instance of my class, what attributes to set, what properties to set, setting(?) values for attributes for my class, calling those stored values, and just about everything else you can imagine.

Some things are obvious to me, such as it is pointless to create classes and methods in a script that is not necessarily being re-used. It was still fun and the point was to learn and practice.

In any case, I am open to any feedback because I do not know what is common sense for everything or best practices that others have seen. As a side note, I do versioning with local repos. I have worked with git and bitbucket before.

Preferred topics if not sure: defensive programming proper exception handling SOLID (I'm def lacking here) Classes (I barely got mine working if its not apparrent) Methods (seems straight forward to me - if code is going to be copied, put it in a method) Preferred nomenclature for everything, classes, methods, variables (I googled it, but still don't like how it looks especially when they get long) Readability (I understand that if code requires comments, its not good) Cleanliness (I guess this is an art, but I see spaghetti when I look at what I wrote)

Links to resources are welcome! I really appreciate any feedback and look forward to all comments.

0 Answers0