Skip to content

Commit

Permalink
Port over classes from LEC, update to new TOC implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
henbagle committed Jun 10, 2021
1 parent 278cf1f commit d9f875b
Show file tree
Hide file tree
Showing 7 changed files with 784 additions and 152 deletions.
30 changes: 30 additions & 0 deletions AutoTOC/AutoTOC.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
Expand Down Expand Up @@ -50,10 +65,25 @@
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StreamIO.cs" />
<Compile Include="TOCBinFile.cs" />
<Compile Include="TOCCreator.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.8">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.8 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
186 changes: 39 additions & 147 deletions AutoTOC/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
Expand All @@ -12,36 +13,24 @@ namespace AutoTOC
{
class Program
{
enum MEGame
{
ME3,
LE1,
LE2,
LE3
}

static void Main(string[] args)
{
string gameDir;
MEGame game = MEGame.ME3;

if (args.Length == 1)
{
// Path is passed in, hopefully is game root directory or .exe
// Path is passed in, hopefully is game .exe
gameDir = args[0];
if (gameDir.EndsWith("\""))
if (gameDir.EndsWith(".exe"))
{
gameDir = gameDir.Remove(gameDir.Length - 1);
}
else if (gameDir.EndsWith(".exe"))
{
gameDir = GetGamepathFromExe(gameDir);
(gameDir, game) = GetGamepathFromExe(gameDir);
}
}
else if (args.Length == 2 && args[0] == "-r")
{
try {
MEGame game = (MEGame)Enum.Parse(typeof(MEGame), args[1], true);

game = (MEGame)Enum.Parse(typeof(MEGame), args[1], true);
gameDir = GetGamepathFromRegistry(game);
if(game != MEGame.ME3)
{
Expand Down Expand Up @@ -72,18 +61,18 @@ static void Main(string[] args)
}
else
{
Console.WriteLine("Requires one argument: the install dir or .exe of the game you're trying to TOC.");
Console.WriteLine("(eg. \"D:\\Origin Games\\Mass Effect Legendary Edition\\ME3\")");
Console.WriteLine("Requires one argument: .exe of the game you're trying to TOC.");
Console.WriteLine("(eg. \"D:\\Origin Games\\Mass Effect Legendary Edition\\ME3\\Binaries\\Win64\\MassEffect3.exe)");
Console.WriteLine("Detect game from registry with -r {game}. Options: ME3, LE1, LE2, LE3");
return;
}

Console.WriteLine($"Generating TOCs for {gameDir}");
GenerateTocFromGamedir(gameDir);
GenerateTocFromGamedir(gameDir, game);
Console.WriteLine("Done!");
}

static void GenerateTocFromGamedir(string gameDir)
static void GenerateTocFromGamedir(string gameDir, MEGame game)
{
string baseDir = Path.Combine(gameDir, @"BIOGame\");
string dlcDir = Path.Combine(baseDir, @"DLC\");
Expand All @@ -97,151 +86,54 @@ static void GenerateTocFromGamedir(string gameDir)
{
Console.WriteLine("DLC folder not detected, TOCing basegame only...");
}
Task.WhenAll(folders.Select(loc => TOCAsync(loc))).Wait();
Task.WhenAll(folders.Select(loc => TOCAsync(loc, game))).Wait();
}

static Task TOCAsync(string tocLoc)
static Task TOCAsync(string tocLoc, MEGame game)
{
return Task.Run(() => PrepareToCreateTOC(tocLoc));
return Task.Run(() => CreateTOC(tocLoc, game));
}

static void PrepareToCreateTOC(string consoletocFile)
static void CreateTOC(string tocLoc, MEGame game)
{
if (!consoletocFile.EndsWith("\\")) consoletocFile += "\\";
List<string> files = GetFiles(consoletocFile);

if (files.Count > 0)
{
string t = files[0];
int n = t.LastIndexOf("DLC_");
if (n > 0)
{
for (int i = 0; i < files.Count; i++)
files[i] = files[i].Substring(n);
string t2 = files[0];
n = t2.IndexOf("\\");
for (int i = 0; i < files.Count; i++)
files[i] = files[i].Substring(n + 1);
}
else
{
n = t.LastIndexOf("BIOGame");
if (n > 0)
{
for (int i = 0; i < files.Count; i++)
files[i] = files[i].Substring(n);
}
}
string pathbase;
string t3 = files[0];
int n2 = t3.LastIndexOf("BIOGame");
if (n2 >= 0)
{
pathbase = Path.GetDirectoryName(Path.GetDirectoryName(consoletocFile)) + "\\";
}
else
{
pathbase = consoletocFile;
}
CreateTOC(pathbase, consoletocFile + "PCConsoleTOC.bin", files.ToArray());
}
}

static void CreateTOC(string basepath, string tocFile, string[] files)
{
FileStream fs = new FileStream(tocFile, FileMode.Create, FileAccess.Write);
long selfSizePosition = -1;
fs.Write(BitConverter.GetBytes((int)0x3AB70C13), 0, 4);
fs.Write(BitConverter.GetBytes((int)0x0), 0, 4);
fs.Write(BitConverter.GetBytes((int)0x1), 0, 4);
fs.Write(BitConverter.GetBytes((int)0x8), 0, 4);
fs.Write(BitConverter.GetBytes((int)files.Length), 0, 4);
for (int i = 0; i < files.Length; i++)
{
string file = files[i];
if (i == files.Length - 1)//Entry Size
fs.Write(new byte[2], 0, 2);
else
fs.Write(BitConverter.GetBytes((ushort)(0x1D + file.Length)), 0, 2);
fs.Write(BitConverter.GetBytes((ushort)0), 0, 2);//Flags
if (Path.GetFileName(file).ToLower() != "pcconsoletoc.bin")
{
fs.Write(BitConverter.GetBytes((int) (new FileInfo(basepath + file).Length)), 0, 4);//Filesize
}
else
{
selfSizePosition = fs.Position;
fs.Write(BitConverter.GetBytes((int)0), 0, 4);//Filesize
}
fs.Write(BitConverter.GetBytes((int)0x0), 0, 4);//SHA1
fs.Write(BitConverter.GetBytes((int)0x0), 0, 4);
fs.Write(BitConverter.GetBytes((int)0x0), 0, 4);
fs.Write(BitConverter.GetBytes((int)0x0), 0, 4);
fs.Write(BitConverter.GetBytes((int)0x0), 0, 4);
foreach (char c in file)
fs.WriteByte((byte)c);
fs.WriteByte(0);
}
if (selfSizePosition >= 0)
{
// Write the size of our own TOC. This ensures TOC appears up to date when we try to update it later
// (important for DLC TOCs)
fs.Seek(selfSizePosition, SeekOrigin.Begin);
fs.Write(BitConverter.GetBytes((int)fs.Length), 0, 4);
}
fs.Close();
}

static List<string> GetFiles(string basefolder)
{
List<string> res = new List<string>();
string test = Path.GetFileName(Path.GetDirectoryName(basefolder));
string[] files = GetTocableFiles(basefolder);
res.AddRange(files);
DirectoryInfo folder = new DirectoryInfo(basefolder);
DirectoryInfo[] folders = folder.GetDirectories();
if (folders.Length != 0)
if (test != "BIOGame")
foreach (DirectoryInfo f in folders)
res.AddRange(GetFiles(basefolder + f.Name + "\\"));
else
foreach (DirectoryInfo f in folders)
if (f.Name == "CookedPCConsole" || f.Name == "Movies" || f.Name == "Splash")
res.AddRange(GetFiles(Path.Combine(basefolder, f.Name)));
else if (f.Name == "Content")
res.AddRange(GetFiles(Path.Combine(basefolder, f.Name, "Packages\\ISACT")));

return res;
}

static string[] Pattern = { "*.pcc", "*.afc", "*.bik", "*.bin", "*.tlk", "*.txt", "*.cnd", "*.upk", "*.tfc", "*.isb" };

static string[] GetTocableFiles(string path)
{
List<string> res = new List<string>();
foreach (string s in Pattern)
res.AddRange(Directory.GetFiles(path, s));
return res.ToArray();
var TOC = TOCCreator.CreateTOCForDirectory(tocLoc, game);
TOC.WriteToFile(Path.Combine(tocLoc, "PCConsoleTOC.bin"));
}

static string[] ValidExecutables = { "MassEffect1.exe", "MassEffect2.exe", "MassEffect3.exe" };

static string GetGamepathFromExe(string path)
static (string, MEGame) GetGamepathFromExe(string path)
{
if(path != null && ValidExecutables.Any((exe) => path.EndsWith(exe)))
if(File.Exists(path) && ValidExecutables.Any((exe) => path.EndsWith(exe)))
{
return path.Substring(0, path.LastIndexOf("Binaries", StringComparison.OrdinalIgnoreCase));
var dir = path.Substring(0, path.LastIndexOf("Binaries", StringComparison.OrdinalIgnoreCase));
if (path.EndsWith(ValidExecutables[0])) return (dir, MEGame.LE1);
if (path.EndsWith(ValidExecutables[1])) return (dir, MEGame.LE2);
if (path.EndsWith(ValidExecutables[2]))
{
var versionInfo = FileVersionInfo.GetVersionInfo(path);
if (versionInfo.FileVersion.StartsWith("1")) return (dir, MEGame.ME3);
else return (dir, MEGame.LE3);
}
// Should never get here
throw new ArgumentException("Executable file is not a supported Mass Effect game.");
}
else throw new ArgumentException("Executable file is not a supported Mass Effect game.");
throw new ArgumentException("Executable file is not a supported Mass Effect game.");
}

static string GetGamepathFromRegistry(MEGame game)
{
if(game != MEGame.ME3)
{
// Get LE path from registry
string hkey64 = @"HKEY_LOCAL_MACHINE\SOFTWARE\BioWare\Mass Effect Legendary Edition";
return (string)Registry.GetValue(hkey64, "Install Dir", null);
string hkey64 = @"HKEY_LOCAL_MACHINE\SOFTWARE\BioWare\Mass Effectâ„¢ Legendary Edition"; // Yes all that weird garbage in this name is required... but not for everyone
string test = (string)Registry.GetValue(hkey64, "Install Dir", null);
if (test != null)
{
return test;
}
hkey64 = @"HKEY_LOCAL_MACHINE\SOFTWARE\BioWare\Mass Effect Legendary Edition"; //For those without weird garbage
test = (string)Registry.GetValue(hkey64, "Install Dir", null);
return test;
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions AutoTOC/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.0.*")]
[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: AssemblyVersion("2.1.*")]
[assembly: AssemblyFileVersion("2.1.0.0")]
Loading

0 comments on commit d9f875b

Please sign in to comment.