Skip to content

Commit

Permalink
Merge pull request #35 from fraganator/dev
Browse files Browse the repository at this point in the history
Finalise v2.15 release
  • Loading branch information
fraganator authored Jan 19, 2023
2 parents 4aa4144 + 566aa3f commit a04231f
Show file tree
Hide file tree
Showing 37 changed files with 1,558 additions and 328 deletions.
12 changes: 12 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
# Archive Cache Manager change history
## v2.15 (2023-01-19)
* New _extract-xiso_ option for Xbox iso conversion
* Full iso files (redump) automatically converted and cached in xiso format
* Supports both zipped and unzipped iso files
* Requires _extract-xiso.exe_ to be added to the `ArchiveCacheManager\Extractors` folder
* Reduced archive cache path lengths, avoiding path too long errors
* Small performance improvement when checking many file priorities
* Smart Extract uses Priority to select file from archive in case where individual ROM file not previously selected
* Fix incorrect path for auto generated M3Us when Launch Path is not Default
* Fix background thread issue when Batch Cache Games window closed while still calculating archive sizes
* Interface tweaks

## v2.14 (2022-05-05)
* New right-click menu option - "Batch Cache Games"
* Extract or copy multiple games to the cache, ready to play later
Expand Down
36 changes: 28 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@

A LaunchBox plugin which caches extracted ROM archives, letting you play games faster. Also allows launching individual files from archives, and loading preferred file types from an archive.

## New in v2.14
* New right-click menu option - "Batch Cache Games"
* Extract or copy multiple games to the cache, ready to play later
* Bulk cache games from NAS or external storage
* Cached games can be played even if network or external storage disconnected
## New in v2.15
* New _extract-xiso_ option for Xbox iso conversion
* Full iso files (redump) automatically converted and cached in xiso format
* Supports both zipped and unzipped iso files
* Requires _extract-xiso.exe_ to be added to the `ArchiveCacheManager\Extractors` folder
* Reduced archive cache path lengths, avoiding path too long errors
* Small performance improvement when checking many file priorities
* Smart Extract uses Priority to select file from archive in case where individual ROM file not previously selected
* Fix incorrect path for auto generated M3Us when Launch Path is not Default
* Fix background thread issue when Batch Cache Games window closed while still calculating archive sizes
* Interface tweaks

## Description
When a compressed ROM (zip, 7z, rar, gz, chd, rvz, etc.) is first extracted, it is stored in the archive cache. The next time it is played, the game is loaded directly from the cache, virtually eliminating wait time.
Expand All @@ -23,10 +29,11 @@ As the cache size approaches the maximum size, the oldest played games are delet
* Option to extract all discs in a multi-disc game, and generate M3U file.
* Option to copy ROM files to cache without extraction.
* Option to keep select ROMs cached and ready to play.
* Select and play individual ROM files from an archive.
* Select and play individual ROMs from a merged ROM archive.
* Batch cache feature for extracting or copying multiple games to cache at once.
* Filename and extension priorities per emulator and platform (cue, bin, iso, etc).
* Support for additional archive formats (chd, rvz, etc)
* Support for Xbox iso to xiso conversion
* Badge to indicate cached games

### Example Use Cases
Expand Down Expand Up @@ -102,7 +109,7 @@ The plugin includes a badge to indicate if a game is currently in the cache. It
Configuration can be accessed from the _Tools->Archive Cache Manager_ menu. An overview of each of the configuration screens and options is below.

## Cache Settings
This page shows a summary of the cache storage and currently cache items, and provides options for cache configuration.
This page shows a summary of the cache storage and currently cached items, and provides options for cache configuration.

![Achive Cache Manager config screen](images/cache-settings.png?raw=true "Achive Cache Manager cache settings")

Expand Down Expand Up @@ -234,17 +241,29 @@ Check this option to extract _rvz_, _wia_, and _gcz_ files to _iso_ files using

Default _`Disabled`_

#### extract-xiso
Check this option to extract and convert full _iso_ files to Xbox _iso_ files using extract-xiso. Supports both zipped and stand-alone _iso_ files. The executable _extract-xiso.exe_ must be copied to the folder `LaunchBox\Plugins\ArchiveCacheManager\Extractors`.

Default _`Disabled`_

## Smart Extract Settings
When enabled, the Smart Extract option will check if it's possible to extract only a single file from an archive. For merged archives containing multiple ROM versions and hacks, this avoids the need to extract a potentially large number of files to play a single game.

![Achive Cache Manager config screen](images/smart-extract-settings.png?raw=true "Achive Cache Manager Smart Extract settings")

