Make it possible to port non-windows raw zips

mac
Miepee 3 years ago
parent a56294bd58
commit e77a66c0ba

@ -7,7 +7,7 @@ public class Core
/// </summary> /// </summary>
public const string Version = "1.4"; public const string Version = "1.4";
public enum LauncherModTargets public enum ModOS
{ {
Windows, Windows,
Linux, Linux,

@ -17,19 +17,23 @@ public static class HelperMethods
foreach(var file in dir.GetFiles()) foreach(var file in dir.GetFiles())
{ {
if (file.Name == file.Name.ToLower()) continue; if (file.Name == file.Name.ToLower()) continue;
file.MoveTo(file.DirectoryName + "/" + file.Name.ToLower()); // Windows is dumb, thus we need to move in two trips
file.MoveTo(file.DirectoryName + "/" + file.Name.ToLower() + "_");
file.MoveTo(file.FullName.Substring(0, file.FullName.Length-1));
} }
foreach(var subDir in dir.GetDirectories()) foreach(var subDir in dir.GetDirectories())
{ {
if (subDir.Name == subDir.Name.ToLower()) continue; if (subDir.Name == subDir.Name.ToLower()) continue;
// ReSharper disable once PossibleNullReferenceException - since this is a subdirectory, it always has a parent // ReSharper disable once PossibleNullReferenceException - since this is a subdirectory, it always has a parent
subDir.MoveTo(subDir.Parent.FullName + "/" + subDir.Name.ToLower()); // Windows is dumb, thus we need to move in two trips
subDir.MoveTo(subDir.Parent.FullName + "/" + subDir.Name.ToLower() + "_");
subDir.MoveTo(subDir.FullName.Substring(0, subDir.FullName.Length-1));
LowercaseFolder(subDir.FullName); LowercaseFolder(subDir.FullName);
} }
} }
public static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs) public static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs = true)
{ {
// Get the subdirectories for the specified directory. // Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName); DirectoryInfo dir = new DirectoryInfo(sourceDirName);

@ -8,14 +8,14 @@ public abstract class LauncherMods : IMods
/// Ports a Mod zip intended to be installed via the AM2RLauncher to other operating systems. /// Ports a Mod zip intended to be installed via the AM2RLauncher to other operating systems.
/// </summary> /// </summary>
/// <param name="inputLauncherZipPath">The path to the AM2RLauncher mod zip that should be ported.</param> /// <param name="inputLauncherZipPath">The path to the AM2RLauncher mod zip that should be ported.</param>
/// <param name="targetOS">The target operating system to port the </param> /// <param name="modTarget">The target operating system to port the </param>
/// <param name="includeAndroid">Whether Android should be inlcuded in the port.</param> /// <param name="includeAndroid">Whether Android should be inlcuded in the port.</param>
/// <param name="outputLauncherZipPath">The path where the ported AM2RLauncher mod zip should be saved.</param> /// <param name="outputLauncherZipPath">The path where the ported AM2RLauncher mod zip should be saved.</param>
/// <param name="am2r11ZipPath">The path to an AM2R 1.1 zip path. This is *required* if the input launcher zip is for Mac and will be ignored if the input zip is for anything else.</param> /// <param name="am2r11ZipPath">The path to an AM2R 1.1 zip path. This is *required* if the input launcher zip is for Mac and will be ignored if the input zip is for anything else.</param>
/// <param name="outputDelegate">The function that should handle in-progress output messages.</param> /// <param name="outputDelegate">The function that should handle in-progress output messages.</param>
/// <exception cref="NotSupportedException">WIP</exception> /// <exception cref="NotSupportedException">WIP</exception>
/// TODO: other exceptions /// TODO: other exceptions
public static void PortLauncherMod(string inputLauncherZipPath, Core.LauncherModTargets targetOS, bool includeAndroid, string outputLauncherZipPath, string am2r11ZipPath = null, OutputHandlerDelegate outputDelegate = null) public static void PortLauncherMod(string inputLauncherZipPath, Core.ModOS modTarget, bool includeAndroid, string outputLauncherZipPath, string am2r11ZipPath = null, OutputHandlerDelegate outputDelegate = null)
{ {
outputHandler = outputDelegate; outputHandler = outputDelegate;
string extractDirectory = tmp + "/" + Path.GetFileNameWithoutExtension(inputLauncherZipPath); string extractDirectory = tmp + "/" + Path.GetFileNameWithoutExtension(inputLauncherZipPath);
@ -34,7 +34,7 @@ public abstract class LauncherMods : IMods
string currentOS = profile.OperatingSystem; string currentOS = profile.OperatingSystem;
bool isAndroidIncluded = profile.SupportsAndroid; bool isAndroidIncluded = profile.SupportsAndroid;
if (targetOS.ToString() == profile.OperatingSystem) if (modTarget.ToString() == profile.OperatingSystem)
{ {
SendOutput("Target OS and Launcher OS are the same; exiting."); SendOutput("Target OS and Launcher OS are the same; exiting.");
return; return;
@ -53,9 +53,9 @@ public abstract class LauncherMods : IMods
if (profile.OperatingSystem == "Mac") if (profile.OperatingSystem == "Mac")
throw new NotSupportedException("Porting Mac mods is currently not supported!"); throw new NotSupportedException("Porting Mac mods is currently not supported!");
switch (targetOS) switch (modTarget)
{ {
case Core.LauncherModTargets.Windows: case Core.ModOS.Windows:
{ {
// We have a non-windows launcher mod, where data file patch is guaranteed to be game.xdelta // We have a non-windows launcher mod, where data file patch is guaranteed to be game.xdelta
File.Move(extractDirectory + "/game.xdelta", extractDirectory + "/data.xdelta"); File.Move(extractDirectory + "/game.xdelta", extractDirectory + "/data.xdelta");
@ -84,7 +84,7 @@ public abstract class LauncherMods : IMods
break; break;
} }
case Core.LauncherModTargets.Linux: case Core.ModOS.Linux:
{ {
if (currentOS == "Windows") if (currentOS == "Windows")
File.Move(extractDirectory + "/data.xdelta", extractDirectory + "/game.xdelta"); File.Move(extractDirectory + "/data.xdelta", extractDirectory + "/game.xdelta");
@ -115,13 +115,13 @@ public abstract class LauncherMods : IMods
break; break;
} }
case Core.LauncherModTargets.Mac: case Core.ModOS.Mac:
{ {
// TODO: Not sure if this is ever gonna be possible, since it requires one to shift up the patch. // TODO: Not sure if this is ever gonna be possible, since it requires one to shift up the patch.
// We'd need a 1.1 file to apply the patch to, run that with umtlib to shift it up, and then apply a new patch. // We'd need a 1.1 file to apply the patch to, run that with umtlib to shift it up, and then apply a new patch.
throw new NotSupportedException("Porting Mac mods is currently not supported!"); throw new NotSupportedException("Porting Mac mods is currently not supported!");
} }
default: throw new ArgumentOutOfRangeException(nameof(targetOS), targetOS, "Unknown target to port to!"); default: throw new ArgumentOutOfRangeException(nameof(modTarget), modTarget, "Unknown target to port to!");
} }
if (!includeAndroid) if (!includeAndroid)
@ -143,7 +143,7 @@ public abstract class LauncherMods : IMods
} }
//zip the result //zip the result
SendOutput($"Creating Launcher zip for {targetOS}..."); SendOutput($"Creating Launcher zip for {modTarget}...");
ZipFile.CreateFromDirectory(extractDirectory, outputLauncherZipPath); ZipFile.CreateFromDirectory(extractDirectory, outputLauncherZipPath);
// Clean up // Clean up

@ -1,14 +1,48 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO.Compression; using System.IO.Compression;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using static AM2RPortHelperLib.Core;
namespace AM2RPortHelperLib; namespace AM2RPortHelperLib;
public abstract class RawMods : IMods public abstract class RawMods : IMods
{ {
// TODO: Make these not windows -> OS, but Raw -> OS // For completionist sake, it should be possible to also port raw APKs to win/lin/mac
// But until some person actually shows up that needs this feature, I'm too lazy to implement it
private static ModOS GetModOSOfRawZip(string inputRawZipPath)
{
ZipArchive archive = ZipFile.OpenRead(inputRawZipPath);
if (archive.Entries.Any(f => f.FullName == "AM2R.exe") && archive.Entries.Any(f => f.FullName == "data.win"))
return ModOS.Linux;
if (archive.Entries.Any(f => f.FullName == "runner") && archive.Entries.Any(f => f.FullName == "assets/game.unx"))
return ModOS.Linux;
// I probably *should* use fullpaths for these, but the .app file could technically be different and don't want to thinka bout how to circumvent it
if (archive.Entries.Any(f => f.FullName.Contains("Contents/MacOS/Mac_Runner")) && archive.Entries.Any(f => f.FullName.Contains("Contents/Resources/game.ios")))
return ModOS.Mac;
throw new NotSupportedException("The OS of the mod zip is unknown and thus not supported");
}
// TODO: Port to Windows
public static void PortToWindows(string inputRawZipPath, string outputRawZipPath, OutputHandlerDelegate outputHandlerDelegate = null)
{
throw new NotImplementedException();
}
public static void PortToLinux(string inputRawZipPath, string outputRawZipPath, OutputHandlerDelegate outputDelegate = null) public static void PortToLinux(string inputRawZipPath, string outputRawZipPath, OutputHandlerDelegate outputDelegate = null)
{ {
ModOS currentOS = GetModOSOfRawZip(inputRawZipPath);
SendOutput("Zip Recognized as " + currentOS);
if (currentOS == ModOS.Linux)
{
SendOutput("Zip is already a raw Linux zip.");
return;
}
outputHandler = outputDelegate; outputHandler = outputDelegate;
string extractDirectory = tmp + "/" + Path.GetFileNameWithoutExtension(inputRawZipPath); string extractDirectory = tmp + "/" + Path.GetFileNameWithoutExtension(inputRawZipPath);
@ -17,26 +51,31 @@ public abstract class RawMods : IMods
// Check if temp folder exists, delete if yes, extract zip to there // Check if temp folder exists, delete if yes, extract zip to there
if (Directory.Exists(extractDirectory)) if (Directory.Exists(extractDirectory))
Directory.Delete(extractDirectory, true); Directory.Delete(extractDirectory, true);
SendOutput("Extracting Linux..."); SendOutput("Extracting for Raw Linux...");
ZipFile.ExtractToDirectory(inputRawZipPath, extractDirectory);
// Move everything into assets folder
SendOutput("Moving into Linux assets folder...");
Directory.CreateDirectory(assetsDir); Directory.CreateDirectory(assetsDir);
foreach (var file in new DirectoryInfo(extractDirectory).GetFiles()) ZipFile.ExtractToDirectory(inputRawZipPath, assetsDir);
file.MoveTo(assetsDir + "/" + file.Name);
foreach (var dir in new DirectoryInfo(extractDirectory).GetDirectories()) // Delete unnecessary files, rename data.win, move in the new runner
SendOutput("Delete unnecessary files for Linux and lowercase them...");
switch (currentOS)
{ {
if (dir.Name == "assets") continue; case ModOS.Windows:
dir.MoveTo(assetsDir + "/" + dir.Name); File.Delete(assetsDir + "/AM2R.exe");
File.Delete(assetsDir + "/D3DX9_43.dll");
File.Move(assetsDir + "/data.win", assetsDir + "/game.unx");
break;
case ModOS.Mac:
var appDir = new DirectoryInfo(assetsDir).GetDirectories().First(n => n.Name.EndsWith(".app"));
HelperMethods.DirectoryCopy(assetsDir + "/" + appDir.Name + "/Contents/Resources", assetsDir);
File.Delete(assetsDir + "/gamecontrollerdb.txt");
File.Delete(assetsDir + "/yoyorunner.config");
Directory.Delete(assetsDir + "/English.lproj", true);
Directory.Delete(assetsDir + "/" + appDir.Name, true);
File.Move(assetsDir + "/game.ios", assetsDir + "/game.unx");
break;
default: throw new NotSupportedException("The OS of the mod zip is unknown and thus not supported");
} }
// Delete unnecessary files, rename data.win, move in the new runner
SendOutput("Delete unnecessary files for Linux and lowercase them...");
File.Delete(assetsDir + "/AM2R.exe");
File.Delete(assetsDir + "/D3DX9_43.dll");
File.Move(assetsDir + "/data.win", assetsDir + "/game.unx");
File.Copy(utilDir + "/runner", extractDirectory + "/runner"); File.Copy(utilDir + "/runner", extractDirectory + "/runner");
if (!File.Exists(assetsDir + "/icon.png")) if (!File.Exists(assetsDir + "/icon.png"))
File.Copy(utilDir + "/icon.png", assetsDir + "/icon.png"); File.Copy(utilDir + "/icon.png", assetsDir + "/icon.png");
@ -47,7 +86,7 @@ public abstract class RawMods : IMods
HelperMethods.LowercaseFolder(assetsDir); HelperMethods.LowercaseFolder(assetsDir);
//zip the result //zip the result
SendOutput("Creating Linux zip..."); SendOutput("Creating raw Linux zip...");
ZipFile.CreateFromDirectory(extractDirectory, outputRawZipPath); ZipFile.CreateFromDirectory(extractDirectory, outputRawZipPath);
// Clean up // Clean up
@ -57,6 +96,9 @@ public abstract class RawMods : IMods
// TODO: try to figure out if its possible to extract the name from the data.win file and then just offer a "use custom save directory" option that decides whether to use it or not. // TODO: try to figure out if its possible to extract the name from the data.win file and then just offer a "use custom save directory" option that decides whether to use it or not.
public static void PortToAndroid(string inputRawZipPath, string outputRawApkPath, string modName = null, bool usesInternet = false, OutputHandlerDelegate outputDelegate = null) public static void PortToAndroid(string inputRawZipPath, string outputRawApkPath, string modName = null, bool usesInternet = false, OutputHandlerDelegate outputDelegate = null)
{ {
ModOS currentOS = GetModOSOfRawZip(inputRawZipPath);
SendOutput("Zip Recognized as " + currentOS);
outputHandler = outputDelegate; outputHandler = outputDelegate;
string extractDirectory = tmp + "/" + Path.GetFileNameWithoutExtension(inputRawZipPath); string extractDirectory = tmp + "/" + Path.GetFileNameWithoutExtension(inputRawZipPath);
string unzipDir = extractDirectory + "/zip"; string unzipDir = extractDirectory + "/zip";
@ -72,8 +114,6 @@ public abstract class RawMods : IMods
if (Directory.Exists(extractDirectory)) if (Directory.Exists(extractDirectory))
Directory.Delete(extractDirectory, true); Directory.Delete(extractDirectory, true);
Directory.CreateDirectory(extractDirectory); Directory.CreateDirectory(extractDirectory);
SendOutput("Extracting...");
ZipFile.ExtractToDirectory(inputRawZipPath, unzipDir);
// Run APKTOOL and decompress the file // Run APKTOOL and decompress the file
SendOutput("Decompiling apk..."); SendOutput("Decompiling apk...");
@ -87,20 +127,38 @@ public abstract class RawMods : IMods
p.Start(); p.Start();
p.WaitForExit(); p.WaitForExit();
// Move everything into assets folder SendOutput("Extracting for Raw Android...");
SendOutput("Move into Android assets folder..."); ZipFile.ExtractToDirectory(inputRawZipPath, apkAssetsDir);
foreach (var file in new DirectoryInfo(unzipDir).GetFiles())
file.MoveTo(apkAssetsDir + "/" + file.Name);
foreach (var dir in new DirectoryInfo(unzipDir).GetDirectories())
dir.MoveTo(apkAssetsDir + "/" + dir.Name);
// Delete unnecessary files, rename data.win, move in the new runner // Delete unnecessary files, rename data.win, move in the new runner
SendOutput("Delete unnecessary files for Android and lowercase them..."); SendOutput("Delete unnecessary files for Android and lowercase them...");
File.Delete(apkAssetsDir + "/AM2R.exe"); switch (currentOS)
File.Delete(apkAssetsDir + "/D3DX9_43.dll"); {
File.Move(apkAssetsDir + "/data.win", apkAssetsDir + "/game.droid"); case ModOS.Windows:
File.Copy(utilDir + "/splashAndroid.png", apkAssetsDir + "/splash.png", true); File.Delete(apkAssetsDir + "/AM2R.exe");
File.Delete(apkAssetsDir + "/D3DX9_43.dll");
File.Move(apkAssetsDir + "/data.win", apkAssetsDir + "/game.droid");
break;
case ModOS.Linux:
File.Delete(apkAssetsDir + "/runner");
HelperMethods.DirectoryCopy(apkAssetsDir + "/assets", apkAssetsDir);
Directory.Delete(apkAssetsDir + "/assets", true);
File.Move(apkAssetsDir + "/game.unx", apkAssetsDir + "/game.droid");
break;
case ModOS.Mac:
var appDir = new DirectoryInfo(apkAssetsDir).GetDirectories().First(n => n.Name.EndsWith(".app"));
HelperMethods.DirectoryCopy(apkAssetsDir + "/" + appDir.Name + "/Contents/Resources", apkAssetsDir);
File.Delete(apkAssetsDir + "/gamecontrollerdb.txt");
File.Delete(apkAssetsDir + "/yoyorunner.config");
Directory.Delete(apkAssetsDir + "/English.lproj", true);
Directory.Delete(apkAssetsDir + "/" + appDir.Name, true);
File.Move(apkAssetsDir + "/game.ios", apkAssetsDir + "/game.droid");
break;
default: throw new NotSupportedException("The OS of the mod zip is unknown and thus not supported");
}
if (!File.Exists(apkAssetsDir + "/splash.png"))
File.Copy(utilDir + "/splashAndroid.png", apkAssetsDir + "/splash.png", true);
//recursively lowercase everything in the assets folder //recursively lowercase everything in the assets folder
HelperMethods.LowercaseFolder(apkAssetsDir); HelperMethods.LowercaseFolder(apkAssetsDir);
@ -121,7 +179,7 @@ public abstract class RawMods : IMods
HelperMethods.SaveAndroidIcon(origPath, 144, resPath + "/drawable-xxhdpi-v4/icon.png"); HelperMethods.SaveAndroidIcon(origPath, 144, resPath + "/drawable-xxhdpi-v4/icon.png");
HelperMethods.SaveAndroidIcon(origPath, 192, resPath + "/drawable-xxxhdpi-v4/icon.png"); HelperMethods.SaveAndroidIcon(origPath, 192, resPath + "/drawable-xxxhdpi-v4/icon.png");
// Hermite probably the best // TODO: Hermite probably best as image upscaler, but we'll see
// On certain occasions, we need to modify the manifest file. // On certain occasions, we need to modify the manifest file.
if (modName != null || usesInternet) if (modName != null || usesInternet)
@ -205,6 +263,15 @@ public abstract class RawMods : IMods
//TODO: try to figure out if its possible to extract the name from the data.win file? They do have a displayname option last time I checked... //TODO: try to figure out if its possible to extract the name from the data.win file? They do have a displayname option last time I checked...
public static void PortToMac(string inputRawZipPath, string outputRawZipPath, string modName, OutputHandlerDelegate outputDelegate = null) public static void PortToMac(string inputRawZipPath, string outputRawZipPath, string modName, OutputHandlerDelegate outputDelegate = null)
{ {
ModOS currentOS = GetModOSOfRawZip(inputRawZipPath);
SendOutput("Zip Recognized as " + currentOS);
if (currentOS == ModOS.Mac)
{
SendOutput("Zip is already a raw Mac zip.");
return;
}
outputHandler = outputDelegate; outputHandler = outputDelegate;
string baseTempDirectory = tmp + "/" + Path.GetFileNameWithoutExtension(inputRawZipPath); string baseTempDirectory = tmp + "/" + Path.GetFileNameWithoutExtension(inputRawZipPath);
string extractDirectory = baseTempDirectory + "/extract"; string extractDirectory = baseTempDirectory + "/extract";
@ -228,13 +295,27 @@ public abstract class RawMods : IMods
// Delete unnecessary files, rename data.win, move in the new runner // Delete unnecessary files, rename data.win, move in the new runner
SendOutput("Delete unnecessary files for Mac and lowercase them..."); SendOutput("Delete unnecessary files for Mac and lowercase them...");
File.Delete(extractDirectory + "/AM2R.exe"); switch (currentOS)
File.Delete(extractDirectory + "/D3DX9_43.dll"); {
File.Move(extractDirectory + "/data.win", extractDirectory + "/game.ios"); case ModOS.Windows:
File.Delete(assetsDir + "/AM2R.exe");
File.Delete(assetsDir + "/D3DX9_43.dll");
File.Move(assetsDir + "/data.win", assetsDir + "/game.ios");
break;
case ModOS.Linux:
File.Delete(assetsDir + "/runner");
HelperMethods.DirectoryCopy(assetsDir + "/assets", assetsDir);
Directory.Delete(assetsDir + "/assets", true);
File.Move(assetsDir + "/game.unx", assetsDir + "/game.ios");
break;
default: throw new NotSupportedException("The OS of the mod zip is unknown and thus not supported");
}
if (!File.Exists(assetsDir + "/icon.png")) if (!File.Exists(assetsDir + "/icon.png"))
File.Copy(utilDir + "/icon.png", extractDirectory + "/icon.png"); File.Copy(utilDir + "/icon.png", extractDirectory + "/icon.png");
if (!File.Exists(assetsDir + "/splash.png")) if (!File.Exists(assetsDir + "/splash.png"))
File.Copy(utilDir + "/splash.png", extractDirectory + "/splash.png"); File.Copy(utilDir + "/splash.png", extractDirectory + "/splash.png");
// Delete fonts folder if it exists, because I need to convert bytecode version from game and newer version doesn't support font loading // Delete fonts folder if it exists, because I need to convert bytecode version from game and newer version doesn't support font loading
if (Directory.Exists(extractDirectory + "/lang/fonts")) if (Directory.Exists(extractDirectory + "/lang/fonts"))
Directory.Delete(extractDirectory + "/lang/fonts", true); Directory.Delete(extractDirectory + "/lang/fonts", true);
@ -243,7 +324,7 @@ public abstract class RawMods : IMods
HelperMethods.LowercaseFolder(extractDirectory); HelperMethods.LowercaseFolder(extractDirectory);
// Convert data.win to BC16 and get rid of not needed functions anymore // Convert data.win to BC16 and get rid of not needed functions anymore
SendOutput("Editing data.win to change data.win BC version and functions..."); SendOutput("Editing data.win to change ByteCode version and functions...");
string bin; string bin;
string args; string args;
@ -274,7 +355,7 @@ public abstract class RawMods : IMods
// Copy assets to the place where they belong to // Copy assets to the place where they belong to
SendOutput("Copy files over..."); SendOutput("Copy files over...");
HelperMethods.DirectoryCopy(extractDirectory, assetsDir, true); HelperMethods.DirectoryCopy(extractDirectory, assetsDir);
// Edit config and plist to change display name // Edit config and plist to change display name
SendOutput("Editing Runner references to AM2R..."); SendOutput("Editing Runner references to AM2R...");

Loading…
Cancel
Save