Make lib configurable by accepting custom icon/splash paths

mac
Miepee 3 years ago
parent 43c00b0e22
commit e1806a6c2f

@ -3,6 +3,7 @@ using System.CommandLine;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using AM2RPortHelperLib; using AM2RPortHelperLib;
using Microsoft.Win32.SafeHandles;
namespace AM2RPortHelper; namespace AM2RPortHelper;
@ -16,15 +17,22 @@ internal static class Program
private static int Main(string[] args) private static int Main(string[] args)
{ {
//LauncherMods.PortLauncherMod("/home/narr/Downloads/UnofficialMultitroidAPKTest1_6b.zip", Core.ModOS.Linux, true, "./foo.zip"); //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<bool>(new[] { "-i", "--interactive" }, "Use an interactive mode. This will ignore all other options."); var interactiveOption = new Option<bool>(new[] { "-i", "--interactive" }, "Use an interactive mode. This will ignore all other options.");
var fileOption = new Option<FileInfo>(new[] { "-f", "--file" }, "The file path to the raw mod that should be ported. *REQUIRED IN NON-INTERACTIVE*"); var fileOption = new Option<FileInfo>(new[] { "-f", "--file" }, "The file path to the raw mod that should be ported. *REQUIRED IN NON-INTERACTIVE*");
var linuxOption = new Option<FileInfo>(new[] { "-l", "--linux" }, "The output file path for the Linux mod. None given equals to no Linux port."); var linuxOption = new Option<FileInfo>(new[] { "-l", "--linux" }, "The output file path for the Linux mod. None given equals to no Linux port.");
var androidOption = new Option<FileInfo>(new[] { "-a", "--android" }, "The output file path for the Android mod. None given equals to no Android port."); var androidOption = new Option<FileInfo>(new[] { "-a", "--android" }, "The output file path for the Android mod. None given equals to no Android port.");
var macOption = new Option<FileInfo>(new[] { "-m", "--mac" }, "The output file path for the Mac mod. None given equals to no Mac port."); var macOption = new Option<FileInfo>(new[] { "-m", "--mac" }, "The output file path for the Mac mod. None given equals to no Mac port.");
var nameOption = new Option<bool>(new[] { "-s", "--customsave" }, "Whether the Android Port should use a custom save location. Has no effect on anything else."); var iconOption = new Option<FileInfo>(new[] { "-c", "--icon " }, "The file path to an icon PNG that should be used for the taskbar/dock/home screen. " +
var internetOption = new Option<bool>(new[] { "-w", "--internet" }, "Add internet usage permissions to the Android mod. Has no effect to other OS."); "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<FileInfo>(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<bool>(new[] { "-s", "--customsave" }, "Whether the Android Port should use a custom save location. Has no effect on other OS.");
var internetOption = new Option<bool>(new[] { "-w", "--internet" }, "Add internet usage permissions to the Android mod. Has no effect on other OS.");
var verboseOption = new Option<bool>(new[] { "-v", "--verbose" }, "Whether to show verbose output."); var verboseOption = new Option<bool>(new[] { "-v", "--verbose" }, "Whether to show verbose output.");
RootCommand rootCommand = new RootCommand("A utility to port Windows AM2R Mods to other operating systems.") RootCommand rootCommand = new RootCommand("A utility to port Windows AM2R Mods to other operating systems.")
@ -34,18 +42,33 @@ internal static class Program
linuxOption, linuxOption,
androidOption, androidOption,
macOption, macOption,
nameOption, iconOption,
splashOption,
customSaveOption,
internetOption internetOption
}; };
rootCommand.SetHandler(RootMethod, interactiveOption, fileOption, linuxOption, androidOption,
macOption, nameOption, internetOption, verboseOption);
rootCommand.SetHandler(context =>
return rootCommand.Invoke(args); {
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.InvokeAsync(args).Result;
} }
#pragma warning disable CS1998 #pragma warning disable CS1998
private static async Task<int> RootMethod(bool interactive, FileInfo inputModPath, FileInfo linuxPath, FileInfo androidPath, FileInfo macPath, private static async Task<int> 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 #pragma warning restore CS1998
{ {
if (interactive || beVerbose) if (interactive || beVerbose)
@ -63,18 +86,24 @@ internal static class Program
return 1; return 1;
} }
void LocalOutput(string output)
{
if (beVerbose)
Console.WriteLine(output);
}
if (linuxPath is not null) 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) if (androidPath is not null)
{ {
RawMods.PortToAndroid(inputModPath.FullName, androidPath.FullName, RawMods.PortToAndroid(inputModPath.FullName, androidPath.FullName,
useCustomSave, usesInternet, beVerbose ? OutputHandlerDelegate : null); iconPath?.FullName, splashPath?.FullName, useCustomSave, usesInternet, LocalOutput);
} }
if (macPath is not null) 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) if (beVerbose)
Console.WriteLine("Done."); Console.WriteLine("Done.");
@ -132,6 +161,16 @@ internal static class Program
} }
} while (invalidOS); } 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 // Port everything
string currentDir = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); string currentDir = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
string linuxPath = $"{currentDir}/{Path.GetFileNameWithoutExtension(modZipPath)}_LINUX.zip"; string linuxPath = $"{currentDir}/{Path.GetFileNameWithoutExtension(modZipPath)}_LINUX.zip";
@ -143,7 +182,7 @@ internal static class Program
if (File.Exists(linuxPath)) if (File.Exists(linuxPath))
File.Delete(linuxPath); File.Delete(linuxPath);
RawMods.PortToLinux(modZipPath, linuxPath, OutputHandlerDelegate); RawMods.PortToLinux(modZipPath, linuxPath, iconPath, splashPath, OutputHandlerDelegate);
} }
if (androidSelected) if (androidSelected)
@ -151,7 +190,6 @@ internal static class Program
if (File.Exists(androidPath)) if (File.Exists(androidPath))
File.Delete(androidPath); File.Delete(androidPath);
// TODO: ask for modname - temp until the other todo is fixed where it gets taht automatically
bool? internetSelected = null; bool? internetSelected = null;
do do
{ {
@ -182,14 +220,14 @@ internal static class Program
} }
while (customSaveSelected == null); 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 (macSelected)
{ {
if (File.Exists(macPath)) if (File.Exists(macPath))
File.Delete(macPath); File.Delete(macPath);
RawMods.PortToMac(modZipPath, macPath, OutputHandlerDelegate); RawMods.PortToMac(modZipPath, macPath, iconPath, splashPath, OutputHandlerDelegate);
} }
Console.WriteLine("Successfully finished!"); Console.WriteLine("Successfully finished!");

