From e1806a6c2f058e334c769b7a2aad1a440e18bdc6 Mon Sep 17 00:00:00 2001 From: Miepee Date: Wed, 18 Jan 2023 22:44:20 +0100 Subject: [PATCH] Make lib configurable by accepting custom icon/splash paths --- AM2RPortHelperCLI/Program.cs | 70 ++++++++++++++----- .../AM2RPortHelperGUI/MainForm.cs | 8 +-- AM2RPortHelperLib/RawMods.cs | 51 +++++++++----- 3 files changed, 90 insertions(+), 39 deletions(-) diff --git a/AM2RPortHelperCLI/Program.cs b/AM2RPortHelperCLI/Program.cs index 24bdcae..9fcc609 100644 --- a/AM2RPortHelperCLI/Program.cs +++ b/AM2RPortHelperCLI/Program.cs @@ -3,6 +3,7 @@ using System.CommandLine; using System.IO; using System.Threading.Tasks; using AM2RPortHelperLib; +using Microsoft.Win32.SafeHandles; namespace AM2RPortHelper; @@ -16,15 +17,22 @@ internal static class Program private static int Main(string[] args) { //LauncherMods.PortLauncherMod("/home/narr/Downloads/UnofficialMultitroidAPKTest1_6b.zip", Core.ModOS.Linux, true, "./foo.zip"); - //TODO: add options to icon file paths + //TODO: If icon paths are not set, these are currently not taken from the config dir! var interactiveOption = new Option(new[] { "-i", "--interactive" }, "Use an interactive mode. This will ignore all other options."); var fileOption = new Option(new[] { "-f", "--file" }, "The file path to the raw mod that should be ported. *REQUIRED IN NON-INTERACTIVE*"); var linuxOption = new Option(new[] { "-l", "--linux" }, "The output file path for the Linux mod. None given equals to no Linux port."); var androidOption = new Option(new[] { "-a", "--android" }, "The output file path for the Android mod. None given equals to no Android port."); var macOption = new Option(new[] { "-m", "--mac" }, "The output file path for the Mac mod. None given equals to no Mac port."); - var nameOption = new Option(new[] { "-s", "--customsave" }, "Whether the Android Port should use a custom save location. Has no effect on anything else."); - var internetOption = new Option(new[] { "-w", "--internet" }, "Add internet usage permissions to the Android mod. Has no effect to other OS."); + var iconOption = new Option(new[] { "-c", "--icon " }, "The file path to an icon PNG that should be used for the taskbar/dock/home screen. " + + "If this is not set, it will read \"icon.png\" from the config folder. If that file does not exist, a stock icon will be used."); + var splashOption = new Option(new[] { "-p", "--splash " }, "The file path to a splash PNG that should be used when booting the game. " + + "If this is not set, it will read \"splash.png\" (or \"splashAndroid.png\" for Android) from the config folder. " + + "If that file does not exist, a stock splash will be used."); + // TODO: double check whether its not possible to have the same splash screen for both desktop and mobile + var customSaveOption = new Option(new[] { "-s", "--customsave" }, "Whether the Android Port should use a custom save location. Has no effect on other OS."); + + var internetOption = new Option(new[] { "-w", "--internet" }, "Add internet usage permissions to the Android mod. Has no effect on other OS."); var verboseOption = new Option(new[] { "-v", "--verbose" }, "Whether to show verbose output."); RootCommand rootCommand = new RootCommand("A utility to port Windows AM2R Mods to other operating systems.") @@ -34,18 +42,33 @@ internal static class Program linuxOption, androidOption, macOption, - nameOption, + iconOption, + splashOption, + customSaveOption, internetOption }; - rootCommand.SetHandler(RootMethod, interactiveOption, fileOption, linuxOption, androidOption, - macOption, nameOption, internetOption, verboseOption); + rootCommand.SetHandler(context => + { + bool interactive = context.ParseResult.GetValueForOption(interactiveOption); + FileInfo inputModPath = context.ParseResult.GetValueForOption(fileOption); + FileInfo linuxPath = context.ParseResult.GetValueForOption(linuxOption); + FileInfo androidPath = context.ParseResult.GetValueForOption(androidOption); + FileInfo macPath = context.ParseResult.GetValueForOption(macOption); + FileInfo splashPath = context.ParseResult.GetValueForOption(splashOption); + bool useCustomSave = context.ParseResult.GetValueForOption(customSaveOption); + bool usesInternet = context.ParseResult.GetValueForOption(internetOption); + bool beVerbose = context.ParseResult.GetValueForOption(verboseOption); + FileInfo iconPath = context.ParseResult.GetValueForOption(iconOption); + + return RootMethod(interactive, inputModPath, linuxPath, androidPath, macPath, splashPath, iconPath, useCustomSave, usesInternet, beVerbose); + }); - return rootCommand.Invoke(args); + return rootCommand.InvokeAsync(args).Result; } #pragma warning disable CS1998 private static async Task RootMethod(bool interactive, FileInfo inputModPath, FileInfo linuxPath, FileInfo androidPath, FileInfo macPath, - bool useCustomSave, bool usesInternet, bool beVerbose) + FileInfo iconPath, FileInfo splashPath, bool useCustomSave, bool usesInternet, bool beVerbose) #pragma warning restore CS1998 { if (interactive || beVerbose) @@ -62,19 +85,25 @@ internal static class Program Console.Error.WriteLine("Input path does not exist, or does not point to a zip file!"); return 1; } + + void LocalOutput(string output) + { + if (beVerbose) + Console.WriteLine(output); + } if (linuxPath is not null) { - RawMods.PortToLinux(inputModPath.FullName, linuxPath.FullName, beVerbose ? OutputHandlerDelegate : null); + RawMods.PortToLinux(inputModPath.FullName, linuxPath.FullName, iconPath?.FullName, splashPath?.FullName, LocalOutput); } if (androidPath is not null) { RawMods.PortToAndroid(inputModPath.FullName, androidPath.FullName, - useCustomSave, usesInternet, beVerbose ? OutputHandlerDelegate : null); + iconPath?.FullName, splashPath?.FullName, useCustomSave, usesInternet, LocalOutput); } if (macPath is not null) { - RawMods.PortToMac(inputModPath.FullName, macPath.FullName, beVerbose ? OutputHandlerDelegate : null); + RawMods.PortToMac(inputModPath.FullName, macPath.FullName, iconPath?.FullName, splashPath?.FullName, LocalOutput); } if (beVerbose) Console.WriteLine("Done."); @@ -131,7 +160,17 @@ internal static class Program break; } } while (invalidOS); - + + // Ask for Icon + Console.WriteLine("Insert the path to your custom PNG icon. If an empty or nonexistant file is provided, the defaults will be used instead."); + string iconPath = Console.ReadLine(); + if (String.IsNullOrWhiteSpace(iconPath) || !File.Exists(iconPath)) iconPath = null; + + // Ask for Splash + Console.WriteLine("Insert the path to your custom PNG splash. If an empty or nonexistant file is provided, the defaults will be used instead."); + string splashPath = Console.ReadLine(); + if (String.IsNullOrWhiteSpace(splashPath) || !File.Exists(splashPath)) splashPath = null; + // Port everything string currentDir = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); string linuxPath = $"{currentDir}/{Path.GetFileNameWithoutExtension(modZipPath)}_LINUX.zip"; @@ -143,7 +182,7 @@ internal static class Program if (File.Exists(linuxPath)) File.Delete(linuxPath); - RawMods.PortToLinux(modZipPath, linuxPath, OutputHandlerDelegate); + RawMods.PortToLinux(modZipPath, linuxPath, iconPath, splashPath, OutputHandlerDelegate); } if (androidSelected) @@ -151,7 +190,6 @@ internal static class Program if (File.Exists(androidPath)) File.Delete(androidPath); - // TODO: ask for modname - temp until the other todo is fixed where it gets taht automatically bool? internetSelected = null; do { @@ -182,14 +220,14 @@ internal static class Program } while (customSaveSelected == null); - RawMods.PortToAndroid(modZipPath, androidPath, customSaveSelected.Value, customSaveSelected.Value, OutputHandlerDelegate); + RawMods.PortToAndroid(modZipPath, androidPath, iconPath, splashPath, customSaveSelected.Value, customSaveSelected.Value, OutputHandlerDelegate); } if (macSelected) { if (File.Exists(macPath)) File.Delete(macPath); - RawMods.PortToMac(modZipPath, macPath, OutputHandlerDelegate); + RawMods.PortToMac(modZipPath, macPath, iconPath, splashPath, OutputHandlerDelegate); } Console.WriteLine("Successfully finished!"); diff --git a/AM2RPortHelperGUI/AM2RPortHelperGUI/MainForm.cs b/AM2RPortHelperGUI/AM2RPortHelperGUI/MainForm.cs index d76ffb8..35d3deb 100644 --- a/AM2RPortHelperGUI/AM2RPortHelperGUI/MainForm.cs +++ b/AM2RPortHelperGUI/AM2RPortHelperGUI/MainForm.cs @@ -11,7 +11,7 @@ namespace AM2RPortHelperGUI; public partial class MainForm : Form { - // TODO: present icons so user can edit them + // TODO: present icons so user can edit them! Also read them from config dir if they exist public MainForm() { Title = $"AM2RPortHelper - v{Core.Version}"; @@ -102,7 +102,7 @@ public partial class MainForm : Form if (File.Exists(linuxPath)) File.Delete(linuxPath); - await Task.Run(() => RawMods.PortToLinux(modZipPath, linuxPath, OutputHandlerDelegate)); + await Task.Run(() => RawMods.PortToLinux(modZipPath, linuxPath, null, null, OutputHandlerDelegate)); } if (checkboxAndroid.Checked.Value) { @@ -111,7 +111,7 @@ public partial class MainForm : Form bool useCustomSave = checkboxUseCustomSave.Checked.Value; bool useInternet = checkboxAndroidRequiresInternet.Checked.Value; - await Task.Run(() => RawMods.PortToAndroid(modZipPath, androidPath, useCustomSave, useInternet, OutputHandlerDelegate)); + await Task.Run(() => RawMods.PortToAndroid(modZipPath, androidPath, null, null, useCustomSave, useInternet, OutputHandlerDelegate)); } if (checkboxMac.Checked.Value) { @@ -119,7 +119,7 @@ public partial class MainForm : Form File.Delete(macPath); string modName = checkboxUseCustomSave.Text; - await Task.Run(() => RawMods.PortToMac(modZipPath, macPath, OutputHandlerDelegate)); + await Task.Run(() => RawMods.PortToMac(modZipPath, macPath, null, null, OutputHandlerDelegate)); } labelProgress.Text = "Done!"; diff --git a/AM2RPortHelperLib/RawMods.cs b/AM2RPortHelperLib/RawMods.cs index 7977630..bf76ff1 100644 --- a/AM2RPortHelperLib/RawMods.cs +++ b/AM2RPortHelperLib/RawMods.cs @@ -14,8 +14,6 @@ public abstract class RawMods : ModsBase // 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 - // TODO: These methods should accept paths for icons/splashes - /// /// Determines for which OS a raw mod zip was made for. /// @@ -42,15 +40,15 @@ public abstract class RawMods : ModsBase /// /// /// + /// /// /// - private static string GetProperPathToBuiltinIcons(string nameOfResource) + private static string GetProperPathToBuiltinIcons(string nameOfResource, string userIconPath) { string SubCaseFunction(string resource) { - string origPath = ConfigDir + "/" + resource; - if (File.Exists(origPath)) - return origPath; + if (File.Exists(userIconPath)) + return userIconPath; var byteArray = resource switch { @@ -61,8 +59,8 @@ public abstract class RawMods : ModsBase }; Image.Load(byteArray).SaveAsPng(TempDir + "/" + resource); - origPath = TempDir + "/" + resource; - return origPath; + userIconPath = TempDir + "/" + resource; + return userIconPath; } switch (nameOfResource) @@ -82,15 +80,20 @@ public abstract class RawMods : ModsBase { } - + /// /// Ports a raw AM2R mod zip for Linux. /// /// The path to the raw mod zip. /// The path where the ported Linux mod zip should be saved to. + /// The path to an icon PNG image that should be used on Linux for i.e. the taskbar. + /// If this is , a default stock icon is used. + /// The path to an splash PNG image that should be used on Linux when starting the game. + /// If this is , a default stock splash screen is used. /// A delegate to post output info to. /// The raw mod zip was made for an OS that can't be determined. - public static void PortToLinux(string inputRawZipPath, string outputRawZipPath, OutputHandlerDelegate outputDelegate = null) + public static void PortToLinux(string inputRawZipPath, string outputRawZipPath, string pathToIcon = null, string pathToSplashScreen = null, + OutputHandlerDelegate outputDelegate = null) { ModOS currentOS = GetModOSOfRawZip(inputRawZipPath); SendOutput("Zip Recognized as " + currentOS); @@ -135,8 +138,8 @@ public abstract class RawMods : ModsBase } File.Copy(UtilDir + "/runner", extractDirectory + "/runner"); - File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.icon)), assetsDir + "/icon.png"); - File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splash)), assetsDir + "/splash.png"); + File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.icon), pathToIcon), assetsDir + "/icon.png"); + File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splash), pathToSplashScreen), assetsDir + "/splash.png"); //recursively lowercase everything in the assets folder HelperMethods.LowercaseFolder(assetsDir); @@ -148,7 +151,7 @@ public abstract class RawMods : ModsBase // Clean up Directory.Delete(TempDir, true); } - + /// /// Ports a raw AM2R mod zip for Android. /// @@ -156,10 +159,15 @@ public abstract class RawMods : ModsBase /// The path where the ported Android mod apk should be saved to. /// Whether the mod should use a custom save location on Android. /// Whether the mod needs an Internet connection. + /// The path to an icon PNG image that should be used on Android for i.e. the home screen. + /// If this is , a default stock icon is used. + /// The path to an splash PNG image that should be used on Android when starting the game. + /// If this is , a default stock splash screen is used. /// A delegate to post output info to. /// The raw mod zip was made for an OS that can't be determined. /// was given, but the display name of the mod is unsuitable as a name for the directory. - public static void PortToAndroid(string inputRawZipPath, string outputRawApkPath, bool useCustomSaveDirectory = false, bool usesInternet = false, OutputHandlerDelegate outputDelegate = null) + public static void PortToAndroid(string inputRawZipPath, string outputRawApkPath, string pathToIcon = null, string pathToSplashScreen = null, + bool useCustomSaveDirectory = false, bool usesInternet = false, OutputHandlerDelegate outputDelegate = null) { ModOS currentOS = GetModOSOfRawZip(inputRawZipPath); SendOutput("Zip Recognized as " + currentOS); @@ -222,7 +230,7 @@ public abstract class RawMods : ModsBase } // The wrapper always has a splash image, so we want to overwrite it. - File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splashAndroid)), apkAssetsDir + "/splash.png", true); + File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splashAndroid), pathToSplashScreen), apkAssetsDir + "/splash.png", true); //recursively lowercase everything in the assets folder HelperMethods.LowercaseFolder(apkAssetsDir); @@ -235,7 +243,7 @@ public abstract class RawMods : ModsBase // Edit the icons in the apk. Wrapper always has these, so we need to overwrite these too. string resPath = apkDir + "/res"; // Icon should only be read from if its there, otherwise default frog icon should be in the assembly - string origPath = GetProperPathToBuiltinIcons(nameof(Resources.icon)); + string origPath = GetProperPathToBuiltinIcons(nameof(Resources.icon), pathToIcon); HelperMethods.SaveAndroidIcon(origPath, 96, resPath + "/drawable/icon.png"); HelperMethods.SaveAndroidIcon(origPath, 72, resPath + "/drawable-hdpi-v4/icon.png"); HelperMethods.SaveAndroidIcon(origPath, 36, resPath + "/drawable-ldpi-v4/icon.png"); @@ -342,9 +350,14 @@ public abstract class RawMods : ModsBase /// /// The path to the raw mod zip. /// he path where the ported Mac mod zip should be saved to. + /// The path to an icon PNG image that should be used on Mac for i.e. the dock. + /// If this is , a default stock icon is used. + /// The path to an splash PNG image that should be used on macOS when starting the game. + /// If this is , a default stock splash screen is used. /// A delegate to post output info to. /// The raw mod zip was made for an OS that can't be determined. - public static void PortToMac(string inputRawZipPath, string outputRawZipPath, OutputHandlerDelegate outputDelegate = null) + public static void PortToMac(string inputRawZipPath, string outputRawZipPath, string pathToIcon = null, string pathToSplashScreen = null, + OutputHandlerDelegate outputDelegate = null) { ModOS currentOS = GetModOSOfRawZip(inputRawZipPath); SendOutput("Zip Recognized as " + currentOS); @@ -392,8 +405,8 @@ public abstract class RawMods : ModsBase default: throw new NotSupportedException("The OS of the mod zip is unknown and thus not supported"); } - File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.icon)), extractDirectory + "/icon.png"); - File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splash)), extractDirectory + "/splash.png"); + File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.icon), pathToIcon), extractDirectory + "/icon.png"); + File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splash), pathToSplashScreen), 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 if (Directory.Exists(extractDirectory + "/lang/fonts"))