/// <summary> /// Loads valid profile entries and reloads the necessary UI components. /// </summary> private void LoadProfilesAndAdjustLists() { // Reset loaded profiles profileDropDown.Items.Clear(); profileList.Clear(); profileIndex = null; // Load the profileList profileList = Profile.LoadProfiles(); // Add profile names to the profileDropDown foreach (ProfileXML profile in profileList) { // Archive version notes if (!profile.Installable) { if (profile.Name.Contains("Community Updates")) { profile.ProfileNotes = Text.ArchiveNotesCommunityUpdates; } else { profile.ProfileNotes = Text.ArchiveNotesMods + "\n\n" + profile.ProfileNotes; } } profileDropDown.Items.Add(profile.Name); } // Read the value from the config string profIndexString = CrossPlatformOperations.ReadFromConfig("ProfileIndex"); // Check if either no profile was found or the setting says that the last current profile didn't exist if (profileDropDown.Items.Count == 0) { profileIndex = null; } else { // We know that profiles exist at this point, so we're going to point it to 0 instead so the following code doesn't fail if (profIndexString == "null") { profIndexString = "0"; } // We parse from the settings, and check if profiles got deleted from the last time the launcher has been selected. if yes, we revert the last selection to 0; int intParseResult = Int32.Parse(profIndexString); profileIndex = intParseResult; if (profileIndex >= profileDropDown.Items.Count) { profileIndex = 0; } profileDropDown.SelectedIndex = profileIndex.Value; } // Update stored profiles in the Profile Settings tab modSettingsProfileDropDown.Items.Clear(); modSettingsProfileDropDown.Items.AddRange(profileDropDown.Items); modSettingsProfileDropDown.SelectedIndex = profileDropDown.Items.Count != 0 ? 0 : -1; // Refresh the author and version label on the main tab if (profileList.Count > 0) { profileAuthorLabel.Text = Text.Author + " " + profileList[profileDropDown.SelectedIndex].Author; profileVersionLabel.Text = Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; } log.Info("Reloading UI components after loading successful."); UpdateStateMachine(); }
public MainForm() { // Exit if we're already running the AM2RLauncher // Thanks, StackOverflow! https://stackoverflow.com/questions/184084/how-to-force-c-sharp-net-app-to-run-only-one-instance-in-windows if (!singleInstance) { // If on Windows, set the original app to the foreground window to prevent confusion if (OS.IsWindows) { Process current = Process.GetCurrentProcess(); Process process = Process.GetProcessesByName(current.ProcessName).First(p => p.Id == current.Id); if (process != null) { Core.Core.SetForegroundWindow(process.MainWindowHandle); } } Environment.Exit(0); } log.Info("Mutex check passed. Entering main thread."); log.Info("Current Launcher Version: " + VERSION); log.Info("Current Platform-ID is: " + Platform.ID); log.Info("Current OS is: " + OS.Name); // Set the Current Directory to the path the Launcher is located. Fixes some relative path issues. Environment.CurrentDirectory = CrossPlatformOperations.CURRENTPATH; log.Info("Set Launcher CWD to " + Environment.CurrentDirectory); // But log actual folder location nonetheless log.Info("Actual Launcher location: " + Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory)); // Set the language to what User wanted or choose local language string userLanguage = CrossPlatformOperations.ReadFromConfig("Language").ToLower(); if (!userLanguage.Equals("default")) { Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultures(CultureTypes.AllCultures).First(c => c.NativeName.ToLower().Contains(userLanguage)); } log.Info("Language has been set to: " + Thread.CurrentThread.CurrentUICulture.EnglishName); #region VARIABLE INITIALIZATION log.Info("Beginning UI initialization..."); Bitmap am2rIcon = new Bitmap(AM2RLauncher.Properties.Resources.AM2RIcon); // System tray indicator ButtonMenuItem showButton = new ButtonMenuItem { Text = Text.TrayButtonShow }; trayIndicator = new TrayIndicator { Menu = new ContextMenu(showButton), Title = "AM2RLauncher", Visible = false, Image = am2rIcon }; // Create menubar with defaults for mac if (OS.IsMac) { Menu = new MenuBar(); } // Create array from validCount profileList = new List <ProfileXML>(); //TODO: whenever profileDropDown gets rewritten to use a datastore, scrap this profileNames = new List <ListItem>(); foreach (var profile in profileList) { profileNames.Add(profile.Name); } // Custom splash texts string splash = Splash.GetSplash(); log.Info("Randomly chosen splash: " + splash); Font smallButtonFont = new Font(SystemFont.Default, 10); // Create mirror list - eventually this should be platform specific! // We do this as a List<Uri> so we can add more dynamically on user input... if necessary. mirrorList = CrossPlatformOperations.GenerateMirrorList(); // Create mirror list // We do this as a list<listItem> for 1) make this dynamic and 2) make ETO happy mirrorDescriptionList = new List <ListItem>(); // Add each entry dynamically instead of harcoding it to two. If we have neither a github or gitlab mirror, we use the mirror itself as text foreach (var mirror in mirrorList) { string text = mirror; if (text.Contains("github.com")) { text = Text.MirrorGithubText; } else if (text.Contains("gitlab.com")) { text = Text.MirrorGitlabText; } mirrorDescriptionList.Add(new ListItem() { Key = mirror, Text = text }); } #endregion Icon = new Icon(1f, am2rIcon); Title = "AM2RLauncher " + VERSION + ": " + splash; MinimumSize = new Size(500, 400); // TODO: for some reason, this sometimes doesn't work on Linux. Was reported at eto, stays here until its fixed ClientSize = new Size(Int32.Parse(CrossPlatformOperations.ReadFromConfig("Width")), Int32.Parse(CrossPlatformOperations.ReadFromConfig("Height"))); if (ClientSize.Width < 500) { ClientSize = new Size(500, ClientSize.Height); } if (ClientSize.Height < 400) { ClientSize = new Size(ClientSize.Width, 400); } log.Info("Start the launcher with Size: " + ClientSize.Width + ", " + ClientSize.Height); if (Boolean.Parse(CrossPlatformOperations.ReadFromConfig("IsMaximized"))) { Maximize(); } drawable = new Drawable { BackgroundColor = colBGNoAlpha }; // Drawable paint event drawable.Paint += DrawablePaintEvent; // Some systems don't call the paintEvent by default and only do so after actual resizing if (OS.IsMac) { LoadComplete += (sender, e) => { Size = new Size(Size.Width + 1, Size.Height); Size = new Size(Size.Width - 1, Size.Height); } } ; #region MAIN WINDOW // Center buttons/interface panel var centerInterface = new DynamicLayout(); // PLAY button playButton = new ColorButton { ToolTip = "", BackgroundColorHover = colBGHover, Height = 40, Width = 250, TextColor = colGreen, TextColorDisabled = colInactive, BackgroundColor = colBG, FrameColor = colGreen, FrameColorDisabled = colInactive }; UpdateStateMachine(); SetPlayButtonState(updateState); centerInterface.AddRow(playButton); // 2px spacer between playButton and apkButton (Windows only) if (OS.IsWindows) { centerInterface.AddRow(new Label { BackgroundColor = colBG, Height = 2 }); } // APK button apkButton = new ColorButton { Text = Text.CreateAPK, Height = 40, Width = 250, TextColor = colGreen, BackgroundColor = colBG, FrameColor = colGreen, BackgroundColorHover = colBGHover }; centerInterface.AddRow(apkButton); progressBar = new ProgressBar { Visible = false, Height = 15 }; // 4px spacer between APK button and progressBar (Windows only) if (OS.IsWindows) { centerInterface.AddRow(new Label { BackgroundColor = colBG, Height = 4 }); } centerInterface.AddRow(progressBar); progressLabel = new Label { BackgroundColor = colBG, Height = 15, Text = "", TextColor = colGreen, Visible = false }; centerInterface.AddRow(progressLabel); // 3px spacer between progressBar and profile label (Windows only) if (OS.IsWindows) { centerInterface.AddRow(new Label { BackgroundColor = colBG, Height = 3 }); } profileLabel = new Label { BackgroundColor = colBG, Height = 15, Text = Text.CurrentProfile, TextColor = colGreen }; centerInterface.AddRow(profileLabel); // Profiles dropdown // Yes, we know this looks horrific on GTK. Sorry. // We're not exactly in a position to rewrite the entire DropDown object as a Drawable child, but if you want to, you're more than welcome! // Mac gets a default BackgroundColor because it looks waaaaaaay better. profileDropDown = new DropDown { TextColor = colGreen, BackgroundColor = OS.IsWindows ? colBGNoAlpha : new Color() }; // In order to not have conflicting theming, we just always respect the users theme for dropdown on GTK. if (OS.IsLinux) { profileDropDown = new DropDown(); } profileDropDown.Items.AddRange(profileNames); // It's actually more comfortable if it's outside, because of GTK shenanigans centerInterface.AddRow(profileDropDown); // Profiles label profileAuthorLabel = new Label { BackgroundColor = colBG, Height = 16, Text = Text.Author + " ", TextColor = colGreen }; centerInterface.AddRow(profileAuthorLabel); profileVersionLabel = new Label { BackgroundColor = colBG, Height = 16, Text = Text.VersionLabel + " ", TextColor = colGreen }; centerInterface.AddRow(profileVersionLabel); saveWarningLabel = new Label { Visible = false, BackgroundColor = colBG, Width = 20, Height = 55, Text = Text.SaveLocationWarning, TextColor = colRed }; centerInterface.AddRow(saveWarningLabel); // Social buttons Bitmap redditIcon = new Bitmap(Resources.redditIcon48); var redditButton = new ImageButton { ToolTip = Text.RedditToolTip, Image = redditIcon }; redditButton.Click += (sender, e) => CrossPlatformOperations.OpenURL("https://www.reddit.com/r/AM2R"); Bitmap githubIcon = new Bitmap(Resources.githubIcon48); var githubButton = new ImageButton { ToolTip = Text.GithubToolTip, Image = githubIcon }; githubButton.Click += (sender, e) => CrossPlatformOperations.OpenURL("https://www.github.com/AM2R-Community-Developers"); Bitmap youtubeIcon = new Bitmap(Resources.youtubeIcon48); var youtubeButton = new ImageButton { ToolTip = Text.YoutubeToolTip, Image = youtubeIcon }; youtubeButton.Click += (sender, e) => CrossPlatformOperations.OpenURL("https://www.youtube.com/c/AM2RCommunityUpdates"); Bitmap discordIcon = new Bitmap(Resources.discordIcon48); var discordButton = new ImageButton { ToolTip = Text.DiscordToolTip, Image = discordIcon }; discordButton.Click += (sender, e) => CrossPlatformOperations.OpenURL("https://discord.gg/nk7UYPbd5u"); // Social button panel var socialPanel = new DynamicLayout(); socialPanel.BeginVertical(); socialPanel.AddRow(redditButton); socialPanel.AddRow(githubButton); socialPanel.AddRow(youtubeButton); socialPanel.AddRow(discordButton); socialPanel.EndVertical(); // Version number label Label versionLabel = new Label { Text = "v" + VERSION + (isThisRunningFromWine ? "-WINE" : ""), Width = 48, TextAlignment = TextAlignment.Right, TextColor = colGreen, Font = new Font(SystemFont.Default, 12) }; // Tie everything together var mainLayout = new DynamicLayout(); mainLayout.BeginHorizontal(); mainLayout.AddColumn(null, socialPanel); mainLayout.AddSpace(); mainLayout.AddColumn(null, centerInterface, null); mainLayout.AddSpace(); // Yes, I'm hardcoding this string. Linux users can english. mainLayout.AddColumn(versionLabel, isThisRunningFromWine ? new Label { Text = "Unsupported", TextColor = colRed, TextAlignment = TextAlignment.Right } : null); drawable.Content = mainLayout; #endregion #region TABS #region MAIN PAGE // [MAIN PAGE] TabPage mainPage = new TabPage { BackgroundColor = colBGNoAlpha, Text = Text.PlayTab, Content = drawable }; #endregion #region CHANGELOG PAGE // [CHANGELOG] Uri changelogUri = new Uri("https://am2r-community-developers.github.io/DistributionCenter/changelog.html"); WebView changelogWebView = new WebView { Url = changelogUri }; if (OS.IsUnix && !isInternetThere) { changelogWebView = new WebView(); } Label changelogNoConnectionLabel = new Label { Text = Text.NoInternetConnection, TextColor = colGreen }; TabPage changelogPage = new TabPage { BackgroundColor = colBGNoAlpha, Text = Text.ChangelogTab, Content = new TableLayout { Rows = { changelogWebView } } }; #endregion #region NEWS PAGE // [NEWS] Uri newsUri = new Uri("https://am2r-community-developers.github.io/DistributionCenter/news.html"); WebView newsWebView = new WebView { Url = newsUri }; //TODO: why exactly is this check necessary? if (OS.IsUnix && !isInternetThere) { newsWebView = new WebView(); } Label newsNoConnectionLabel = new Label { Text = Text.NoInternetConnection, TextColor = colGreen }; TabPage newsPage = new TabPage { Text = Text.NewsTab, BackgroundColor = colBGNoAlpha, Content = new TableLayout { Rows = { newsWebView } } }; //TODO: this is hack because on linux / mac the other way doesn't work. eto issue? if (OS.IsUnix && !isInternetThere) { changelogPage.Content = new TableLayout { Rows = { null, changelogNoConnectionLabel, null } }; newsPage.Content = new TableLayout { Rows = { null, newsNoConnectionLabel, null } }; } #endregion #region SETTINGS PAGE // [LAUNCHER SETTINGS] DynamicLayout settingsLayout = new DynamicLayout(); // LanguageLabel Label languageLabel = new Label { Text = Text.LanguageNotice, TextColor = colGreen }; // Language DropDown menu List <ListItem> languageList = new List <ListItem> { Text.SystemLanguage, "Deutsch", "English", "Español", "Français", "Italiano", "Português", "Русский", "日本語", "中文(简体)" }; languageDropDown = new DropDown { TextColor = colGreen, BackgroundColor = OS.IsWindows ? colBGNoAlpha : new Color() }; if (OS.IsLinux) { languageDropDown = new DropDown(); } languageDropDown.Items.AddRange(languageList); var tmpLanguage = CrossPlatformOperations.ReadFromConfig("Language"); languageDropDown.SelectedIndex = tmpLanguage == "Default" ? 0 : languageDropDown.Items.IndexOf(languageDropDown.Items.FirstOrDefault(x => x.Text.Equals(tmpLanguage))); if (languageDropDown.SelectedIndex == -1) { log.Info("User has tried to use " + tmpLanguage + " as a Language, but it was not found. Reverting to System Language"); languageDropDown.SelectedIndex = 0; } // autoUpdateAM2R checkbox autoUpdateAM2RCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateAM2R")), Text = Text.AutoUpdateAM2R, TextColor = colGreen }; // autoUpdateLauncher checkbox autoUpdateLauncherCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateLauncher")), Text = Text.AutoUpdateLauncher, TextColor = colGreen }; // HQ music, PC hqMusicPCCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("MusicHQPC")), Text = Text.HighQualityPC, TextColor = colGreen }; // HQ music, Android hqMusicAndroidCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("MusicHQAndroid")), Text = Text.HighQualityAndroid, TextColor = colGreen }; // Create game debug logs profileDebugLogCheck = new CheckBox { Checked = bool.Parse(CrossPlatformOperations.ReadFromConfig("ProfileDebugLog")), Text = Text.ProfileDebugCheckBox, TextColor = colGreen }; // Custom environment variables label Label customEnvVarLabel = new Label(); if (OS.IsLinux) { customEnvVarLabel = new Label { Text = Text.CustomEnvVarLabel, TextColor = colGreen }; } // Custom environment variables textbox customEnvVarTextBox = null; if (OS.IsLinux) { customEnvVarTextBox = new TextBox { Text = CrossPlatformOperations.ReadFromConfig("CustomEnvVar"), BackgroundColor = colBGNoAlpha, TextColor = colGreen }; } // Mirror list mirrorLabel = new Label { Text = Text.DownloadSource, TextColor = colGreen }; mirrorDropDown = new DropDown { TextColor = colGreen, BackgroundColor = OS.IsWindows ? colBGNoAlpha : new Color() }; if (OS.IsLinux) { mirrorDropDown = new DropDown(); } mirrorDropDown.Items.AddRange(mirrorDescriptionList); // As above, find a way to get this inside the dropDown definition mirrorIndex = (Int32.Parse(CrossPlatformOperations.ReadFromConfig("MirrorIndex")) < mirrorDropDown.Items.Count) ? Int32.Parse(CrossPlatformOperations.ReadFromConfig("MirrorIndex")) : 0; mirrorDropDown.SelectedIndex = mirrorIndex; currentMirror = mirrorList[mirrorDropDown.SelectedIndex]; // Custom mirror customMirrorCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("CustomMirrorEnabled")), Text = Text.CustomMirrorCheck, TextColor = colGreen }; customMirrorTextBox = new TextBox { Text = CrossPlatformOperations.ReadFromConfig("CustomMirrorText"), BackgroundColor = colBGNoAlpha, TextColor = colGreen }; EnableMirrorControlsAccordingly(); settingsLayout.BeginHorizontal(); settingsLayout.AddSpace(); settingsLayout.AddColumn(null, languageLabel, languageDropDown, autoUpdateAM2RCheck, autoUpdateLauncherCheck, hqMusicPCCheck, hqMusicAndroidCheck, profileDebugLogCheck, customEnvVarLabel, (Control)customEnvVarTextBox ?? new Label(), mirrorLabel, mirrorDropDown, customMirrorCheck, customMirrorTextBox, null); settingsLayout.AddSpace(); TabPage settingsPage = new TabPage { BackgroundColor = colBGNoAlpha, Content = settingsLayout, Text = Text.LauncherSettingsTab }; #endregion #region MODSETTINGS PAGE // [MOD SETTINGS] DynamicLayout modSettingsLayout = new DynamicLayout(); addModButton = new ColorButton { ToolTip = null, Text = Text.AddNewMod, Font = smallButtonFont, Height = 30, Width = 275, TextColor = colGreen, BackgroundColor = colBG, FrameColor = colGreen, BackgroundColorHover = colBGHover }; Label modSpacer = new Label { Height = 14 }; settingsProfileLabel = new Label { Text = Text.CurrentProfile, TextColor = colGreen, Width = 275 }; modSettingsProfileDropDown = new DropDown { TextColor = colGreen, BackgroundColor = OS.IsWindows ? colBGNoAlpha : new Color() }; // In order to not have conflicting theming, we just always respect the users theme for dropdown on GTK. if (OS.IsLinux) { modSettingsProfileDropDown = new DropDown(); } modSettingsProfileDropDown.Items.AddRange(profileNames); // It's actually more comfortable if it's outside, because of GTK shenanigans profileButton = new ColorButton { ToolTip = null, Text = Text.OpenProfileFolder, Font = smallButtonFont, Height = 30, Width = 275, TextColor = colGreen, BackgroundColor = colBG, FrameColor = colGreen, BackgroundColorHover = colBGHover }; saveButton = new ColorButton { ToolTip = null, Text = Text.OpenSaveFolder, Font = smallButtonFont, Height = 30, Width = 275, TextColor = colGreen, BackgroundColor = colBG, FrameColor = colGreen, BackgroundColorHover = colBGHover }; updateModButton = new ColorButton { ToolTip = null, Text = Text.UpdateModButtonText, Font = smallButtonFont, Height = 30, Width = 275, TextColor = colGreen, BackgroundColor = colBG, FrameColor = colGreen, BackgroundColorHover = colBGHover }; deleteModButton = new ColorButton { ToolTip = null, Text = Text.DeleteModButtonText, Font = smallButtonFont, Height = 30, Width = 275, TextColor = colGreen, BackgroundColor = colBG, FrameColor = colGreen, BackgroundColorHover = colBGHover }; profileNotesTextArea = new TextArea { ReadOnly = true, BackgroundColor = colBGNoAlpha, TextColor = colInactive, SpellCheck = false, Width = 275, Height = 150, Text = Text.ProfileNotes }; modSettingsLayout.BeginHorizontal(); modSettingsLayout.AddSpace(); modSettingsLayout.AddColumn(null, addModButton, modSpacer, settingsProfileLabel, modSettingsProfileDropDown, profileButton, saveButton, updateModButton, deleteModButton, profileNotesTextArea, null); modSettingsLayout.AddSpace(); TabPage modSettingsPage = new TabPage { BackgroundColor = colBGNoAlpha, Content = modSettingsLayout, Text = Text.ModSettingsTab }; #endregion #endregion Content = new TabControl { Pages = { mainPage, changelogPage, newsPage, settingsPage, modSettingsPage } }; #region EVENTS log.Info("All UI objects have been initialized, UI has been set up."); log.Info("Beginning event linkage..."); Closing += MainformClosing; showButton.Click += ShowButtonClick; profileDropDown.SelectedIndexChanged += ProfileDropDownSelectedIndexChanged; languageDropDown.SelectedIndexChanged += LanguageDropDownSelectedIndexChanged; autoUpdateAM2RCheck.CheckedChanged += AutoUpdateAM2RCheckChanged; autoUpdateLauncherCheck.CheckedChanged += AutoUpdateLauncherCheckChanged; hqMusicAndroidCheck.CheckedChanged += HqMusicAndroidCheckChanged; hqMusicPCCheck.CheckedChanged += HqMusicPCCheckChanged; customMirrorCheck.CheckedChanged += CustomMirrorCheckChanged; apkButton.Click += ApkButtonClickEvent; apkButton.LoadComplete += (sender, e) => UpdateApkState(); profileDropDown.LoadComplete += (sender, e) => UpdateProfileState(); playButton.Click += PlayButtonClickEvent; playButton.LoadComplete += PlayButtonLoadComplete; customMirrorTextBox.LostFocus += CustomMirrorTextBoxLostFocus; mirrorDropDown.SelectedIndexChanged += MirrorDropDownSelectedIndexChanged; modSettingsLayout.LoadComplete += ProfileLayoutLoadComplete; addModButton.Click += AddModButtonClicked; profileButton.Click += ProfileDataButtonClickEvent; saveButton.Click += SaveButtonClickEvent; modSettingsProfileDropDown.SelectedIndexChanged += ModSettingsProfileDropDownSelectedIndexChanged; deleteModButton.Click += DeleteModButtonClicked; updateModButton.Click += UpdateModButtonClicked; profileDebugLogCheck.CheckedChanged += ProfileDebugLogCheckedChanged; if (OS.IsLinux) { customEnvVarTextBox.LostFocus += CustomEnvVarTextBoxLostFocus; } //TODO: Retest if these now work on mac newsWebView.DocumentLoaded += (sender, e) => ChangeToEmptyPageOnNoInternet(newsPage, newsNoConnectionLabel); changelogWebView.DocumentLoaded += (sender, e) => ChangeToEmptyPageOnNoInternet(changelogPage, changelogNoConnectionLabel); log.Info("Events linked successfully."); #endregion }
/// <summary> /// Performs the entire AM2RLauncher update procedure. /// </summary> public static void Main() { log.Info("Running update check..."); // Update section // Clean old files that have been left if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak")) { log.Info("AM2RLauncher.bak detected. Removing file."); File.Delete(CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak"); } if (OS.IsWindows && File.Exists(oldConfigPath)) { log.Info(CrossPlatformOperations.LAUNCHERNAME + ".oldCfg detected. Removing file."); File.Delete(oldConfigPath); } if (OS.IsWindows && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/oldLib")) { log.Info("Old lib folder detected, removing folder."); Directory.Delete(CrossPlatformOperations.CURRENTPATH + "/oldLib", true); } // Clean up old update libs if (OS.IsWindows && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/lib")) { foreach (FileInfo file in new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/lib").GetFiles()) { if (file.Name.EndsWith(".bak")) { file.Delete(); } } // Do the same for each subdir foreach (DirectoryInfo dir in new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/lib").GetDirectories()) { foreach (FileInfo file in dir.GetFiles()) { if (file.Name.EndsWith(".bak")) { file.Delete(); } } } } // Check settings if autoUpdateLauncher is set to true bool autoUpdate = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateLauncher")); if (autoUpdate) { log.Info("AutoUpdate Launcher set to true!"); // This is supposed to fix the updater throwing an exception on windows 7 and earlier(?) // See this for information: https://stackoverflow.com/q/2859790 and https://stackoverflow.com/a/50977774 if (OS.IsWindows) { ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; } HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://github.com/AM2R-Community-Developers/AM2RLauncher/releases/latest"); HttpWebResponse response; try { response = (HttpWebResponse)request.GetResponse(); } catch (WebException) { log.Error("WebException caught! Displaying MessageBox."); MessageBox.Show(Language.Text.NoInternetConnection); return; } Uri realUri = response.ResponseUri; string onlineVersion = realUri.AbsoluteUri.Substring(realUri.AbsoluteUri.LastIndexOf('/') + 1); bool isCurrentVersionOutdated = false; string[] localVersionArray = VERSION.Split('.'); string[] onlineVersionArray = onlineVersion.Split('.'); for (int i = 0; i < localVersionArray.Length; i++) { int onlineNum = Int32.Parse(onlineVersionArray[i]); int localNum = Int32.Parse(localVersionArray[i]); if (onlineNum > localNum) { isCurrentVersionOutdated = true; break; } if (localNum > onlineNum) { break; } } log.Info((isCurrentVersionOutdated ? "Updating" : "Not Updating") + " from " + VERSION + " to " + onlineVersion); // No new update, exiting if (!isCurrentVersionOutdated) { return; } // For mac, we just show a message box that a new version is available, because I don't want to support it yet. // hardcoded string, since also temporarily until it gets supported one day. if (OS.IsMac) { MessageBox.Show("Your current version is outdated! The newest version is " + onlineVersion + "." + "Please recompile AM2RLauncher again or disable auto-updating"); return; } log.Info("Current version (" + VERSION + ") is outdated! Initiating update for version " + onlineVersion + "."); string tmpUpdatePath = CrossPlatformOperations.CURRENTPATH + "/tmpupdate/"; string zipPath = CrossPlatformOperations.CURRENTPATH + "/launcher.zip"; // Clean tmpupdate if (Directory.Exists(tmpUpdatePath)) { Directory.Delete(tmpUpdatePath, true); } if (!Directory.Exists(tmpUpdatePath)) { Directory.CreateDirectory(tmpUpdatePath); } try { using (var client = new WebClient()) { string platformSuffix = ""; if (OS.IsWindows) { platformSuffix = "_win"; } else if (OS.IsLinux) { platformSuffix = "_lin"; } log.Info("Downloading https://github.com/AM2R-Community-Developers/AM2RLauncher/releases/latest/download/AM2RLauncher_" + onlineVersion + platformSuffix + ".zip to " + zipPath + "."); client.DownloadFile("https://github.com/AM2R-Community-Developers/AM2RLauncher/releases/latest/download/AM2RLauncher_" + onlineVersion + platformSuffix + ".zip", zipPath); log.Info("File successfully downloaded."); } } catch (UnauthorizedAccessException) { log.Error("UnauthorizedAccessException caught! Displaying MessageBox."); MessageBox.Show(Language.Text.UnauthorizedAccessMessage); return; } ZipFile.ExtractToDirectory(zipPath, tmpUpdatePath); log.Info("Updates successfully extracted to " + tmpUpdatePath); File.Delete(zipPath); File.Move(updatePath + "/" + CrossPlatformOperations.LAUNCHERNAME, CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak"); if (OS.IsWindows) { File.Move(CrossPlatformOperations.LAUNCHERNAME + ".config", CrossPlatformOperations.LAUNCHERNAME + ".oldCfg"); } foreach (var file in new DirectoryInfo(tmpUpdatePath).GetFiles()) { log.Info("Moving " + file.FullName + " to " + CrossPlatformOperations.CURRENTPATH + "/" + file.Name); File.Copy(file.FullName, updatePath + "/" + file.Name, true); } // For windows, the actual application is in "AM2RLauncher.dll". Which means, we need to update the lib folder as well. if (OS.IsWindows && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/lib")) { // So, because Windows behavior is dumb... // Rename all files in lib to *.bak foreach (FileInfo file in new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/lib").GetFiles()) { file.CopyTo(file.Directory + "/" + file.Name + ".bak"); } // Do the same for each subdir foreach (DirectoryInfo dir in new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/lib").GetDirectories()) { foreach (FileInfo file in dir.GetFiles()) { file.CopyTo(file.Directory + "/" + file.Name + ".bak"); } } // Yes, the above calls could be recursive. No, I can't be bothered to make them as such. if (Directory.Exists(tmpUpdatePath + "lib")) { HelperMethods.DirectoryCopy(tmpUpdatePath + "lib", CrossPlatformOperations.CURRENTPATH + "/lib"); } } Directory.Delete(tmpUpdatePath, true); CrossPlatformOperations.CopyOldConfigToNewConfig(); log.Info("Files extracted. Preparing to restart executable..."); if (OS.IsLinux) { System.Diagnostics.Process.Start("chmod", "+x " + updatePath + "./AM2RLauncher.Gtk"); } System.Diagnostics.Process.Start(updatePath + "/" + CrossPlatformOperations.LAUNCHERNAME); Environment.Exit(0); } else { log.Info("AutoUpdate Launcher set to false. Exiting update check."); } }