@ -11,7 +11,7 @@ namespace AM2RPortHelperGUI;
public partial class MainForm : Form 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() public MainForm()
{ {
Title = $"AM2RPortHelper - v{Core.Version}"; Title = $"AM2RPortHelper - v{Core.Version}";
@ -102,7 +102,7 @@ public partial class MainForm : Form
if (File.Exists(linuxPath)) if (File.Exists(linuxPath))
File.Delete(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) if (checkboxAndroid.Checked.Value)
{ {
@ -111,7 +111,7 @@ public partial class MainForm : Form
bool useCustomSave = checkboxUseCustomSave.Checked.Value; bool useCustomSave = checkboxUseCustomSave.Checked.Value;
bool useInternet = checkboxAndroidRequiresInternet.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) if (checkboxMac.Checked.Value)
{ {
@ -119,7 +119,7 @@ public partial class MainForm : Form
File.Delete(macPath); File.Delete(macPath);
string modName = checkboxUseCustomSave.Text; 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!"; labelProgress.Text = "Done!";

@ -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 // 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 // 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
/// <summary> /// <summary>
/// Determines for which OS a raw mod zip was made for. /// Determines for which OS a raw mod zip was made for.
/// </summary> /// </summary>
@ -42,15 +40,15 @@ public abstract class RawMods : ModsBase
/// ///
/// </summary> /// </summary>
/// <param name="nameOfResource"></param> /// <param name="nameOfResource"></param>
/// <param name="userIconPath"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="InvalidDataException"></exception> /// <exception cref="InvalidDataException"></exception>
private static string GetProperPathToBuiltinIcons(string nameOfResource) private static string GetProperPathToBuiltinIcons(string nameOfResource, string userIconPath)
{ {
string SubCaseFunction(string resource) string SubCaseFunction(string resource)
{ {
string origPath = ConfigDir + "/" + resource; if (File.Exists(userIconPath))
if (File.Exists(origPath)) return userIconPath;
return origPath;
var byteArray = resource switch var byteArray = resource switch
{ {
@ -61,8 +59,8 @@ public abstract class RawMods : ModsBase
}; };
Image.Load(byteArray).SaveAsPng(TempDir + "/" + resource); Image.Load(byteArray).SaveAsPng(TempDir + "/" + resource);
origPath = TempDir + "/" + resource; userIconPath = TempDir + "/" + resource;
return origPath; return userIconPath;
} }
switch (nameOfResource) switch (nameOfResource)
@ -88,9 +86,14 @@ public abstract class RawMods : ModsBase
/// </summary> /// </summary>
/// <param name="inputRawZipPath">The path to the raw mod zip.</param> /// <param name="inputRawZipPath">The path to the raw mod zip.</param>
/// <param name="outputRawZipPath">The path where the ported Linux mod zip should be saved to.</param> /// <param name="outputRawZipPath">The path where the ported Linux mod zip should be saved to.</param>
/// <param name="pathToIcon">The path to an icon PNG image that should be used on Linux for i.e. the taskbar.
/// If this is <see langword="null"/>, a default stock icon is used.</param>
/// <param name="pathToSplashScreen">The path to an splash PNG image that should be used on Linux when starting the game.
/// If this is <see langword="null"/>, a default stock splash screen is used.</param>
/// <param name="outputDelegate">A delegate to post output info to.</param> /// <param name="outputDelegate">A delegate to post output info to.</param>
/// <exception cref="NotSupportedException">The raw mod zip was made for an OS that can't be determined.</exception> /// <exception cref="NotSupportedException">The raw mod zip was made for an OS that can't be determined.</exception>
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); ModOS currentOS = GetModOSOfRawZip(inputRawZipPath);
SendOutput("Zip Recognized as " + currentOS); SendOutput("Zip Recognized as " + currentOS);
@ -135,8 +138,8 @@ public abstract class RawMods : ModsBase
} }
File.Copy(UtilDir + "/runner", extractDirectory + "/runner"); File.Copy(UtilDir + "/runner", extractDirectory + "/runner");
File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.icon)), assetsDir + "/icon.png"); File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.icon), pathToIcon), assetsDir + "/icon.png");
File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splash)), assetsDir + "/splash.png"); File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splash), pathToSplashScreen), assetsDir + "/splash.png");
//recursively lowercase everything in the assets folder //recursively lowercase everything in the assets folder
HelperMethods.LowercaseFolder(assetsDir); HelperMethods.LowercaseFolder(assetsDir);
@ -156,10 +159,15 @@ public abstract class RawMods : ModsBase
/// <param name="outputRawApkPath">The path where the ported Android mod apk should be saved to.</param> /// <param name="outputRawApkPath">The path where the ported Android mod apk should be saved to.</param>
/// <param name="useCustomSaveDirectory">Whether the mod should use a custom save location on Android.</param> /// <param name="useCustomSaveDirectory">Whether the mod should use a custom save location on Android.</param>
/// <param name="usesInternet">Whether the mod needs an Internet connection.</param> /// <param name="usesInternet">Whether the mod needs an Internet connection.</param>
/// <param name="pathToIcon">The path to an icon PNG image that should be used on Android for i.e. the home screen.
/// If this is <see langword="null"/>, a default stock icon is used.</param>
/// <param name="pathToSplashScreen">The path to an splash PNG image that should be used on Android when starting the game.
/// If this is <see langword="null"/>, a default stock splash screen is used.</param>
/// <param name="outputDelegate">A delegate to post output info to.</param> /// <param name="outputDelegate">A delegate to post output info to.</param>
/// <exception cref="NotSupportedException">The raw mod zip was made for an OS that can't be determined.</exception> /// <exception cref="NotSupportedException">The raw mod zip was made for an OS that can't be determined.</exception>
/// <exception cref="InvalidDataException"><paramref name="useCustomSaveDirectory"/> was given, but the display name of the mod is unsuitable as a name for the directory.</exception> /// <exception cref="InvalidDataException"><paramref name="useCustomSaveDirectory"/> was given, but the display name of the mod is unsuitable as a name for the directory.</exception>
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); ModOS currentOS = GetModOSOfRawZip(inputRawZipPath);
SendOutput("Zip Recognized as " + currentOS); 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. // 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 //recursively lowercase everything in the assets folder
HelperMethods.LowercaseFolder(apkAssetsDir); 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. // Edit the icons in the apk. Wrapper always has these, so we need to overwrite these too.
string resPath = apkDir + "/res"; string resPath = apkDir + "/res";
// Icon should only be read from if its there, otherwise default frog icon should be in the assembly // 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, 96, resPath + "/drawable/icon.png");
HelperMethods.SaveAndroidIcon(origPath, 72, resPath + "/drawable-hdpi-v4/icon.png"); HelperMethods.SaveAndroidIcon(origPath, 72, resPath + "/drawable-hdpi-v4/icon.png");
HelperMethods.SaveAndroidIcon(origPath, 36, resPath + "/drawable-ldpi-v4/icon.png"); HelperMethods.SaveAndroidIcon(origPath, 36, resPath + "/drawable-ldpi-v4/icon.png");
@ -342,9 +350,14 @@ public abstract class RawMods : ModsBase
/// </summary> /// </summary>
/// <param name="inputRawZipPath">The path to the raw mod zip.</param> /// <param name="inputRawZipPath">The path to the raw mod zip.</param>
/// <param name="outputRawZipPath">he path where the ported Mac mod zip should be saved to.</param> /// <param name="outputRawZipPath">he path where the ported Mac mod zip should be saved to.</param>
/// <param name="pathToIcon">The path to an icon PNG image that should be used on Mac for i.e. the dock.
/// If this is <see langword="null"/>, a default stock icon is used.</param>
/// <param name="pathToSplashScreen">The path to an splash PNG image that should be used on macOS when starting the game.
/// If this is <see langword="null"/>, a default stock splash screen is used.</param>
/// <param name="outputDelegate">A delegate to post output info to.</param> /// <param name="outputDelegate">A delegate to post output info to.</param>
/// <exception cref="NotSupportedException">The raw mod zip was made for an OS that can't be determined.</exception> /// <exception cref="NotSupportedException">The raw mod zip was made for an OS that can't be determined.</exception>
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); ModOS currentOS = GetModOSOfRawZip(inputRawZipPath);
SendOutput("Zip Recognized as " + currentOS); 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"); 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.icon), pathToIcon), extractDirectory + "/icon.png");
File.Copy(GetProperPathToBuiltinIcons(nameof(Resources.splash)), extractDirectory + "/splash.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 // 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"))

Loading…
Cancel
Save