diff --git a/.github/upgrades/dotnet-upgrade-plan.md b/.github/upgrades/dotnet-upgrade-plan.md new file mode 100644 index 0000000..93658cc --- /dev/null +++ b/.github/upgrades/dotnet-upgrade-plan.md @@ -0,0 +1,34 @@ +# .NET 8.0 Upgrade Plan + +## Execution Steps + +Execute steps below sequentially one by one in the order they are listed. + +1. Validate that a .NET 8.0 SDK required for this upgrade is installed on the machine and if not, help to get it installed. +2. Ensure that the SDK version specified in global.json files is compatible with the .NET 8.0 upgrade. +3. Upgrade UnityLauncherPro\UnityLauncherPro.csproj + +## Settings + +This section contains settings and data used by execution steps. + +### Excluded projects + +No projects are excluded from the upgrade. + +### Project upgrade details + +This section contains details about each project upgrade and modifications that need to be done in the project. + +#### UnityLauncherPro\UnityLauncherPro.csproj modifications + +Project format changes: + - Project file needs to be converted to SDK-style format + +Project properties changes: + - Target framework should be changed from `net48` to `net8.0-windows` + +Other changes: + - WPF project properties need to be configured for .NET 8.0 (UseWPF=true) + - Assembly information may need to be migrated from AssemblyInfo.cs to project properties + - Project references and file includes will be automatically inferred by SDK-style format \ No newline at end of file diff --git a/UnityLauncherPro/App.config b/UnityLauncherPro/App.config index 7df03f7..c21b1a0 100644 --- a/UnityLauncherPro/App.config +++ b/UnityLauncherPro/App.config @@ -1,141 +1,151 @@  + + + +
+ + + + - - -
- - - - - - - - - 600 - - - 650 - - - True - - - False - - - False - - - True - - - False - - - False - - - False - - - False - - - - - - - - - True - - - False - - - False - - - False - - - - - - False - - - theme.ini - - - False - - - False - - - False - - - dd/MM/yyyy HH:mm:ss - - - False - - - False - - - -s Unity ActivityManager PackageManager dalvikvm DEBUG -v color - - - 0 - - - - - - - - - False - - - False - - - - - - - - C:\Program Files\ - - - - - InitializeProject.cs - - - False - - - 50000 - - - - - - - - False - - - 40 - - - + + + + + 600 + + + 650 + + + True + + + False + + + False + + + True + + + False + + + False + + + False + + + False + + + + + + + + + True + + + False + + + False + + + False + + + + + + False + + + theme.ini + + + False + + + False + + + False + + + dd/MM/yyyy HH:mm:ss + + + False + + + False + + + -s Unity ActivityManager PackageManager dalvikvm DEBUG -v color + + + 0 + + + + + + + + + False + + + False + + + + + + + + + + C:\Program Files\ + + + + + + InitializeProject.cs + + + False + + + 50000 + + + + + + + + False + + + 40 + + + diff --git a/UnityLauncherPro/GetProjects.cs b/UnityLauncherPro/GetProjects.cs index bb3ae29..6cbaa52 100644 --- a/UnityLauncherPro/GetProjects.cs +++ b/UnityLauncherPro/GetProjects.cs @@ -17,6 +17,10 @@ public static class GetProjects public static List Scan(bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, StringCollection AllProjectPaths = null, bool searchGitbranchRecursively = false, bool showSRP = false) { + // TODO FIXME + Console.WriteLine("TODO fixme 8.0"); + return null; + List projectsFound = new List(); var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); diff --git a/UnityLauncherPro/GetUnityInstallations.cs b/UnityLauncherPro/GetUnityInstallations.cs index 7f4570d..a7090cd 100644 --- a/UnityLauncherPro/GetUnityInstallations.cs +++ b/UnityLauncherPro/GetUnityInstallations.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; namespace UnityLauncherPro @@ -14,8 +15,13 @@ public static class GetUnityInstallations // returns unity installations public static List Scan() { + // TODO fixme 8.0 + Console.WriteLine("TODO fixme 8.0"); + return null; + + // get list from settings - var rootFolders = Properties.Settings.Default.rootFolders; + StringCollection rootFolders = Properties.Settings.Default.rootFolders; // unityversion, exe_path List results = new List(); diff --git a/UnityLauncherPro/MainWindow.xaml.cs b/UnityLauncherPro/MainWindow.xaml.cs index e965383..7d18842 100644 --- a/UnityLauncherPro/MainWindow.xaml.cs +++ b/UnityLauncherPro/MainWindow.xaml.cs @@ -152,7 +152,9 @@ void Start() //Properties.Settings.Default.projectPaths = null; //Properties.Settings.Default.Save(); - projectsSource = GetProjects.Scan(getGitBranch: (bool)chkShowGitBranchColumn.IsChecked, getPlasticBranch: (bool)chkCheckPlasticBranch.IsChecked, getArguments: (bool)chkShowLauncherArgumentsColumn.IsChecked, showMissingFolders: (bool)chkShowMissingFolderProjects.IsChecked, showTargetPlatform: (bool)chkShowPlatform.IsChecked, AllProjectPaths: Properties.Settings.Default.projectPaths, searchGitbranchRecursively: (bool)chkGetGitBranchRecursively.IsChecked, showSRP: (bool)chkCheckSRP.IsChecked); + // TODO fixme 8.0 + Console.WriteLine("TODO fixme 8.0"); + //projectsSource = GetProjects.Scan(getGitBranch: (bool)chkShowGitBranchColumn.IsChecked, getPlasticBranch: (bool)chkCheckPlasticBranch.IsChecked, getArguments: (bool)chkShowLauncherArgumentsColumn.IsChecked, showMissingFolders: (bool)chkShowMissingFolderProjects.IsChecked, showTargetPlatform: (bool)chkShowPlatform.IsChecked, AllProjectPaths: Properties.Settings.Default.projectPaths, searchGitbranchRecursively: (bool)chkGetGitBranchRecursively.IsChecked, showSRP: (bool)chkCheckSRP.IsChecked); //Console.WriteLine("projectsSource.Count: " + projectsSource.Count); @@ -531,15 +533,46 @@ private bool BuildReportFilter(object item) return (reportItem.Path.IndexOf(_filterString, 0, StringComparison.CurrentCultureIgnoreCase) != -1); } + void UpgradeOnceIfNeeded() + { + if (!Settings.Default.__UpgradedOnce) + { + try { Settings.Default.Upgrade(); } catch { /* ignore */ } + Settings.Default.__UpgradedOnce = true; + Settings.Default.Save(); + } + } + + void RepairProblematicSettings() + { + // Ensure XML-serializable defaults for complex types + try { var _ = Settings.Default.rootFolders; } + catch { Settings.Default.rootFolders = new System.Collections.Specialized.StringCollection(); } + + try { var _ = Settings.Default.gridColumnWidths; } + catch { Settings.Default.gridColumnWidths = Array.Empty(); } + + try { var _ = Settings.Default.gridColumnWidthsBuildReport; } + catch { Settings.Default.gridColumnWidthsBuildReport = Array.Empty(); } + + try { var _ = Settings.Default.recentColumnsOrder; } + catch { Settings.Default.recentColumnsOrder = Array.Empty(); } + + Settings.Default.Save(); + } + + void LoadSettings() { - // debug, print filename - //Console.WriteLine(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath); + UpgradeOnceIfNeeded(); + RepairProblematicSettings(); + Settings.Default.Reload(); - // catch corrupted config file try { + // For .NET 8: Reload is still needed to get latest values from user.config Settings.Default.Reload(); + // form size this.Width = Settings.Default.windowWidth; this.Height = Settings.Default.windowHeight; @@ -553,7 +586,7 @@ void LoadSettings() chkQuitAfterOpen.IsChecked = Settings.Default.closeAfterProject; chkShowLauncherArgumentsColumn.IsChecked = Settings.Default.showArgumentsColumn; chkShowGitBranchColumn.IsChecked = Settings.Default.showGitBranchColumn; - chkGetGitBranchRecursively.IsChecked = Settings.Default.searchGitFolderRecursivly; // FIXME typo + chkGetGitBranchRecursively.IsChecked = Settings.Default.searchGitFolderRecursivly; chkCheckPlasticBranch.IsChecked = Settings.Default.checkPlasticBranch; chkShowMissingFolderProjects.IsChecked = Settings.Default.showProjectsMissingFolder; chkAllowSingleInstanceOnly.IsChecked = Settings.Default.AllowSingleInstanceOnly; @@ -584,9 +617,15 @@ void LoadSettings() // update installations folder listbox lstRootFolders.Items.Clear(); - // check if no installation root folders are added, then add default folder(s), this usually happens only on first run (or if user has not added any folders) - if (Settings.Default.rootFolders.Count == 0) + // check if no installation root folders are added, then add default folder(s) + if (Settings.Default.rootFolders == null || Settings.Default.rootFolders.Count == 0) { + // Initialize the collection if null + if (Settings.Default.rootFolders == null) + { + Settings.Default.rootFolders = new System.Collections.Specialized.StringCollection(); + } + // default hub installation folder string baseFolder = "\\Program Files\\Unity\\Hub\\Editor"; string baseFolder2 = "\\Program Files\\"; @@ -594,47 +633,48 @@ void LoadSettings() string defaultFolder2 = "D:" + baseFolder; string defaultFolder3 = "C:" + baseFolder2; string defaultFolder4 = "D:" + baseFolder2; + if (Directory.Exists(defaultFolder1)) { - Properties.Settings.Default.rootFolders.Add(defaultFolder1); + Settings.Default.rootFolders.Add(defaultFolder1); } else if (Directory.Exists(defaultFolder2)) { - Properties.Settings.Default.rootFolders.Add(defaultFolder2); + Settings.Default.rootFolders.Add(defaultFolder2); } else if (Directory.Exists(defaultFolder3)) { if (GetUnityInstallations.HasUnityInstallations(defaultFolder3)) { - Properties.Settings.Default.rootFolders.Add(defaultFolder3); + Settings.Default.rootFolders.Add(defaultFolder3); } else if (GetUnityInstallations.HasUnityInstallations(defaultFolder4)) { - Properties.Settings.Default.rootFolders.Add(defaultFolder4); + Settings.Default.rootFolders.Add(defaultFolder4); } } } - lstRootFolders.ItemsSource = Properties.Settings.Default.rootFolders; + lstRootFolders.ItemsSource = Settings.Default.rootFolders; // restore recent project datagrid column widths - int[] gridColumnWidths = Properties.Settings.Default.gridColumnWidths; + int[] gridColumnWidths = Settings.Default.gridColumnWidths; if (gridColumnWidths != null) { for (int i = 0; i < gridColumnWidths.Length; ++i) { - if (i >= gridRecent.Columns.Count) break; // too many columns were saved, probably some test columns + if (i >= gridRecent.Columns.Count) break; gridRecent.Columns[i].Width = gridColumnWidths[i]; } } // restore buildreport datagrid column widths - gridColumnWidths = Properties.Settings.Default.gridColumnWidthsBuildReport; + gridColumnWidths = Settings.Default.gridColumnWidthsBuildReport; if (gridColumnWidths != null) { for (int i = 0; i < gridColumnWidths.Length; ++i) { - if (i >= gridBuildReport.Columns.Count) break; // too many columns were saved, probably some test columns + if (i >= gridBuildReport.Columns.Count) break; gridBuildReport.Columns[i].Width = gridColumnWidths[i]; } } @@ -650,13 +690,12 @@ void LoadSettings() { currentDateFormat = Settings.Default.customDateFormat; } - else // use default + else { currentDateFormat = defaultDateFormat; } chkHumanFriendlyDateTime.IsChecked = Settings.Default.useHumandFriendlyLastModified; - // if both enabled, then disable custom if (chkHumanFriendlyDateTime.IsChecked == true && chkUseCustomLastModified.IsChecked == true) { chkUseCustomLastModified.IsChecked = false; @@ -669,8 +708,6 @@ void LoadSettings() // recent grid column display index order var order = Settings.Default.recentColumnsOrder; - // if we dont have any values, get & set them now - // also, if user has disabled optional columns, saved order must be reset to default if (order == null || gridRecent.Columns.Count != Settings.Default.recentColumnsOrder.Length) { Settings.Default.recentColumnsOrder = new Int32[gridRecent.Columns.Count]; @@ -680,7 +717,7 @@ void LoadSettings() } Settings.Default.Save(); } - else // load existing order + else { for (int i = 0; i < gridRecent.Columns.Count; i++) { @@ -708,58 +745,104 @@ void LoadSettings() break; } - // set default .bat folder location to appdata/.., if nothing is set, or current one is invalid - if (string.IsNullOrEmpty(txtShortcutBatchFileFolder.Text) || Directory.Exists(txtShortcutBatchFileFolder.Text) == false) + // set default .bat folder location + if (string.IsNullOrEmpty(Settings.Default.shortcutBatchFileFolder) || + !Directory.Exists(Settings.Default.shortcutBatchFileFolder)) { - Settings.Default.shortcutBatchFileFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), appName); - txtShortcutBatchFileFolder.Text = Settings.Default.shortcutBatchFileFolder; + Settings.Default.shortcutBatchFileFolder = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), appName); + Settings.Default.Save(); } + txtShortcutBatchFileFolder.Text = Settings.Default.shortcutBatchFileFolder; chkUseInitScript.IsChecked = Settings.Default.useInitScript; txtCustomInitFileURL.Text = Settings.Default.customInitFileURL; // load webgl port - txtWebglPort.Text = "" + Settings.Default.webglPort; + txtWebglPort.Text = Settings.Default.webglPort.ToString(); webglPort = Settings.Default.webglPort; txtMaxProjectCount.Text = Settings.Default.maxProjectCount.ToString(); chkOverride40ProjectCount.IsChecked = Settings.Default.override40ProjectCount; - if ((bool)chkOverride40ProjectCount.IsChecked) - { - maxProjectCount = Settings.Default.maxProjectCount; - } - else - { - maxProjectCount = 40; - } + maxProjectCount = (bool)chkOverride40ProjectCount.IsChecked + ? Settings.Default.maxProjectCount + : 40; } catch (ConfigurationErrorsException ex) { - string filename = ((ConfigurationErrorsException)ex.InnerException).Filename; + Console.WriteLine($"Configuration error: {ex.Message}"); - if (MessageBox.Show("This may be due to a Windows crash/BSOD.\n" + - "Click 'Yes' to use automatic backup (if exists, otherwise settings are reset), then start application again.\n\n" + - "Click 'No' to exit now (and delete user.config manually)\n\nCorrupted file: " + filename, - appName + " - Corrupt user settings", - MessageBoxButton.YesNo, - MessageBoxImage.Error) == MessageBoxResult.Yes) - { + // Try to get the corrupted file path + string filename = ex.InnerException is ConfigurationErrorsException innerEx + ? innerEx.Filename + : null; - // try to use backup - string backupFilename = filename + ".bak"; - if (File.Exists(backupFilename)) + if (!string.IsNullOrEmpty(filename)) + { + var result = MessageBox.Show( + "Settings file is corrupted or incompatible with .NET 8.\n\n" + + "Click 'Yes' to reset settings to defaults.\n" + + "Click 'No' to exit and fix manually.\n\n" + + $"Corrupted file: {filename}", + $"{appName} - Configuration Error", + MessageBoxButton.YesNo, + MessageBoxImage.Error); + + if (result == MessageBoxResult.Yes) { - File.Copy(backupFilename, filename, true); + try + { + // Try to delete the corrupted user.config + if (File.Exists(filename)) + { + File.Delete(filename); + } + + // Reset to defaults + Settings.Default.Reset(); + Settings.Default.Save(); + + MessageBox.Show( + "Settings have been reset. Please restart the application.", + appName, + MessageBoxButton.OK, + MessageBoxImage.Information); + + Application.Current.Shutdown(); + } + catch (Exception deleteEx) + { + MessageBox.Show( + $"Failed to reset settings: {deleteEx.Message}\n\n" + + $"Please manually delete: {filename}", + appName, + MessageBoxButton.OK, + MessageBoxImage.Error); + Application.Current.Shutdown(); + } } else { - File.Delete(filename); + Application.Current.Shutdown(); } } - // need to restart, otherwise settings not loaded - Process.GetCurrentProcess().Kill(); + else + { + // No specific file, just reset + Settings.Default.Reset(); + Settings.Default.Save(); + } + } + catch (Exception ex) + { + Console.WriteLine($"Unexpected error loading settings: {ex.Message}"); + MessageBox.Show( + $"Error loading settings: {ex.Message}\n\nUsing defaults.", + appName, + MessageBoxButton.OK, + MessageBoxImage.Warning); } - } // LoadSettings() + } private void SaveSettingsOnExit() { @@ -835,6 +918,14 @@ void UpdateUnityInstallationsList() //preferredVersion = "none"; unityInstallationsSource = GetUnityInstallations.Scan(); + + if (unityInstallationsSource == null) + { + lblFoundXInstallations.Content = "Found 0 installations"; + dataGridUnitys.ItemsSource = null; + return; + } + dataGridUnitys.ItemsSource = unityInstallationsSource; // Also make dictionary of installed unitys, to search faster @@ -1261,7 +1352,7 @@ private void Window_Closing(object sender, CancelEventArgs e) { // (TODO force) close theme editor, if still open, TODO NEED to cancel all changes CloseThemeEditor(); - SaveSettingsOnExit(); + //SaveSettingsOnExit(); CloseHubPipeAsync(); } diff --git a/UnityLauncherPro/Properties/AssemblyInfo.cs b/UnityLauncherPro/Properties/AssemblyInfo.cs deleted file mode 100644 index 6fe6e89..0000000 --- a/UnityLauncherPro/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("UnityLauncherPro")] -[assembly: AssemblyDescription("Unity Hub Alternative")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("UnityCoder.com")] -[assembly: AssemblyProduct("UnityLauncherPro")] -[assembly: AssemblyCopyright("Copyright © 2025")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.1")] -[assembly: AssemblyFileVersion("1.0.0.1")] diff --git a/UnityLauncherPro/Properties/Settings.Designer.cs b/UnityLauncherPro/Properties/Settings.Designer.cs index 448598d..778ca0f 100644 --- a/UnityLauncherPro/Properties/Settings.Designer.cs +++ b/UnityLauncherPro/Properties/Settings.Designer.cs @@ -637,5 +637,17 @@ public bool fetchAdditionalInfo { this["fetchAdditionalInfo"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool @__UpgradedOnce { + get { + return ((bool)(this["__UpgradedOnce"])); + } + set { + this["__UpgradedOnce"] = value; + } + } } } diff --git a/UnityLauncherPro/Properties/Settings.settings b/UnityLauncherPro/Properties/Settings.settings index 6cea055..d3c203c 100644 --- a/UnityLauncherPro/Properties/Settings.settings +++ b/UnityLauncherPro/Properties/Settings.settings @@ -160,5 +160,8 @@ False + + False + \ No newline at end of file diff --git a/UnityLauncherPro/UnityLauncherPro.csproj b/UnityLauncherPro/UnityLauncherPro.csproj index 5fe024b..ca500c6 100644 --- a/UnityLauncherPro/UnityLauncherPro.csproj +++ b/UnityLauncherPro/UnityLauncherPro.csproj @@ -1,19 +1,7 @@ - - - + - Debug - AnyCPU - {EC78D91A-3E63-4CAA-8BC3-9673A30FDA45} + net8.0-windows10.0.19041.0 WinExe - UnityLauncherPro - UnityLauncherPro - v4.8 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - true publish\ true Disk @@ -29,158 +17,13 @@ false false true - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - + true + true + true Images/icon.ico - - - app.manifest + 10.0.19041.0 - - - - - - - - - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - - - - - - - - - - - - - DownloadProgressWindow.xaml - - - - - - - - - NewProject.xaml - - - ProjectProperties.xaml - - - ThemeEditor.xaml - - - - - UpgradeWindow.xaml - - - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - False @@ -202,13 +45,26 @@ - - - + + + + + + True + True + Settings.settings + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + \ No newline at end of file