Smart Extract will extract and launch a single file from an archive if the following conditions are met:

* An individual file has been selected through the "Select ROM in Archive..." right-click menu.
* All of the file types in an archive are the same, excluding files with Metadata Extensions.

_OR_

* All of the file types in an archive are Stand-alone ROMs, excluding files with Metadata Extensions.

The file to extract will be (in priority order):
1. The individual file selected through the "Select ROM in Archive..." right-click menu.
2. The first file which matches a configured Priority.
3. The first file in the archive.

#### Stand-alone ROM Extensions
A comma delimited list of file extensions which can run stand-alone (no dependencies on other files).

Expand Down Expand Up @@ -294,3 +313,4 @@ Octokit | latest | `Install-Package Octokit -ProjectName Plugin`
* INI File Parser library Copyright (c) 2008 Ricardo Amores Hernández. Licensed under the MIT license. https://github.com/rickyah/ini-parser
* Octokit library Copyright (c) 2017 GitHub Inc. Licensed under the MIT license. https://github.com/octokit/octokit.net
* FlexibleMessageBox Copyright (c) 2014 Jörg Reichert. Licensed under the CPOL. https://www.codeproject.com/Articles/601900/FlexibleMessageBox
* FastWildcard Copyright (c) 2020 Alex Angas. Licensed under the MIT license. https://github.com/fastwildcard/fastwildcard
6 changes: 3 additions & 3 deletions src/ArchiveCacheManager/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Archive Cache Manager")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand All @@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.14.0.0")]
[assembly: AssemblyFileVersion("2.14.0.0")]
[assembly: AssemblyVersion("2.15.0.0")]
[assembly: AssemblyFileVersion("2.15.0.0")]
121 changes: 40 additions & 81 deletions src/Core/CacheManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public static void AddArchiveToCache(int? disc = null)
var result = LaunchInfo.Extractor.Extract(LaunchInfo.GetArchivePath(disc), LaunchInfo.GetArchiveCachePath(disc), singleFile.ToSingleArray());
if (result)
{
LaunchInfo.UpdateSizeFromCache(disc);
LaunchInfo.SaveToCache(disc);
DiskUtils.SetDirectoryContentsReadOnly(LaunchInfo.GetArchiveCachePath(disc));
File.Delete(PathUtils.GetArchiveCacheExtractingFlagPath(LaunchInfo.GetArchiveCachePath(disc)));
Expand All @@ -124,7 +125,7 @@ public static void GenerateM3u()
foreach (var discInfo in LaunchInfo.Game.Discs)
{
// Delete any previously generated m3u file, so it doesn't get included in the subsequent archive listing
DiskUtils.DeleteFile(LaunchInfo.GetM3uName(discInfo.Disc));
DiskUtils.DeleteFile(LaunchInfo.GetM3uPath(LaunchInfo.GetArchiveCachePath(discInfo.Disc), discInfo.Disc));
filePaths.Add(discInfo.Disc, ListCacheArchive(LaunchInfo.GetArchiveCachePath(discInfo.Disc), discInfo.Disc).FirstOrDefault());
}

Expand All @@ -143,7 +144,7 @@ public static void GenerateM3u()
}
}

