@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO ;
using System.IO.Compression ;
using System.Linq ;
using System.Net.Mime ;
using System.Reflection ;
using System.Text.RegularExpressions ;
using Atomic.Language ;
@ -14,37 +13,41 @@ namespace Atomic;
public partial class ModPacker : Form
{
private const string version = Core . Version ;
private ModCreationInfo modInfo = new ModCreationInfo ( ) ;
// Lookup dictionaries, filled in Constructor
private Dictionary < ProfileOperatingSystems , Label > labelLookupTable = new Dictionary < ProfileOperatingSystems , Label > ( ) ;
private Dictionary < ProfileOperatingSystems , Button > buttonLookupTable = new Dictionary < ProfileOperatingSystems , Button > ( ) ;
private Dictionary < ProfileOperatingSystems , CheckBox > checkboxLookupTable = new Dictionary < ProfileOperatingSystems , CheckBox > ( ) ;
private Dictionary < ProfileOperatingSystems , FieldInfo > modPathLookupTable = new Dictionary < ProfileOperatingSystems , FieldInfo > ( ) ;
private Dictionary < ProfileOperatingSystems , PropertyInfo > isModLoadedLookupTable = new Dictionary < ProfileOperatingSystems , PropertyInfo > ( ) ;
// TODO: make sure all messageboxes have this form as parent
private const string Version = Core . Version ;
private readonly FileFilter apkFileFilter = new FileFilter ( Text . APKFileFilter , ".apk" ) ;
private readonly FileFilter zipFileFilter = new FileFilter ( Text . ZipArchivesFileFilter , ".zip" ) ;
private readonly FileFilter apkFileFilter = new FileFilter ( Text . APKFileFilter , ".apk" ) ;
private readonly Dictionary < ProfileOperatingSystems , Button > buttonLookupTable ;
private readonly Dictionary < ProfileOperatingSystems , CheckBox > checkboxLookupTable ;
private readonly Dictionary < ProfileOperatingSystems , PropertyInfo > isModLoadedLookupTable ;
// Lookup dictionaries, filled in Constructor
private readonly Dictionary < ProfileOperatingSystems , Label > labelLookupTable ;
private readonly ModCreationInfo modInfo = new ModCreationInfo ( ) ;
private readonly Dictionary < ProfileOperatingSystems , FieldInfo > modPathLookupTable ;
#region Eto events
private void CustomSaveCheckBoxChecked_Changed ( object sender , EventArgs e )
{
customSaveButton . Enabled = customSaveCheckBox . Checked . Value ;
customSaveTextBox . Enabled = customSaveCheckBox . Checked . Value ;
UpdateCreateButton ( ) ;
}
private void CustomSaveDataButton_Click ( object sender , EventArgs e )
{
// TODO: is this replace necessary?
string home = Environment . GetFolderPath ( Environment . SpecialFolder . UserProfile ) . Replace ( "\\" , "\\\\" ) ; // This is \ -> \\
bool wasSuccessful = false ;
var winSaveRegex = new Regex ( @"C:\\Users\\.*\\AppData\\Local\\" ) ; //this is to ensure, that the save directory is valid. so far, this is only important for windows
var linSaveRegex = new Regex ( $@"{home}/\.config/" ) ; // GMS hardcodes save into ~/.config on linux
var macSaveRegex = new Regex ( $@"{home}/Library/Application Support/" ) ;
// TODO: instead of creating 3 different regexes, only create one regex and fill it out depending on current OS. Just leech off of the os check a bit further down for that.
Regex winSaveRegex = new Regex ( @"C:\\Users\\.*\\AppData\\Local\\" ) ; //this is to ensure, that the save directory is valid.
Regex linSaveRegex = new Regex ( $@"{home}/\.config/" ) ; // GMS hardcodes save into ~/.config on linux
Regex macSaveRegex = new Regex ( $@"{home}/Library/Application Support/" ) ;
var dialog = new SelectFolderDialog ( ) ;
SelectFolderDialog dialog = new SelectFolderDialog ( ) ;
string initialDir = "" ;
if ( OS . IsWindows )
initialDir = Environment . GetEnvironmentVariable ( "LocalAppData" ) ;
@ -52,11 +55,11 @@ public partial class ModPacker : Form
initialDir = home + "/.config" ;
else if ( OS . IsMac )
initialDir = $@"{home}/Library/Application Support/" ;
dialog . Directory = initialDir ;
// TODO: clean this while loop a little
string saveFolderPath = null ;
while ( ! wasSuccessful )
{
if ( dialog . ShowDialog ( this ) = = DialogResult . Ok )
{
Match match = Match . Empty ;
@ -66,22 +69,24 @@ public partial class ModPacker : Form
match = linSaveRegex . Match ( dialog . Directory ) ;
else if ( OS . IsMac )
match = macSaveRegex . Match ( dialog . Directory ) ;
if ( match . Success = = false )
{
MessageBox . Show ( Text . InvalidSaveDirectory ) ;
}
else
{
wasSuccessful = true ;
saveFolderPath = dialog . Directory . Replace ( match . Value , "%localappdata%/" ) ;
// If we don't do this, custom save locations are going to fail on Linux
if ( OS . IsWindows )
if ( OS . IsWindows )
saveFolderPath = saveFolderPath . Replace ( "\\" , "/" ) ;
// On Mac, we need to adjust the path
if ( OS . IsMac )
saveFolderPath = saveFolderPath . Replace ( "com.yoyogames.am2r" , "AM2R" ) ;
// if someone has a custom save path inside of am2r and creates these w h ithin game maker, they will always be lower case
// if someone has a custom save path inside of am2r and creates these w ithin game maker, they will always be lower case
// we need to adjust them here to lowercase as well, as otherwise launcher gets problems on nix systems
const string vanillaPrefix = "%localappdata%/AM2R/" ;
if ( saveFolderPath . Contains ( vanillaPrefix ) )
@ -92,11 +97,11 @@ public partial class ModPacker : Form
{
wasSuccessful = true ;
}
}
customSaveTextBox . Text = saveFolderPath ;
UpdateCreateButton ( ) ;
}
private void YYCCheckBox_CheckedChanged ( object sender , EventArgs e )
{
// Don't do anything if it's been disabled
@ -108,11 +113,13 @@ public partial class ModPacker : Form
macButton . Enabled = false ;
modInfo . MacModPath = null ;
}
private void m acCheckBox_CheckedChanged( object sender , EventArgs e )
private void M acCheckBox_CheckedChanged( object sender , EventArgs e )
{
if ( ! yycCheckBox . Checked . Value )
{
OSCheckboxChanged ( ProfileOperatingSystems . Mac ) ;
}
else if ( macCheckBox . Checked . Value )
{
MessageBox . Show ( Text . YYCMacUnsupported , Text . Warning , MessageBoxButtons . OK , MessageBoxType . Warning ) ;
@ -130,6 +137,7 @@ public partial class ModPacker : Form
private void CreateButton_Click ( object sender , EventArgs e )
{
// TODO: use string.isnullorwhitespace
if ( nameTextBox . Text = = "" | | authorTextBox . Text = = "" | | versionTextBox . Text = = "" )
{
MessageBox . Show ( Text . FieldsMissing , Text . Error , MessageBoxButtons . OK , MessageBoxType . Error ) ;
@ -139,15 +147,15 @@ public partial class ModPacker : Form
// Trim the mod name textbox so that it has no leading/ending whitespace.
// Also check for invalid file names
nameTextBox . Text = nameTextBox . Text . Trim ( ) ;
if ( Path . GetInvalidFileNameChars ( ) . Any ( nameTextBox . Text . Contains ) )
{
MessageBox . Show ( Text . NameInvalidCharacters + "\n" + String . Join ( "\n" , Path . GetInvalidFileNameChars ( ) ) ) ;
MessageBox . Show ( Text . NameInvalidCharacters + "\n" + String . Join ( "\n" , Path . GetInvalidFileNameChars ( ) ) ) ;
return ;
}
// Verify 1.1
var result11 = Core . CheckIfZipIsAM2R11 ( modInfo . AM2R11Path ) ;
IsZipAM2R11ReturnCodes result11 = Core . CheckIfZipIsAM2R11 ( modInfo . AM2R11Path ) ;
if ( result11 ! = IsZipAM2R11ReturnCodes . Successful )
{
MessageBox . Show ( Text . AM2R11Invalid + " " + result11 ) ;
@ -162,16 +170,19 @@ public partial class ModPacker : Form
{
string output ;
using ( var saveFile = new SaveFileDialog { Title = Text . SaveOSModProfile . Replace ( "$1" , GetLocalizedStringOfOS ( os ) ) , Filters = { zipFileFilter } } )
using ( SaveFileDialog saveFile = new SaveFileDialog { Title = Text . SaveOSModProfile . Replace ( "$1" , GetLocalizedStringOfOS ( os ) ) , Filters = { zipFileFilter } } )
{
if ( saveFile . ShowDialog ( this ) = = DialogResult . Ok )
{
output = saveFile . FileName ;
}
else
{
createLabel . Text = Text . ModPackagingAborted ;
return false ;
}
}
// Some filepickers don't automatically set the file extension
if ( ! output . ToLower ( ) . EndsWith ( ".zip" ) )
output + = ".zip" ;
@ -186,27 +197,29 @@ public partial class ModPacker : Form
AbortPatch ( ) ;
return false ;
}
return true ;
}
bool CheckForProfileXML ( ZipArchive zip f ile)
bool CheckForProfileXML ( ZipArchive zip F ile)
{
if ( zip f ile. Entries . All ( f = > f . Name ! = "profile.xml" ) )
if ( zip F ile. Entries . All ( f = > f . Name ! = "profile.xml" ) )
return true ;
var result = MessageBox . Show ( Text . ProfileXMLFound , Text . Warning , MessageBoxButtons . YesNo , MessageBoxType . Warning ) ;
DialogResult result = MessageBox . Show ( Text . ProfileXMLFound , Text . Warning , MessageBoxButtons . YesNo , MessageBoxType . Warning ) ;
if ( result = = DialogResult . Yes )
return true ;
AbortPatch ( ) ;
return false ;
}
// TODO: look if its not possible to generalize these
if ( windowsCheckBox . Checked . Value )
{
var windowsZip = ZipFile . Open ( modInfo . WindowsModPath , ZipArchiveMode . Read ) ;
ZipArchive windowsZip = ZipFile . Open ( modInfo . WindowsModPath , ZipArchiveMode . Read ) ;
if ( windowsZip . Entries . All ( f = > f . FullName ! = "AM2R.exe" ) )
{
{
// TODO: make method for these $1 replacements
var result = MessageBox . Show ( Text . ModdedGameNotFound . Replace ( "$1" , Text . Windows ) , Text . Warning , MessageBoxButtons . YesNo , MessageBoxType . Warning ) ;
DialogResult result = MessageBox . Show ( Text . ModdedGameNotFound . Replace ( "$1" , Text . Windows ) , Text . Warning , MessageBoxButtons . YesNo , MessageBoxType . Warning ) ;
if ( result ! = DialogResult . Yes )
{
AbortPatch ( ) ;
@ -223,10 +236,10 @@ public partial class ModPacker : Form
if ( linuxCheckBox . Checked . Value )
{
var linuxZip = ZipFile . Open ( modInfo . LinuxModPath , ZipArchiveMode . Read ) ;
ZipArchive linuxZip = ZipFile . Open ( modInfo . LinuxModPath , ZipArchiveMode . Read ) ;
if ( linuxZip . Entries . All ( f = > f . FullName ! = "AM2R" ) & & linuxZip . Entries . All ( f = > f . FullName ! = "runner" ) )
{
var result = MessageBox . Show ( Text . ModdedGameNotFound . Replace ( "$1" , Text . Linux ) , Text . Warning , MessageBoxButtons . YesNo , MessageBoxType . Warning ) ;
{
DialogResult result = MessageBox . Show ( Text . ModdedGameNotFound . Replace ( "$1" , Text . Linux ) , Text . Warning , MessageBoxButtons . YesNo , MessageBoxType . Warning ) ;
if ( result ! = DialogResult . Yes )
{
AbortPatch ( ) ;
@ -240,12 +253,13 @@ public partial class ModPacker : Form
if ( ! PromptAndSaveOSMod ( ProfileOperatingSystems . Linux ) )
return ;
}
if ( macCheckBox . Checked . Value )
{
var macZip = ZipFile . Open ( modInfo . MacModPath , ZipArchiveMode . Read ) ;
ZipArchive macZip = ZipFile . Open ( modInfo . MacModPath , ZipArchiveMode . Read ) ;
if ( macZip . Entries . All ( f = > f . FullName ! = "AM2R.app/Contents/MacOS/Mac_Runner" ) )
{
var result = MessageBox . Show ( Text . ModdedGameNotFound . Replace ( "$1" , Text . Mac ) , Text . Warning , MessageBoxButtons . YesNo , MessageBoxType . Warning ) ;
DialogResult result = MessageBox . Show ( Text . ModdedGameNotFound . Replace ( "$1" , Text . Mac ) , Text . Warning , MessageBoxButtons . YesNo , MessageBoxType . Warning ) ;
if ( result ! = DialogResult . Yes )
AbortPatch ( ) ;
}
@ -256,6 +270,7 @@ public partial class ModPacker : Form
if ( ! PromptAndSaveOSMod ( ProfileOperatingSystems . Mac ) )
return ;
}
createLabel . Text = "Mod package(s) created!" ;
}
@ -276,9 +291,12 @@ public partial class ModPacker : Form
currentConfig . Fields . SupportsMac = macCheckBox . Checked . Value ;
currentConfig . Fields . SupportsAndroid = apkCheckBox . Checked . Value ;
}
Config . SaveConfig ( currentConfig ) ;
}
# endregion
private static string GetLocalizedStringOfOS ( ProfileOperatingSystems os )
{
return os switch
@ -290,10 +308,8 @@ public partial class ModPacker : Form
_ = > "Unknown"
} ;
}
# endregion
private void LoadProfileParameters ( ProfileOperatingSystems operatingSystem )
private void LoadProfileParameters ( ProfileOperatingSystems operatingSystem )
{
// TODO: give the control events where they assign the values directly?
modInfo . Profile . Name = nameTextBox . Text ;
@ -309,7 +325,9 @@ public partial class ModPacker : Form
else
modInfo . Profile . SaveLocation = "%localappdata%/AM2R" ;
if ( operatingSystem = = ProfileOperatingSystems . Linux )
{
modInfo . Profile . SaveLocation = modInfo . Profile . SaveLocation . Replace ( "%localappdata%" , "~/.config" ) ;
}
else if ( operatingSystem = = ProfileOperatingSystems . Mac )
{
if ( modInfo . Profile . SaveLocation . Contains ( "%localappdata%/AM2R" ) )
@ -328,24 +346,24 @@ public partial class ModPacker : Form
if ( Directory . Exists ( Path . GetTempPath ( ) + "/Atomic" ) )
Directory . Delete ( Path . GetTempPath ( ) + "/Atomic" , true ) ;
}
private void UpdateCreateButton ( )
{
if ( modInfo . IsAM2R11Loaded & & // AM2R_11 zip must be provided
( ! windowsCheckBox . Checked . Value | | modInfo . IsWindowsModLoaded ) & & // either Windows is disabled OR windows is provided
( ! apkCheckBox . Checked . Value | | modInfo . IsApkModLoaded ) & & // either APK is disabled OR APK is provided
( ! linuxCheckBox . Checked . Value | | modInfo . IsLinuxModLoaded ) & & // either Linux is disabled OR linux is provided
( ! macCheckBox . Checked . Value | | modInfo . IsMacModLoaded ) & & // either Mac is disabled OR mac is provided
if ( modInfo . IsAM2R11Loaded & & // AM2R_11 zip must be provided
( ! windowsCheckBox . Checked . Value | | modInfo . IsWindowsModLoaded ) & & // either Windows is disabled OR windows is provided
( ! apkCheckBox . Checked . Value | | modInfo . IsApkModLoaded ) & & // either APK is disabled OR APK is provided
( ! linuxCheckBox . Checked . Value | | modInfo . IsLinuxModLoaded ) & & // either Linux is disabled OR linux is provided
( ! macCheckBox . Checked . Value | | modInfo . IsMacModLoaded ) & & // either Mac is disabled OR mac is provided
( modInfo . IsWindowsModLoaded | | modInfo . IsLinuxModLoaded | | modInfo . IsMacModLoaded ) & & // one desktop OS has to be selected
( ! customSaveCheckBox . Checked . Value | | customSaveTextBox . Text ! = "" ) ) // either custom saves are disabled OR custom save is provided
( ! customSaveCheckBox . Checked . Value | | customSaveTextBox . Text ! = "" ) ) // either custom saves are disabled OR custom save is provided
createButton . Enabled = true ;
else
createButton . Enabled = false ;
}
private string SelectFile ( string title , FileFilter filter )
{
using var fileFinder = new OpenFileDialog { Filters = { filter } } ;
using OpenFileDialog fileFinder = new OpenFileDialog { Filters = { filter } } ;
fileFinder . Title = title ;
fileFinder . CurrentFilter = fileFinder . Filters . First ( ) ;
fileFinder . CheckFileExists = true ;
@ -370,9 +388,10 @@ public partial class ModPacker : Form
osLabel . Visible = false ;
osModPath . SetValue ( modInfo , null ) ;
}
UpdateCreateButton ( ) ;
}
private void OSButtonClicked ( ProfileOperatingSystems os )
{
string pickerMessage = Text . SelectModdedFile . Replace ( "$1" , GetLocalizedStringOfOS ( os ) ) . Replace ( "$2" , os = = ProfileOperatingSystems . Android ? Text . APK : Text . Zip ) ;