def MakeTest(origin, target): script_path = util.GetScriptPath() util.LogDebug("This is the origin: " + origin) util.LogDebug("This is the target: " + target) FoldersToCreate = [] FilesToCreate = [] util.CreateTarget(target) util.LogDebug("Target Created") for root, subdirs, files in os.walk(origin): if root != origin: FoldersToCreate.append(root) util.LogDebug("Adding folder ({})".format(root)) for filename in files: file_path = os.path.join(root, filename) FilesToCreate.append(file_path) util.LogDebug("Adding file ({})".format(file_path)) for folderToCreate in FoldersToCreate: util.LogDebug("About to add folder ({})".format(folderToCreate)) newFolderName = folderToCreate.replace(origin, target) util.LogDebug("New folder name is ({})".format(newFolderName)) os.mkdir(newFolderName) for fileToCreate in FilesToCreate: util.LogDebug("About to add file ({})".format(fileToCreate)) newFileName = fileToCreate.replace(origin, target) util.LogDebug("New filename is ({})".format(newFileName)) with open(newFileName, "w") as myFile: myFile.write("TESTFILE")
def ReconcileHKX(mod_path, oldrim_path): script_path = util.GetScriptPath() util.LogInfo("Reconcile HKX") util.LogDebug("This is the mod_path: " + mod_path) util.LogDebug("This is the oldrim_path " + oldrim_path) CopyHKX = [] totalCount = 0 matchedCount = 0 for root, subdirs, files in os.walk(mod_path): util.LogDebug("Walking folder " + root) for filename in files: if filename.lower().endswith(".hkx"): file_path = os.path.join(root, filename) relative_path = os.path.relpath(file_path, mod_path) util.LogDebug("Relative path {} OR Path {}".format( relative_path, oldrim_path)) oldrim_file_path = os.path.join(oldrim_path, relative_path) totalCount += 1 util.LogDebug("Found {}, checking {}".format( file_path, oldrim_file_path)) if os.path.exists(oldrim_file_path): util.LogDebug( "Found {} match in oldrim".format(oldrim_file_path)) matchedCount += 1 CopyHKX.append((file_path, oldrim_file_path)) util.LogInfo("Matched {}/{} hkx files in the mod".format( matchedCount, totalCount)) for i in range(len(CopyHKX)): (copy_to, copy_from) = CopyHKX[i] util.LogDebug("Copying {}->{}".format(copy_from, copy_to)) shutil.copy2(copy_from, copy_to) sys.stdout.write("Reconciled {}/{} \r".format(i + 1, len(CopyHKX))) sys.stdout.flush() sys.stdout.write("\n")
def ConvertPath(mod_name, target): script_path = util.GetScriptPath() util.LogInfo("Convert Path") util.LogDebug("This is the target: " + target) util.LogDebug("This is the mod name " + mod_name) has_havoc = util.HasHavokBPP() do_meshes = \ toolkit_config.get_bool_setting("Meshes", "RemoveEditorMarker") or \ toolkit_config.get_bool_setting("Meshes", "PrettySortBlocks") or \ toolkit_config.get_bool_setting("Meshes", "TrimTexturesPath") or \ toolkit_config.get_bool_setting("Meshes", "OptimizeForSSE") NoConversion = {} WarnConversion = {} ConvertListDDS = [] ConvertListHKX = [] ConvertListHKX64 = [] ConvertListTXT = [] ConvertListSound = [] ConvertListMesh = [] for root, subdirs, files in os.walk(target): if root != target: util.LogDebug("Walking folder " + root) for filename in files: #util.LogDebug("filename: {}".format(filename)) if filename.lower().endswith(".dds"): file_path = os.path.join(root, filename) ddsChecked = check_dds.CheckDDS(file_path, file_path) if ddsChecked == check_dds.PC: ConvertListDDS.append(file_path) elif ddsChecked == check_dds.NX: if 'DDS' not in NoConversion: NoConversion['DDS'] = 0 NoConversion['DDS'] += 1 else: if 'DDS' not in WarnConversion: WarnConversion['DDS'] = [] WarnConversion['DDS'].append( (filename, "Unknown DDS format")) elif filename.lower().endswith(".hkx"): file_path = os.path.join(root, filename) hkxChecked = check_hkx.CheckHKX(file_path, file_path) if hkxChecked == check_hkx.PC_32: ConvertListHKX.append(file_path) elif hkxChecked == check_hkx.PC_XML: ConvertListHKX.append(file_path) elif hkxChecked == check_hkx.PC_64: # if root.lower().find("behaviors") > 0 or filename.lower().find("skeleton") > 0: # if 'HKX' not in WarnConversion: # WarnConversion['HKX'] = [] # WarnConversion['HKX'].append( (filename, "SSE hkx animation") ) # else: ConvertListHKX64.append(file_path) elif hkxChecked == check_hkx.NX_64: if 'HKX' not in NoConversion: NoConversion['HKX'] = 0 NoConversion['HKX'] += 1 else: if 'HKX' not in WarnConversion: WarnConversion['HKX'] = [] WarnConversion['HKX'].append( (filename, "Unknown hkx animation format")) elif filename.lower().startswith( "translate_") and filename.lower().endswith(".txt"): file_path = os.path.join(root, filename) ConvertListTXT.append(file_path) elif filename.lower().endswith(".xwm") or filename.lower( ).endswith(".fuz") or filename.lower().endswith(".wav"): file_path = os.path.join(root, filename[:-4]) if not file_path in ConvertListSound: ConvertListSound.append(file_path) elif filename.lower().endswith(".nif"): file_path = os.path.join(root, filename) ConvertListMesh.append(file_path) for fileType in NoConversion: util.LogInfo("Found {} {} files that are already in NX format".format( NoConversion[fileType], fileType)) for fileType in WarnConversion: fileTypeWarnings = WarnConversion[fileType] for i in range(len(fileTypeWarnings)): util.LogInfo("Warning, cannot convert {} because <{}>".format( fileTypeWarnings[i][0], fileTypeWarnings[i][1])) util.LogInfo("Found {} dds files to convert".format(len(ConvertListDDS))) if has_havoc: util.LogInfo("Found {} 32-bit hkx files to convert".format( len(ConvertListHKX))) else: util.LogInfo( "Found {} 32-bit hkx files that won't convert as Havoc utility wasn't found." .format(len(ConvertListHKX))) util.LogInfo("Found {} 64-bit hkx files to convert".format( len(ConvertListHKX64))) util.LogInfo("Found {} txt files to convert".format(len(ConvertListTXT))) util.LogInfo("Found {} sound files to convert".format( len(ConvertListSound))) if do_meshes: util.LogInfo("Found {} mesh files to convert".format( len(ConvertListMesh))) else: util.LogInfo("Found {} mesh files but won't touch them.".format( len(ConvertListMesh))) ''' def LogProgress(convertList, convertFn, name): if len(convertList) > 0: failedCount = 0 for i in range(len(convertList)): file_path = convertList[i] success = convertFn(target, file_path) if not success: failedCount += 1 sys.stdout.write("Converted {}/{} {} ({}) failed. \r".format(i+1, len(convertList), name, failedCount)) sys.stdout.flush() sys.stdout.write("\n") ''' def LogProgress(convertList, fnName, convertFn, name, threadSetting): if len(convertList) > 0: failedCount = 0 maxThreads = toolkit_config.get_int_setting( "Performance", threadSetting) jm = job_manager.JobManager(maxThreads) convertedCount = 0 processedCount = 0 totalCount = len(convertList) def cb(success): nonlocal processedCount, convertedCount, failedCount processedCount += 1 if success: convertedCount += 1 else: failedCount += 1 sys.stdout.write( "{} Processed {}/{} ({}/{}) success/failure. \r".format( name, processedCount, totalCount, convertedCount, failedCount)) sys.stdout.flush() for i in range(len(convertList)): file_path = convertList[i] job = job_manager.Job(cb, fnName, convertFn, target.lower(), file_path.lower()) jm.AddJob(job) jm.ProcessBatch() sys.stdout.write( "{} Processing Complete: {}/{} ({}/{}) success/failure. \r". format(name, processedCount, totalCount, convertedCount, failedCount)) sys.stdout.write("\n") if processedCount != totalCount: sys.stdout.write("Not all were processed.\n") sys.stdout.flush() LogProgress(ConvertListDDS, "ConvertDDS", convert_dds.ConvertDDS, "DDS", "MaxTextureThreads") if has_havoc: LogProgress(ConvertListHKX, "ConvertHKX", convert_hkx.ConvertHKX, "HKX 32-bit", "MaxAnimationThreads") LogProgress(ConvertListHKX64, "ConvertHKX64", convert_hkx64.ConvertHKX64, "HKX 64-bit", "MaxAnimationThreads") LogProgress(ConvertListTXT, "ConvertTXT", convert_txt.ConvertTXT, "TXT", "MaxOtherThreads") LogProgress(ConvertListSound, "ConvertSound", convert_sound.ConvertSound, "Sounds", "MaxSoundThreads") if do_meshes: LogProgress(ConvertListMesh, "ConvertMesh", convert_nif.ConvertNIF, "Meshes", "MaxMeshThreads")
def PackMod(mod_name, target): script_path = util.GetScriptPath() utilities_path = util.GetUtilitiesPath() bsarch = os.path.join(utilities_path, "bsarch.exe") util.LogDebug("This is the target: " + target) util.LogDebug("This is the mod name " + mod_name) util.LogInfo("Pack Mod") has_archive = util.HasArchive() util.LogDebug("HasArchive is {}".format(has_archive)) data_list = os.listdir(target) util.LogDebug(str(data_list)) BSARules = bsa_rules.GetBSARules() BSAs = {} SafePlugins = [ "skyrim.esm", "dawnguard.esm", "hearthfires.esm", "dragonborn.esm" ] PluginPaths = {} for plugin in SafePlugins: PluginPaths[plugin] = plugin # Arbitrary Limit to search for merged plugin list LineLimit = 10 ChunkSize = 1024 ChunksLimit = 10 childPattern = re.compile(r"Merged Plugin:([^\0]*)[\0]", re.MULTILINE) espPattern = re.compile(r"(.+?\.[^.]*$|$)", re.MULTILINE) def ReadPlugin(filename): util.LogDebug("Reading plugin{}".format(filename)) pluginList = [] with open(filename, "rb") as plugin: lineNumber = 0 chunkNumber = 0 foundMerge = False buffer = '' while True: chunk = plugin.read(ChunkSize) chunkNumber += 1 buffer = buffer + "".join(map(chr, chunk)) if "Merged Plugin:" in buffer: foundMerge = True if foundMerge: childPlugins = re.search(childPattern, buffer) if childPlugins != None: wholePattern = childPlugins.group(0) value = childPlugins.group(1) util.LogDebug("Found Plugins Block <{}>".format(value)) while True: espTest = re.findall(espPattern, value) if espTest != None: for espCandidate in espTest: espCandidate = espCandidate.strip( ) #''.join(espCandidate.split()) if espCandidate != '': util.LogDebug( "Found <{}>".format(espCandidate)) pluginList.append(espCandidate.lower()) #util.LogInfo("Found <{}>".format(str(espTest))) break break if chunkNumber >= ChunksLimit: break if not foundMerge: lineNumber += 1 if lineNumber >= LineLimit: break return pluginList mod_pathname = mod_name + ".esp" for root, subdirs, files in os.walk(target): for file in files: if file.endswith(".esp") or file.endswith(".esm"): filename = os.path.join(root, file) util.LogDebug("Found a plugin at {}, <{}>".format( filename, file)) # look after yourself PluginPaths[file.lower()] = file.lower() childrenOfPlugin = ReadPlugin(filename) if len(childrenOfPlugin) > 0: util.LogInfo( "Detected that {} is merged from:".format(file)) for child in childrenOfPlugin: util.LogInfo(" - {}".format(child)) # look after your children PluginPaths[child.lower()] = file.lower() mod_pathname = file # only interested in files in the root folder break util.LogDebug("PluginPaths is <{}>".format(str(PluginPaths))) def DefineBSA(bsa_name): nonlocal BSAs temp = os.path.join(target, "Temp") if bsa_name != '': temp = os.path.join(target, "Temp - " + bsa_name) temp_data = os.path.join(temp, "Data") util.RemoveTree(temp) os.makedirs(temp_data, exist_ok=True) BSAs[bsa_name] = temp_data numFoldersToMove = 0 numFilesToMove = 0 numFoldersMoved = 0 numFilesMoved = 0 def ApplyRuleToFolder(rule, folder): nonlocal numFoldersMoved bsa_name = rule["BSA"] if bsa_name not in BSAs: DefineBSA(bsa_name) move_to_folder = BSAs[bsa_name] child = os.path.basename(folder) parent = os.path.dirname(folder) if parent != target: util.LogDebug("parent is not target") rel_parent = os.path.relpath(parent, target) util.LogDebug("rel_parent is {}".format(rel_parent)) move_to_folder = os.path.join(move_to_folder, rel_parent, child) util.LogDebug("move_to_folder is {}".format(move_to_folder)) shutil.move(folder, move_to_folder) util.LogDebug("moving {} to {}".format(folder, move_to_folder)) numFoldersMoved += 1 sys.stdout.write("Moved Files {}/{} Folders {}/{} \r".format( numFilesMoved, numFilesToMove, numFoldersMoved, numFoldersToMove)) sys.stdout.flush() def ApplyRuleToFile(rule, file_path): nonlocal numFilesMoved bsa_name = rule["BSA"] if bsa_name not in BSAs: DefineBSA(bsa_name) relative_path = os.path.relpath(file_path, target) target_path = os.path.join(BSAs[bsa_name], relative_path) target_folder = os.path.dirname(target_path) os.makedirs(target_folder, exist_ok=True) util.LogDebug("moving {} to {}".format(file_path, target_path)) shutil.move(file_path, target_path) numFilesMoved += 1 sys.stdout.write("Moved Files {}/{} Folders {}/{} \r".format( numFilesMoved, numFilesToMove, numFoldersMoved, numFoldersToMove)) sys.stdout.flush() ignoreMovedFolders = [] for root, subdirs, files in os.walk(target): relative_folder = os.path.relpath(root, target).lower() if root != target: # Check if this folder is ignored already ignoreThisFolder = False for ignored in ignoreMovedFolders: if relative_folder.startswith(ignored): ignoreThisFolder = True if not ignoreThisFolder: # Now check if there is an unqualified path rule for this folder (like "scripts" are only placed in Misc) folderCount = 0 lastRuleMatch = None for rule in BSARules: if "Folder" in rule and relative_folder.startswith( rule["Folder"]): folderCount += 1 lastRuleMatch = rule if folderCount == 1: numFoldersToMove += 1 ignoreMovedFolders.append(relative_folder) else: for filename in files: util.LogDebug(os.path.join(relative_folder, filename)) numFilesToMove += 1 util.LogInfo("Files ({}) / Folders ({}) to move".format( numFilesToMove, numFoldersToMove)) RemoveFolders = [] for root, subdirs, files in os.walk(target): relative_folder = os.path.relpath(root, target).lower() #util.LogDebug("Walking relative folder " + relative_folder) if root == target: for child in subdirs: util.LogDebug("Children {}".format(child)) RemoveFolders.append(os.path.join(target, child)) else: # First check if there is an unqualified path rule for this folder (like "scripts" are only placed in Misc) folderCount = 0 lastRuleMatch = None for rule in BSARules: if "Folder" in rule and relative_folder.startswith( rule["Folder"]): folderCount += 1 lastRuleMatch = rule if folderCount == 1: util.LogDebug("ApplyRuleToFolder({}) -> {}".format( lastRuleMatch["BSA"], relative_folder)) ApplyRuleToFolder(lastRuleMatch, root) else: #util.LogDebug("No folder match, check files") for filename in files: filename = filename.lower() file_path = os.path.join(root, filename) relative_path = os.path.relpath(file_path, target) should_apply = False for rule in BSARules: should_apply = True if should_apply and "Folder" in rule: #util.LogDebug("checking folder rule {} vs relative_folder {}".format(rule["Folder"], relative_folder)) should_apply = should_apply and relative_folder.startswith( rule["Folder"]) if should_apply and "Extension" in rule: #util.LogDebug("checking extension rule {} vs filename {}".format(rule["Extension"], filename)) should_apply = should_apply and filename.endswith( rule["Extension"]) if should_apply: util.LogDebug("Applying BSA {} for {}".format( rule["BSA"], file_path)) ApplyRuleToFile(rule, file_path) break if not should_apply: util.LogWarn("Could not apply rule for <{}>".format( relative_path)) for rule in BSARules: should_apply = True if should_apply and "Folder" in rule: util.LogDebug( "checking folder rule {} vs relative_folder {}" .format(rule["Folder"], relative_folder)) should_apply = should_apply and relative_folder.startswith( rule["Folder"]) if should_apply and "Extension" in rule: util.LogDebug( "checking extension rule {} vs filename {}" .format(rule["Extension"], filename)) should_apply = should_apply and filename.endswith( rule["Extension"]) sys.stdout.write("\n") util.LogInfo("Cleanup old folders") for folder in RemoveFolders: util.LogDebug("Cleanup {}".format(folder)) util.RemoveTree(folder) def CleanPluginSpecificPaths(cleanup_directory): MoveFromTo = [] DeleteUnmatched = [] for root, subdirs, files in os.walk(cleanup_directory): directory = root.lower() dir_name = os.path.basename(directory) if (dir_name.endswith("esm") or dir_name.endswith("esp")) and dir_name not in SafePlugins: if dir_name in PluginPaths: target_pathname = PluginPaths[dir_name.lower()] new_path = os.path.join(os.path.dirname(directory), target_pathname) if not os.path.isdir(new_path): util.LogDebug( "Rename plugin directory {} to {}".format( directory, new_path)) os.rename(directory, new_path) else: util.LogDebug( "Move plugin files from directory {} to {}".format( directory, new_path)) MoveFromTo.append((directory, new_path)) else: util.LogWarn("Marking <{}> for deletion.".format(dir_name)) DeleteUnmatched.append(directory) for moveFromTo in MoveFromTo: (move_from, move_to) = moveFromTo util.LogDebug("Need to move from {} to {}".format( move_from, move_to)) for root, subdirs, files in os.walk(move_from): for file in files: file_path = os.path.join(root, file) relative_path = os.path.relpath(root, move_from) new_path = os.path.join(move_to, relative_path, file) util.LogDebug("Moving file from {} to {}".format( file_path, new_path)) new_directory = os.path.dirname(new_path) os.makedirs(new_directory, exist_ok=True) shutil.move(file_path, new_path) for deleteDirectory in DeleteUnmatched: util.LogDebug("Deleting <{}>".format(deleteDirectory)) util.RemoveTree(deleteDirectory) util.LogDebug("Deleted <{}>".format(deleteDirectory)) util.LogDebug("Build BSAs") bsaList = [] for bsa_name in BSAs: temp_data = BSAs[bsa_name] temp = os.path.dirname(temp_data) bsa_file_suffix = "" if bsa_name != "": bsa_file_suffix = " - " + bsa_name CleanPluginSpecificPaths(temp_data) bsa_filename = mod_name + bsa_file_suffix + ".bsa" target_bsa = os.path.join(target, bsa_filename) useArchive = has_archive if useArchive: bsa_list = archive_bsa.ArchiveBSA(temp, bsa_filename) for bsa_info in bsa_list: bsa_filename = bsa_info["FileName"] bsa_filepath = bsa_info["Folder"] bsa_fullpath = os.path.join(bsa_filepath, bsa_filename) newTargetBSA = os.path.join(target, bsa_filename) shutil.move(bsa_fullpath, newTargetBSA) bsaList.append(newTargetBSA) else: bsa_list = bsarch_bsa.BsarchBSA(temp, target_bsa) for bsa_info in bsa_list: bsa_filename = bsa_info["FileName"] bsa_filepath = bsa_info["Folder"] bsa_fullpath = os.path.join(bsa_filepath, bsa_filename) newTargetBSA = os.path.join(target, bsa_filename) shutil.move(bsa_fullpath, newTargetBSA) bsaList.append(newTargetBSA) util.RemoveTree(temp) util.LogDebug("PackMod Done") return bsaList
def BsarchBSA(target_folder, bsa_filename): script_path = util.GetScriptPath() utilities_path = util.GetUtilitiesPath() bsarch = os.path.join(utilities_path, "bsarch.exe") log_basename = "log.txt" log_filename = os.path.join(target_folder, log_basename) config_basename = "bsa_config.txt" config_filename = os.path.join(target_folder, config_basename) allFilesList = [] Flag_NamedDir = 1 Flag_NamedFiles = 2 Flag_Compressed = 4 Flag_RetainDir = 8 Flag_RetainName = 16 Flag_RetainFOff = 32 Flag_XBox360 = 64 Flag_StartupStr = 128 Flag_EmbedName = 256 Flag_XMem = 512 Flag_Bit = 1024 flags = bitflag.BitFlag() flags.SetFlag(Flag_NamedDir) flags.SetFlag(Flag_NamedFiles) util.LogInfo("Build File List") totalFileSizeTally = 0 target_data = os.path.join(target_folder, "Data") util.LogDebug("Walking the target directory " + target_data) bsaFolders = [] SizeLimitBSA = bsa_rules.BSASizeLimit totalFileCount = 0 for root, subdirs, files in os.walk(target_data): util.LogDebug('--\nroot = ' + root) if root != target_data: for filename in files: if filename != "desktop.ini" and filename != 'thumbs.db': file_path = os.path.join(root, filename) file_size = os.path.getsize(file_path) totalFileSizeTally += file_size totalFileCount += 1 currentFileIndex = None if totalFileSizeTally > SizeLimitBSA: currentFileIndex = 0 totalWrittenTally = 0 currentFileSizeTally = 0 buffer = '' bsaFileWritten = [] bsa_original_filename = bsa_filename temp_data = os.path.join(os.path.dirname(target_data), "Ready") def WriteBSA(): nonlocal currentFileIndex, bsa_filename util.LogDebug("Writing BSA") if currentFileIndex != None: bsa_filename = bsa_original_filename[:-4] + str( currentFileIndex) + ".bsa" currentFileIndex += 1 util.LogInfo("Run bsarch.exe") flags_value = flags.GetValue() flags_hexvalue = hex(flags_value) compress = "-z" if flags.IsSet(Flag_Compressed) else "" commandLine = [ bsarch, "pack", temp_data, bsa_filename, "-sse", compress, "-af:" + flags_hexvalue ] util.RunCommandLine(commandLine) bsaFileWritten.append({ "Folder": target_folder, "FileName": bsa_filename }) util.RemoveTree(temp_data) filesArchived = 0 for root, subdirs, files in os.walk(target_data): util.LogDebug('--\nroot = ' + root) if root == target_data: util.LogDebug("subdirs: " + str(subdirs)) lower_case_data_list = [x.lower() for x in subdirs] util.LogDebug("lcds: " + str(lower_case_data_list)) if "meshes" in lower_case_data_list: util.LogDebug("found meshes") flags.SetFlag(Flag_StartupStr) flags.SetFlag(Flag_Compressed) if "textures" in lower_case_data_list: util.LogDebug("found textures") if "interface" in lower_case_data_list: util.LogDebug("found interface") if "music" in lower_case_data_list: util.LogDebug("found music") flags.SetFlag(Flag_RetainName) if "sound" in lower_case_data_list: util.LogDebug("found sound") sound_list = os.listdir(os.path.join(target_data, "sound")) sound_list_lower = [x.lower() for x in sound_list] if "fx" in sound_list_lower: util.LogDebug("found sound//fx") flags.SetFlag(Flag_RetainName) if "voice" in sound_list_lower: util.LogDebug("found sound//voice") if "shadersfx" in lower_case_data_list: util.LogDebug("found shaders") if "seq" in lower_case_data_list: util.LogDebug("found seq") flags.SetFlag(Flag_RetainName) if "grass" in lower_case_data_list: util.LogDebug("found grass") flags.SetFlag(Flag_RetainName) if "scripts" in lower_case_data_list: util.LogDebug("found scripts") flags.SetFlag(Flag_RetainName) else: for filename in files: if filename != "desktop.ini" and filename != 'thumbs.db': file_path = os.path.join(root, filename) file_size = os.path.getsize(file_path) newTally = currentFileSizeTally + file_size util.LogDebug("Attempting to add " + file_path + " currentFileSizeTally is " + str(currentFileSizeTally) + " file_size is " + str(file_size)) if (newTally >= SizeLimitBSA): util.LogDebug( "New BSA would be too big, writing current BSA") sys.stdout.write("\n") WriteBSA() currentFileSizeTally = 0 relative_path = file_path.replace(target_folder, '') path_no_data = relative_path[6:] temp_path = os.path.join(temp_data, path_no_data) util.LogDebug("Moving <{}> to <{}>".format( file_path, temp_path)) paths_to_create = [] check_path = os.path.dirname(temp_path) util.LogDebug("Checking path {}".format(check_path)) while not os.path.isdir(check_path): util.LogDebug("{} does not exist.".format(check_path)) paths_to_create.insert(0, check_path) check_path = os.path.dirname(check_path) util.LogDebug("Checking path {}".format(check_path)) for path_to_create in paths_to_create: util.LogDebug("{} does not exist.".format(check_path)) os.mkdir(path_to_create) shutil.move(file_path, temp_path) currentFileSizeTally += file_size filesArchived += 1 sys.stdout.write("Prepared {}/{} \r".format( filesArchived, totalFileCount)) sys.stdout.flush() sys.stdout.write("\n") if currentFileSizeTally > 0: WriteBSA() util.LogInfo("Clean Up") os.chdir(script_path) return bsaFileWritten
def ArchiveBSA(target_folder, bsa_filename): script_path = util.GetScriptPath() utilities_path = util.GetUtilitiesPath() archive_original = os.path.join(utilities_path, "Archive.exe") util.LogDebug("Copy Archive.exe to target folder") archive = os.path.join(target_folder, "Archive.exe") shutil.copy2(archive_original, archive) log_basename = "log.txt" log_filename = os.path.join(target_folder, log_basename) config_basename = "bsa_config.txt" config_filename = os.path.join(target_folder, config_basename) allFilesList = [] checks = {} util.LogInfo("Build File List") totalFileSizeTally = 0 target_data = os.path.join(target_folder, "Data") util.LogDebug("Walking the target directory " + target_data) for root, subdirs, files in os.walk(target_data): util.LogDebug('--\nroot = ' + root) if root == target_data: util.LogDebug("subdirs: " + str(subdirs)) lower_case_data_list = [x.lower() for x in subdirs] util.LogDebug("lcds: " + str(lower_case_data_list)) if "meshes" in lower_case_data_list: util.LogDebug("found meshes") checks["Retain Strings During Startup"] = True checks["Meshes"] = True if "textures" in lower_case_data_list: util.LogDebug("found texttures") checks["Textures"] = True if "interface" in lower_case_data_list: util.LogDebug("found interface") checks["Menus"] = True if "music" in lower_case_data_list: util.LogDebug("found music") checks["Retain File Names"] = True checks["Sounds"] = True if "sound" in lower_case_data_list: util.LogDebug("found sound") sound_list = os.listdir(os.path.join(target_data, "sound")) sound_list_lower = [x.lower() for x in sound_list] if "fx" in sound_list_lower: util.LogDebug("found sound//fx") checks["Retain File Names"] = True checks["Sounds"] = True if "voice" in sound_list_lower: util.LogDebug("found sound//voice") checks["Voices"] = True if "shadersfx" in lower_case_data_list: util.LogDebug("found shaders") checks["Shaders"] = True if "seq" in lower_case_data_list: util.LogDebug("found seq") checks["Retain File Names"] = True checks["Misc"] = True if "grass" in lower_case_data_list: util.LogDebug("found grass") checks["Retain File Names"] = True checks["Misc"] = True if "scripts" in lower_case_data_list: util.LogDebug("found scripts") checks["Retain File Names"] = True checks["Misc"] = True else: for filename in files: if filename != "desktop.ini": file_path = os.path.join(root, filename) relative_path = file_path.replace(target_folder, '') util.LogDebug('\t- file %s (relative path: %s)' % (filename, relative_path)) path_no_data = relative_path[6:] file_size = os.path.getsize(file_path) totalFileSizeTally += file_size util.LogDebug("totalFileSizeTally is now: " + str(totalFileSizeTally)) allFilesList.append({ 'FileName': filename, 'FilePath': file_path, 'RelativePath': relative_path, 'PathNoData': path_no_data, 'FileSize': file_size }) SizeLimitBSA = bsa_rules.BSASizeLimit currentFileIndex = None currentFileSizeTally = 0 buffer = '' bsaFileWritten = [] bsa_original_filename = bsa_filename def WrtiteBSA(): nonlocal currentFileIndex, buffer, bsa_filename util.LogDebug("Writing BSA with filelist:<" + buffer + ">") filelist_basename = "bsa_filelist.txt" if currentFileIndex != None: filelist_basename = "bsa_filelist" + str(currentFileIndex) + ".txt" bsa_filename = bsa_original_filename[:-4] + str( currentFileIndex) + ".bsa" currentFileIndex += 1 filelist_filename = os.path.join(target_folder, filelist_basename) with open(filelist_filename, 'w') as filelist_file: filelist_file.write(buffer) buffer = '' util.LogInfo("Build Config") checksOrder = [ "Meshes", "Textures", "Menus", "Sounds", "Voices", "Shaders", "Trees", "Fonts", "Misc", "Compress Archive", "Retain Directory Names", "Retain File Names", "Retain File Name Offsets", "Retain Strings During Startup", "XBox 360 Archive", "Embed File Names" ] with open(config_filename, 'w') as config_file: config_file.write("Log: " + log_basename + "\n") config_file.write("New Archive\n") for check in checksOrder: if check in checks: config_file.write("Check: " + check + "\n") config_file.write("Set File Group Root: Data\\\n") config_file.write("Add File Group: " + filelist_basename + "\n") config_file.write("Save Archive: " + bsa_filename + "\n") util.LogInfo("Run Archive.exe") commandLine = ["Archive.exe", config_basename] os.chdir(target_folder) util.RunCommandLine(commandLine) with open(log_filename, "r") as log_file: for line in log_file: util.LogDebug(line) os.remove(log_filename) os.remove(filelist_filename) os.remove(config_filename) bsaFileWritten.append({ "Folder": target_folder, "FileName": bsa_filename }) if totalFileSizeTally > SizeLimitBSA: currentFileIndex = 0 totalWrittenTally = 0 for fileInfo in allFilesList: file_size = fileInfo['FileSize'] newTally = currentFileSizeTally + file_size totalWrittenTally = totalWrittenTally + file_size util.LogDebug("Adding " + fileInfo['FileName'] + " currentFileSizeTally is " + str(currentFileSizeTally) + " file_size is " + str(file_size) + " totalWrittenTally is " + str(totalWrittenTally)) buffer += fileInfo['PathNoData'] + "\n" currentFileSizeTally += file_size if (newTally >= SizeLimitBSA) or (totalWrittenTally >= totalFileSizeTally): WrtiteBSA() currentFileSizeTally = 0 if buffer != '': util.LogWarn("BUFFER NOT EMPTY!") util.LogInfo("Clean Up") util.RemoveFile(archive) os.chdir(script_path) return bsaFileWritten