string m3uPath = LaunchInfo.GetM3uName(discInfo.Disc);
string m3uPath = LaunchInfo.GetM3uPath(LaunchInfo.GetArchiveCachePath(discInfo.Disc), discInfo.Disc);
try
{
File.WriteAllLines(m3uPath, multiDiscPaths);
Expand Down Expand Up @@ -218,7 +219,7 @@ public static void ListArchive()
if (LaunchInfo.Game.MultiDisc && LaunchInfo.MultiDiscSupport && LaunchInfo.Game.EmulatorPlatformM3u)
{
// This is a multi-disc game, and the emulator supports m3u files. Set the file list to the generated m3u file.
fileList.Add(LaunchInfo.GetM3uName(LaunchInfo.Game.SelectedDisc));
fileList.Add(LaunchInfo.GetM3uPath(LaunchInfo.GetArchiveCacheLaunchPath(LaunchInfo.Game.SelectedDisc), LaunchInfo.Game.SelectedDisc));
}
else
{
Expand Down Expand Up @@ -251,51 +252,27 @@ public static void ListArchive()
/// <returns>The file list for the archive in "Path = absolute\file\path.ext" format, with one entry per line.</returns>
public static List<string> ListFileArchive()
{
string stdout = string.Empty;
string selectedFilePath = string.Empty;
List<string> fileList = new List<string>();
List<string> filteredFileList = new List<string>();
string[] fileList = LaunchInfo.GetFileList();
string selectedFile = LaunchInfo.GetExtractSingleFile() ?? LaunchInfo.Game.SelectedFile;

if (!LaunchInfo.Game.SelectedFile.Equals(string.Empty))
if (!string.IsNullOrEmpty(selectedFile))
{
if (LaunchInfo.Extractor.List(LaunchInfo.GetArchivePath(), LaunchInfo.Game.SelectedFile.ToSingleArray()).Length > 0)
if (LaunchInfo.MatchFileList(fileList, selectedFile.ToSingleArray()).Length > 0)
{
fileList.Add(LaunchInfo.Game.SelectedFile);
Logger.Log(string.Format("Selected individual file from archive \"{0}\".", LaunchInfo.Game.SelectedFile));
return fileList;
filteredFileList.Add(selectedFile);
Logger.Log(string.Format("Selected individual file from archive \"{0}\".", selectedFile));
return filteredFileList;
}
}

List<string> prioritySections = new List<string>();
prioritySections.Add(Config.EmulatorPlatformKey(LaunchInfo.Game.Emulator, LaunchInfo.Game.Platform));
prioritySections.Add(Config.EmulatorPlatformKey("All", "All"));

foreach (var prioritySection in prioritySections)
filteredFileList = LaunchInfo.GetPriorityFileList(fileList);
if (filteredFileList.Count > 0)
{
try
{
string[] extensionPriority = Config.GetFilenamePriority(prioritySection).Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);

// Search the extensions in priority order
foreach (string extension in extensionPriority)
{
fileList = LaunchInfo.Extractor.List(LaunchInfo.GetArchivePath(), string.Format("{0}", extension.Trim()).ToSingleArray(), null, true).ToList();

if (fileList.Count > 0)
{
Logger.Log(string.Format("Using filename priority \"{0}\".", extension.Trim()));
return fileList;
}
}
}
catch (KeyNotFoundException)
{

}
return filteredFileList;
}

fileList = LaunchInfo.Extractor.List(LaunchInfo.GetArchivePath()).ToList();

return fileList;
return fileList.ToList();
}

/// <summary>
Expand All @@ -304,69 +281,51 @@ public static List<string> ListFileArchive()
/// <returns>The file list for the cached archive, with one entry per line. All paths are absolute.</returns>
public static List<string> ListCacheArchive(string archiveCachePath, int? disc = null)
{
List<string> fileList = new List<string>();
List<string> filteredFileList = new List<string>();
string[] managerFiles = PathUtils.GetManagerFiles(archiveCachePath);
string[] fileList;

try
{
fileList = Directory.GetFiles(archiveCachePath, "*", SearchOption.AllDirectories);
}
catch (Exception e)
{
Logger.Log($"Failed to list cache path {archiveCachePath}\r\n{e.ToString()}");
return filteredFileList;
}

if (!string.IsNullOrEmpty(LaunchInfo.Game.SelectedFile) && !(LaunchInfo.Game.MultiDisc && LaunchInfo.MultiDiscSupport))
{
if (Directory.GetFiles(archiveCachePath, LaunchInfo.Game.SelectedFile, SearchOption.AllDirectories).Length > 0)
if (LaunchInfo.MatchFileList(fileList, LaunchInfo.Game.SelectedFile.ToSingleArray()).Length > 0)
{
fileList.Add(Path.Combine(archiveCachePath, LaunchInfo.Game.SelectedFile));
string selectedFilePath = Path.Combine(archiveCachePath, LaunchInfo.Game.SelectedFile);
filteredFileList.Add(selectedFilePath);
Logger.Log(string.Format("Selected individual file from archive \"{0}\".", LaunchInfo.Game.SelectedFile));
return fileList;
return filteredFileList;
}
}

List<string> prioritySections = new List<string>();
prioritySections.Add(Config.EmulatorPlatformKey(LaunchInfo.Game.Emulator, LaunchInfo.Game.Platform));
prioritySections.Add(Config.EmulatorPlatformKey("All", "All"));

foreach (var prioritySection in prioritySections)
filteredFileList = LaunchInfo.GetPriorityFileList(fileList, managerFiles);
if (filteredFileList.Count > 0)
{
try
{
string[] extensionPriority = Utils.SplitExtensions(Config.GetFilenamePriority(prioritySection));

// Search the extensions in priority order
foreach (string extension in extensionPriority)
{
fileList = Directory.GetFiles(archiveCachePath, string.Format("*{0}", extension), SearchOption.AllDirectories).ToList();

foreach (string ex in managerFiles)
{
fileList.Remove(ex);
}

if (fileList.Count > 0)
{
Logger.Log(string.Format("Using filename priority \"{0}\".", extension));
return fileList;
}
}
}
catch (KeyNotFoundException)
{

}
return filteredFileList;
}

fileList = Directory.GetFiles(archiveCachePath, "*", SearchOption.AllDirectories).ToList();

filteredFileList = fileList.ToList();
foreach (string ex in managerFiles)
{
fileList.Remove(ex);
filteredFileList.Remove(ex);
}

if (fileList.Count > 0)
if (filteredFileList.Count > 0)
{
// If we're listing a disc from a multi-disc game, only return a single file
if (disc != null)
{
fileList.RemoveRange(1, fileList.Count() - 1);
filteredFileList.RemoveRange(1, filteredFileList.Count() - 1);
}
}

return fileList;
return filteredFileList;
}

/// <summary>
Expand Down
26 changes: 26 additions & 0 deletions src/Core/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public enum M3uName
private static readonly M3uName defaultM3uName = M3uName.GameId;
private static readonly bool defaultChdman = false;
private static readonly bool defaultDolphinTool = false;
private static readonly bool defaultExtractXiso = false;

public class EmulatorPlatformConfig
{
Expand All @@ -65,6 +66,7 @@ public class EmulatorPlatformConfig
public bool SmartExtract;
public bool Chdman;
public bool DolphinTool;
public bool ExtractXiso;

public EmulatorPlatformConfig()
{
Expand All @@ -76,6 +78,7 @@ public EmulatorPlatformConfig()
SmartExtract = defaultSmartExtract;
Chdman = defaultChdman;
DolphinTool = defaultDolphinTool;
ExtractXiso = defaultExtractXiso;
}
};

Expand Down Expand Up @@ -321,6 +324,23 @@ public static bool GetDolphinTool(string key)
return defaultDolphinTool;
}

public static bool GetExtractXiso(string key)
{
try
{
return mEmulatorPlatformConfig[key].ExtractXiso;
}
catch (KeyNotFoundException) { }

try
{
return mEmulatorPlatformConfig[defaultEmulatorPlatform].ExtractXiso;
}
catch (KeyNotFoundException) { }

return defaultExtractXiso;
}

public static string EmulatorPlatformKey(string emulator, string platform) => string.Format(@"{0} \ {1}", emulator, platform);

/// <summary>
Expand Down Expand Up @@ -478,6 +498,11 @@ public static void Load()
{
mEmulatorPlatformConfig[section.SectionName].DolphinTool = Convert.ToBoolean(section.Keys[nameof(EmulatorPlatformConfig.DolphinTool)]);
}

if (section.Keys.ContainsKey(nameof(EmulatorPlatformConfig.ExtractXiso)))
{
mEmulatorPlatformConfig[section.SectionName].ExtractXiso = Convert.ToBoolean(section.Keys[nameof(EmulatorPlatformConfig.ExtractXiso)]);
}
}
}

Expand Down Expand Up @@ -567,6 +592,7 @@ public static void Save()
iniData[priority.Key][nameof(EmulatorPlatformConfig.SmartExtract)] = priority.Value.SmartExtract.ToString();
iniData[priority.Key][nameof(EmulatorPlatformConfig.Chdman)] = priority.Value.Chdman.ToString();
iniData[priority.Key][nameof(EmulatorPlatformConfig.DolphinTool)] = priority.Value.DolphinTool.ToString();
iniData[priority.Key][nameof(EmulatorPlatformConfig.ExtractXiso)] = priority.Value.ExtractXiso.ToString();
}

try
Expand Down
3 changes: 3 additions & 0 deletions src/Core/Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,15 @@
<ItemGroup>
<Compile Include="Extractors\Chdman.cs" />
<Compile Include="Extractors\DolphinTool.cs" />
<Compile Include="Extractors\ExtractXiso.cs" />
<Compile Include="Extractors\Robocopy.cs" />
<Compile Include="Extractors\Extractor.cs" />
<Compile Include="FastWildcard.cs" />
<Compile Include="LaunchInfo.cs" />
<Compile Include="Config.cs" />
<Compile Include="GameIndex.cs" />
<Compile Include="GameInfo.cs" />
<Compile Include="MatchSettings.cs" />
<Compile Include="ProcessUtils.cs" />
<Compile Include="Logger.cs" />
<Compile Include="Utils.cs" />
Expand Down
Loading

0 comments on commit a04231f

Please sign in to comment.