diff --git a/README.md b/README.md index 9439b52..d4b68b0 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,21 @@ +# Note: New Dark Theme WPF version is here : https://github.com/unitycoder/UnityLauncherPro + +### this old winforms version is no longer updated! + # UnityLauncher -Autotically launch projects with correct Unity versions and some extra features to manager your projects and Unity versions! +Handle all your Unity versions and Projects easily! # Features - Automagically Open Projects with Correct Unity Version -- Display Recent Projects list with last modified date and Unity version info +- Display Recent Projects list with last modified date and project version info - Quickly Explore Project Folder - List installed Unity versions, can easily Run, Explore installation folder, View release notes - Download Missing Unity Versions Easily -- Can be used in commandline `UnityLauncher.exe -projectPath "c:/project/path/"` +- Can be used from commandline `UnityLauncher.exe -projectPath "c:/project/path/"` - Can add custom Explorer context menu item to launch folder as a project: https://github.com/unitycoder/UnityLauncher/wiki/Adding-Explorer-Context-Menu +- Use custom launcher arguments per project! +- Show project git branch info - List of custom package folders (quicly explore them and then can import packages) - Show list of available Unity versions/updates @@ -44,6 +50,14 @@ https://forum.unity3d.com/threads/unitylauncher-launch-correct-unity-versions-fo ![image](https://user-images.githubusercontent.com/5438317/35776544-85f7c1f8-09d9-11e8-8ab7-ee08d01ebef3.png) -![image](https://user-images.githubusercontent.com/5438317/35776558-d0692970-09d9-11e8-8191-f48da5d63ca8.png) +![image](https://user-images.githubusercontent.com/5438317/56789044-ac867c80-6809-11e9-9187-b998dbed0d0d.png) ![image](https://user-images.githubusercontent.com/5438317/35776575-01c720bc-09da-11e8-99d1-f6e4ad3c0fab.png) + +# Special Thanks (for fixes, updates, pull requests) +- https://github.com/851marc +- https://github.com/KyleOrth +- https://github.com/Raebyn +- Ville Tuhkanen +- https://github.com/geo-at-github +- https://github.com/yschuurmans diff --git a/UnityLauncher/App.config b/UnityLauncher/App.config index beb935b..498e2cf 100644 --- a/UnityLauncher/App.config +++ b/UnityLauncher/App.config @@ -13,7 +13,7 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema"> C:\Program Files\ @@ -24,14 +24,14 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> True - True + False 600 @@ -39,12 +39,14 @@ 650 - - - - - + + False + + + False + + + False diff --git a/UnityLauncher/Form1.Designer.cs b/UnityLauncher/Form1.Designer.cs index eecce41..318d60b 100644 --- a/UnityLauncher/Form1.Designer.cs +++ b/UnityLauncher/Form1.Designer.cs @@ -32,6 +32,9 @@ private void InitializeComponent() System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabProjects = new System.Windows.Forms.TabPage(); + this.lblClearSearchField = new System.Windows.Forms.Label(); + this.btnBrowseForProject = new System.Windows.Forms.Button(); + this.btnRefreshProjectList = new System.Windows.Forms.Button(); this.tbSearchBar = new System.Windows.Forms.TextBox(); this.btnUpgradeProject = new System.Windows.Forms.Button(); this.btnRunUnityOnly = new System.Windows.Forms.Button(); @@ -42,6 +45,8 @@ private void InitializeComponent() this._version = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._path = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._dateModified = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._launchArguments = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._gitBranch = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabUnitys = new System.Windows.Forms.TabPage(); this.btn_refreshUnityList = new System.Windows.Forms.Button(); this.btnOpenReleasePage = new System.Windows.Forms.Button(); @@ -50,6 +55,8 @@ private void InitializeComponent() this.gridUnityList = new System.Windows.Forms.DataGridView(); this._unityVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._unityPath = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._unityInstallDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this._Platforms = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabPackages = new System.Windows.Forms.TabPage(); this.btnAddAssetStoreFolder = new System.Windows.Forms.Button(); this.btnExplorePackageFolder = new System.Windows.Forms.Button(); @@ -58,12 +65,23 @@ private void InitializeComponent() this.label3 = new System.Windows.Forms.Label(); this.lstPackageFolders = new System.Windows.Forms.ListBox(); this.tabUpdates = new System.Windows.Forms.TabPage(); + this.btnDownloadNewUnity = new System.Windows.Forms.Button(); + this.tbSearchUpdates = new System.Windows.Forms.TextBox(); this.btnOpenUpdateWebsite = new System.Windows.Forms.Button(); this.btnFetchUnityVersions = new System.Windows.Forms.Button(); this.gridUnityUpdates = new System.Windows.Forms.DataGridView(); this._Date = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._UnityUpdateVersion = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.tabSettings = new System.Windows.Forms.TabPage(); + this.btnPlayerLogFolder = new System.Windows.Forms.Button(); + this.btnOpenLogcatCmd = new System.Windows.Forms.Button(); + this.chkDarkSkin = new System.Windows.Forms.CheckBox(); + this.btnCheckUpdates = new System.Windows.Forms.Button(); + this.linkProjectGithub = new System.Windows.Forms.LinkLabel(); + this.linkArgumentsDocs = new System.Windows.Forms.LinkLabel(); + this.chkShowGitBranchColumn = new System.Windows.Forms.CheckBox(); + this.label5 = new System.Windows.Forms.Label(); + this.chkShowLauncherArgumentsColumn = new System.Windows.Forms.CheckBox(); this.ChkQuitAfterOpen = new System.Windows.Forms.CheckBox(); this.btnOpenLogFolder = new System.Windows.Forms.Button(); this.chkQuitAfterCommandline = new System.Windows.Forms.CheckBox(); @@ -84,6 +102,7 @@ private void InitializeComponent() this.btnAddPackFolder = new System.Windows.Forms.Button(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker(); this.tabControl1.SuspendLayout(); this.tabProjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridRecent)).BeginInit(); @@ -115,6 +134,9 @@ private void InitializeComponent() // // tabProjects // + this.tabProjects.Controls.Add(this.lblClearSearchField); + this.tabProjects.Controls.Add(this.btnBrowseForProject); + this.tabProjects.Controls.Add(this.btnRefreshProjectList); this.tabProjects.Controls.Add(this.tbSearchBar); this.tabProjects.Controls.Add(this.btnUpgradeProject); this.tabProjects.Controls.Add(this.btnRunUnityOnly); @@ -128,13 +150,51 @@ private void InitializeComponent() this.tabProjects.Text = "Projects"; this.tabProjects.UseVisualStyleBackColor = true; // + // lblClearSearchField + // + this.lblClearSearchField.AutoSize = true; + this.lblClearSearchField.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblClearSearchField.ForeColor = System.Drawing.Color.DarkGray; + this.lblClearSearchField.Location = new System.Drawing.Point(448, 8); + this.lblClearSearchField.Name = "lblClearSearchField"; + this.lblClearSearchField.Size = new System.Drawing.Size(12, 13); + this.lblClearSearchField.TabIndex = 24; + this.lblClearSearchField.Text = "x"; + this.lblClearSearchField.Click += new System.EventHandler(this.lblClearSearchField_Click); + this.lblClearSearchField.MouseEnter += new System.EventHandler(this.lblClearSearchField_MouseEnter); + this.lblClearSearchField.MouseLeave += new System.EventHandler(this.lblClearSearchField_MouseLeave); + // + // btnBrowseForProject + // + this.btnBrowseForProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnBrowseForProject.Location = new System.Drawing.Point(469, 3); + this.btnBrowseForProject.Name = "btnBrowseForProject"; + this.btnBrowseForProject.Size = new System.Drawing.Size(80, 23); + this.btnBrowseForProject.TabIndex = 23; + this.btnBrowseForProject.Text = "+ Add Project"; + this.toolTip1.SetToolTip(this.btnBrowseForProject, "Browse for a Project"); + this.btnBrowseForProject.UseVisualStyleBackColor = true; + this.btnBrowseForProject.Click += new System.EventHandler(this.btnBrowseForProject_Click); + // + // btnRefreshProjectList + // + this.btnRefreshProjectList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnRefreshProjectList.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnRefreshProjectList.Location = new System.Drawing.Point(555, 3); + this.btnRefreshProjectList.Name = "btnRefreshProjectList"; + this.btnRefreshProjectList.Size = new System.Drawing.Size(22, 23); + this.btnRefreshProjectList.TabIndex = 22; + this.btnRefreshProjectList.Text = "⟳"; + this.toolTip1.SetToolTip(this.btnRefreshProjectList, "Refresh Unity Installations List"); + this.btnRefreshProjectList.UseCompatibleTextRendering = true; + this.btnRefreshProjectList.UseVisualStyleBackColor = true; + this.btnRefreshProjectList.Click += new System.EventHandler(this.btnRefreshProjectList_Click); + // // tbSearchBar // - this.tbSearchBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.tbSearchBar.Location = new System.Drawing.Point(9, 4); + this.tbSearchBar.Location = new System.Drawing.Point(3, 5); this.tbSearchBar.Name = "tbSearchBar"; - this.tbSearchBar.Size = new System.Drawing.Size(563, 20); + this.tbSearchBar.Size = new System.Drawing.Size(460, 20); this.tbSearchBar.TabIndex = 0; this.tbSearchBar.TextChanged += new System.EventHandler(this.FilterRecentProject); // @@ -201,20 +261,22 @@ private void InitializeComponent() this._project, this._version, this._path, - this._dateModified}); - this.gridRecent.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; + this._dateModified, + this._launchArguments, + this._gitBranch}); + this.gridRecent.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnF2; this.gridRecent.Location = new System.Drawing.Point(3, 30); this.gridRecent.MultiSelect = false; this.gridRecent.Name = "gridRecent"; - this.gridRecent.ReadOnly = true; this.gridRecent.RowHeadersWidth = 18; this.gridRecent.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.gridRecent.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.gridRecent.ShowCellErrors = false; this.gridRecent.ShowCellToolTips = false; - this.gridRecent.ShowEditingIcon = false; this.gridRecent.Size = new System.Drawing.Size(574, 475); + this.gridRecent.StandardTab = true; this.gridRecent.TabIndex = 1; + this.gridRecent.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.gridRecent_CellEndEdit); this.gridRecent.CellMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.GridRecent_CellMouseDoubleClick); this.gridRecent.KeyDown += new System.Windows.Forms.KeyEventHandler(this.gridRecent_KeyDown); // @@ -249,6 +311,17 @@ private void InitializeComponent() this._dateModified.Resizable = System.Windows.Forms.DataGridViewTriState.True; this._dateModified.Width = 120; // + // _launchArguments + // + this._launchArguments.HeaderText = "Arguments"; + this._launchArguments.Name = "_launchArguments"; + // + // _gitBranch + // + this._gitBranch.HeaderText = "GITBranch"; + this._gitBranch.Name = "_gitBranch"; + this._gitBranch.ReadOnly = true; + // // tabUnitys // this.tabUnitys.Controls.Add(this.btn_refreshUnityList); @@ -260,7 +333,7 @@ private void InitializeComponent() this.tabUnitys.Name = "tabUnitys"; this.tabUnitys.Size = new System.Drawing.Size(580, 549); this.tabUnitys.TabIndex = 1; - this.tabUnitys.Text = "Unity\'s"; + this.tabUnitys.Text = "Unitys"; this.tabUnitys.UseVisualStyleBackColor = true; // // btn_refreshUnityList @@ -327,28 +400,32 @@ private void InitializeComponent() this.gridUnityList.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.gridUnityList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this._unityVersion, - this._unityPath}); + this._unityPath, + this._unityInstallDate, + this._Platforms}); this.gridUnityList.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; this.gridUnityList.Location = new System.Drawing.Point(3, 27); this.gridUnityList.MultiSelect = false; this.gridUnityList.Name = "gridUnityList"; this.gridUnityList.ReadOnly = true; + this.gridUnityList.RowHeadersWidth = 15; this.gridUnityList.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.gridUnityList.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.gridUnityList.ShowCellErrors = false; this.gridUnityList.ShowCellToolTips = false; this.gridUnityList.ShowEditingIcon = false; this.gridUnityList.Size = new System.Drawing.Size(574, 478); + this.gridUnityList.StandardTab = true; this.gridUnityList.TabIndex = 10; this.gridUnityList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.unityGridView_KeyDown); // // _unityVersion // this._unityVersion.HeaderText = "Version"; - this._unityVersion.MinimumWidth = 150; + this._unityVersion.MinimumWidth = 120; this._unityVersion.Name = "_unityVersion"; this._unityVersion.ReadOnly = true; - this._unityVersion.Width = 150; + this._unityVersion.Width = 120; // // _unityPath // @@ -359,6 +436,19 @@ private void InitializeComponent() this._unityPath.Resizable = System.Windows.Forms.DataGridViewTriState.False; this._unityPath.Width = 300; // + // _unityInstallDate + // + this._unityInstallDate.HeaderText = "Installed"; + this._unityInstallDate.Name = "_unityInstallDate"; + this._unityInstallDate.ReadOnly = true; + this._unityInstallDate.Width = 120; + // + // _Platforms + // + this._Platforms.HeaderText = "Platforms"; + this._Platforms.Name = "_Platforms"; + this._Platforms.ReadOnly = true; + // // tabPackages // this.tabPackages.Controls.Add(this.btnAddAssetStoreFolder); @@ -441,6 +531,8 @@ private void InitializeComponent() // // tabUpdates // + this.tabUpdates.Controls.Add(this.btnDownloadNewUnity); + this.tabUpdates.Controls.Add(this.tbSearchUpdates); this.tabUpdates.Controls.Add(this.btnOpenUpdateWebsite); this.tabUpdates.Controls.Add(this.btnFetchUnityVersions); this.tabUpdates.Controls.Add(this.gridUnityUpdates); @@ -451,17 +543,37 @@ private void InitializeComponent() this.tabUpdates.Text = "Updates"; this.tabUpdates.UseVisualStyleBackColor = true; // + // btnDownloadNewUnity + // + this.btnDownloadNewUnity.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnDownloadNewUnity.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnDownloadNewUnity.Location = new System.Drawing.Point(3, 511); + this.btnDownloadNewUnity.Name = "btnDownloadNewUnity"; + this.btnDownloadNewUnity.Size = new System.Drawing.Size(239, 35); + this.btnDownloadNewUnity.TabIndex = 25; + this.btnDownloadNewUnity.Text = "Download in Browser"; + this.toolTip1.SetToolTip(this.btnDownloadNewUnity, "Open Release Page"); + this.btnDownloadNewUnity.UseVisualStyleBackColor = true; + this.btnDownloadNewUnity.Click += new System.EventHandler(this.btnDownloadNewUnity_Click); + // + // tbSearchUpdates + // + this.tbSearchUpdates.Location = new System.Drawing.Point(3, 5); + this.tbSearchUpdates.Name = "tbSearchUpdates"; + this.tbSearchUpdates.Size = new System.Drawing.Size(460, 20); + this.tbSearchUpdates.TabIndex = 8; + this.tbSearchUpdates.TextChanged += new System.EventHandler(this.FilterUnityUpdates); + // // btnOpenUpdateWebsite // - this.btnOpenUpdateWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); + this.btnOpenUpdateWebsite.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.btnOpenUpdateWebsite.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnOpenUpdateWebsite.Location = new System.Drawing.Point(5, 511); + this.btnOpenUpdateWebsite.Location = new System.Drawing.Point(248, 511); this.btnOpenUpdateWebsite.Name = "btnOpenUpdateWebsite"; - this.btnOpenUpdateWebsite.Size = new System.Drawing.Size(572, 35); + this.btnOpenUpdateWebsite.Size = new System.Drawing.Size(329, 35); this.btnOpenUpdateWebsite.TabIndex = 24; this.btnOpenUpdateWebsite.Text = "Open Website"; - this.toolTip1.SetToolTip(this.btnOpenUpdateWebsite, "Launch selected project"); + this.toolTip1.SetToolTip(this.btnOpenUpdateWebsite, "Open Release Page"); this.btnOpenUpdateWebsite.UseVisualStyleBackColor = true; this.btnOpenUpdateWebsite.Click += new System.EventHandler(this.btnOpenUpdateWebsite_Click); // @@ -494,7 +606,7 @@ private void InitializeComponent() this._Date, this._UnityUpdateVersion}); this.gridUnityUpdates.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; - this.gridUnityUpdates.Location = new System.Drawing.Point(3, 27); + this.gridUnityUpdates.Location = new System.Drawing.Point(3, 30); this.gridUnityUpdates.MultiSelect = false; this.gridUnityUpdates.Name = "gridUnityUpdates"; this.gridUnityUpdates.ReadOnly = true; @@ -504,7 +616,8 @@ private void InitializeComponent() this.gridUnityUpdates.ShowCellErrors = false; this.gridUnityUpdates.ShowCellToolTips = false; this.gridUnityUpdates.ShowEditingIcon = false; - this.gridUnityUpdates.Size = new System.Drawing.Size(574, 478); + this.gridUnityUpdates.Size = new System.Drawing.Size(574, 475); + this.gridUnityUpdates.StandardTab = true; this.gridUnityUpdates.TabIndex = 22; // // _Date @@ -525,6 +638,15 @@ private void InitializeComponent() // // tabSettings // + this.tabSettings.Controls.Add(this.btnPlayerLogFolder); + this.tabSettings.Controls.Add(this.btnOpenLogcatCmd); + this.tabSettings.Controls.Add(this.chkDarkSkin); + this.tabSettings.Controls.Add(this.btnCheckUpdates); + this.tabSettings.Controls.Add(this.linkProjectGithub); + this.tabSettings.Controls.Add(this.linkArgumentsDocs); + this.tabSettings.Controls.Add(this.chkShowGitBranchColumn); + this.tabSettings.Controls.Add(this.label5); + this.tabSettings.Controls.Add(this.chkShowLauncherArgumentsColumn); this.tabSettings.Controls.Add(this.ChkQuitAfterOpen); this.tabSettings.Controls.Add(this.btnOpenLogFolder); this.tabSettings.Controls.Add(this.chkQuitAfterCommandline); @@ -546,11 +668,123 @@ private void InitializeComponent() this.tabSettings.Text = "Settings"; this.tabSettings.UseVisualStyleBackColor = true; // + // btnPlayerLogFolder + // + this.btnPlayerLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnPlayerLogFolder.Location = new System.Drawing.Point(328, 300); + this.btnPlayerLogFolder.Name = "btnPlayerLogFolder"; + this.btnPlayerLogFolder.Size = new System.Drawing.Size(119, 23); + this.btnPlayerLogFolder.TabIndex = 43; + this.btnPlayerLogFolder.Text = "Player.log Folder"; + this.btnPlayerLogFolder.UseVisualStyleBackColor = true; + this.btnPlayerLogFolder.Click += new System.EventHandler(this.btnPlayerLogFolder_Click); + // + // btnOpenLogcatCmd + // + this.btnOpenLogcatCmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnOpenLogcatCmd.Location = new System.Drawing.Point(453, 271); + this.btnOpenLogcatCmd.Name = "btnOpenLogcatCmd"; + this.btnOpenLogcatCmd.Size = new System.Drawing.Size(119, 23); + this.btnOpenLogcatCmd.TabIndex = 42; + this.btnOpenLogcatCmd.Text = "ADB logcat (cmd)"; + this.toolTip1.SetToolTip(this.btnOpenLogcatCmd, "adb logcat -s Unity ActivityManager PackageManager dalvikvm DEBUG -v color"); + this.btnOpenLogcatCmd.UseVisualStyleBackColor = true; + this.btnOpenLogcatCmd.Click += new System.EventHandler(this.btnOpenLogcatCmd_Click); + // + // chkDarkSkin + // + this.chkDarkSkin.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkDarkSkin.AutoSize = true; + this.chkDarkSkin.Location = new System.Drawing.Point(20, 443); + this.chkDarkSkin.Name = "chkDarkSkin"; + this.chkDarkSkin.Size = new System.Drawing.Size(85, 17); + this.chkDarkSkin.TabIndex = 41; + this.chkDarkSkin.Text = "Dark Theme"; + this.chkDarkSkin.UseVisualStyleBackColor = true; + this.chkDarkSkin.CheckedChanged += new System.EventHandler(this.chkDarkSkin_CheckedChanged); + // + // btnCheckUpdates + // + this.btnCheckUpdates.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCheckUpdates.Location = new System.Drawing.Point(415, 495); + this.btnCheckUpdates.Name = "btnCheckUpdates"; + this.btnCheckUpdates.Size = new System.Drawing.Size(157, 23); + this.btnCheckUpdates.TabIndex = 40; + this.btnCheckUpdates.Text = "Open Github Releases Page"; + this.btnCheckUpdates.UseVisualStyleBackColor = true; + this.btnCheckUpdates.Click += new System.EventHandler(this.btnCheckUpdates_Click); + // + // linkProjectGithub + // + this.linkProjectGithub.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.linkProjectGithub.AutoSize = true; + this.linkProjectGithub.LinkArea = new System.Windows.Forms.LinkArea(20, 6); + this.linkProjectGithub.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; + this.linkProjectGithub.Location = new System.Drawing.Point(434, 532); + this.linkProjectGithub.Name = "linkProjectGithub"; + this.linkProjectGithub.Size = new System.Drawing.Size(138, 17); + this.linkProjectGithub.TabIndex = 39; + this.linkProjectGithub.TabStop = true; + this.linkProjectGithub.Text = "Visit UnityLauncher Github"; + this.linkProjectGithub.UseCompatibleTextRendering = true; + this.linkProjectGithub.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkProjectGithub_LinkClicked); + // + // linkArgumentsDocs + // + this.linkArgumentsDocs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.linkArgumentsDocs.AutoSize = true; + this.linkArgumentsDocs.LinkArea = new System.Windows.Forms.LinkArea(1, 4); + this.linkArgumentsDocs.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline; + this.linkArgumentsDocs.Location = new System.Drawing.Point(385, 375); + this.linkArgumentsDocs.Name = "linkArgumentsDocs"; + this.linkArgumentsDocs.Size = new System.Drawing.Size(36, 17); + this.linkArgumentsDocs.TabIndex = 38; + this.linkArgumentsDocs.TabStop = true; + this.linkArgumentsDocs.Text = "(docs)"; + this.linkArgumentsDocs.UseCompatibleTextRendering = true; + this.linkArgumentsDocs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkArgumentsDocs_LinkClicked); + // + // chkShowGitBranchColumn + // + this.chkShowGitBranchColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkShowGitBranchColumn.AutoSize = true; + this.chkShowGitBranchColumn.Location = new System.Drawing.Point(266, 397); + this.chkShowGitBranchColumn.Name = "chkShowGitBranchColumn"; + this.chkShowGitBranchColumn.Size = new System.Drawing.Size(76, 17); + this.chkShowGitBranchColumn.TabIndex = 36; + this.chkShowGitBranchColumn.Text = "Git Branch"; + this.chkShowGitBranchColumn.UseVisualStyleBackColor = true; + this.chkShowGitBranchColumn.CheckedChanged += new System.EventHandler(this.checkShowGitBranchColumn_CheckedChanged); + // + // label5 + // + this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label5.AutoSize = true; + this.label5.Enabled = false; + this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label5.Location = new System.Drawing.Point(263, 349); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(105, 13); + this.label5.TabIndex = 35; + this.label5.Text = "Optional Columns"; + // + // chkShowLauncherArgumentsColumn + // + this.chkShowLauncherArgumentsColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.chkShowLauncherArgumentsColumn.AutoSize = true; + this.chkShowLauncherArgumentsColumn.Location = new System.Drawing.Point(266, 374); + this.chkShowLauncherArgumentsColumn.Name = "chkShowLauncherArgumentsColumn"; + this.chkShowLauncherArgumentsColumn.Size = new System.Drawing.Size(124, 17); + this.chkShowLauncherArgumentsColumn.TabIndex = 34; + this.chkShowLauncherArgumentsColumn.Text = "Launcher Arguments"; + this.chkShowLauncherArgumentsColumn.UseVisualStyleBackColor = true; + this.chkShowLauncherArgumentsColumn.CheckedChanged += new System.EventHandler(this.checkShowLauncherArgumentsColumn_CheckedChanged); + // // ChkQuitAfterOpen // this.ChkQuitAfterOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.ChkQuitAfterOpen.AutoSize = true; - this.ChkQuitAfterOpen.Location = new System.Drawing.Point(20, 409); + this.ChkQuitAfterOpen.Location = new System.Drawing.Point(20, 397); this.ChkQuitAfterOpen.Name = "ChkQuitAfterOpen"; this.ChkQuitAfterOpen.Size = new System.Drawing.Size(172, 17); this.ChkQuitAfterOpen.TabIndex = 33; @@ -561,9 +795,9 @@ private void InitializeComponent() // btnOpenLogFolder // this.btnOpenLogFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOpenLogFolder.Location = new System.Drawing.Point(435, 380); + this.btnOpenLogFolder.Location = new System.Drawing.Point(328, 271); this.btnOpenLogFolder.Name = "btnOpenLogFolder"; - this.btnOpenLogFolder.Size = new System.Drawing.Size(137, 23); + this.btnOpenLogFolder.Size = new System.Drawing.Size(119, 23); this.btnOpenLogFolder.TabIndex = 32; this.btnOpenLogFolder.Text = "Open Editor Log Folder"; this.btnOpenLogFolder.UseVisualStyleBackColor = true; @@ -573,7 +807,7 @@ private void InitializeComponent() // this.chkQuitAfterCommandline.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkQuitAfterCommandline.AutoSize = true; - this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 432); + this.chkQuitAfterCommandline.Location = new System.Drawing.Point(20, 420); this.chkQuitAfterCommandline.Name = "chkQuitAfterCommandline"; this.chkQuitAfterCommandline.Size = new System.Drawing.Size(189, 17); this.chkQuitAfterCommandline.TabIndex = 31; @@ -584,7 +818,7 @@ private void InitializeComponent() // btnAddRegister // this.btnAddRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnAddRegister.Location = new System.Drawing.Point(139, 465); + this.btnAddRegister.Location = new System.Drawing.Point(139, 493); this.btnAddRegister.Name = "btnAddRegister"; this.btnAddRegister.Size = new System.Drawing.Size(64, 23); this.btnAddRegister.TabIndex = 30; @@ -595,11 +829,11 @@ private void InitializeComponent() // btnRemoveRegister // this.btnRemoveRegister.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnRemoveRegister.Location = new System.Drawing.Point(209, 465); + this.btnRemoveRegister.Location = new System.Drawing.Point(209, 493); this.btnRemoveRegister.Name = "btnRemoveRegister"; this.btnRemoveRegister.Size = new System.Drawing.Size(64, 23); this.btnRemoveRegister.TabIndex = 29; - this.btnRemoveRegister.Text = "uninstall"; + this.btnRemoveRegister.Text = "Uninstall"; this.btnRemoveRegister.UseVisualStyleBackColor = true; this.btnRemoveRegister.Click += new System.EventHandler(this.btnRemoveRegister_Click); // @@ -607,7 +841,7 @@ private void InitializeComponent() // this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(19, 470); + this.label4.Location = new System.Drawing.Point(19, 498); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(117, 13); this.label4.TabIndex = 28; @@ -619,7 +853,7 @@ private void InitializeComponent() this.label2.AutoSize = true; this.label2.Enabled = false; this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.Location = new System.Drawing.Point(17, 361); + this.label2.Location = new System.Drawing.Point(17, 349); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(88, 13); this.label2.TabIndex = 26; @@ -629,7 +863,7 @@ private void InitializeComponent() // this.chkMinimizeToTaskbar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.chkMinimizeToTaskbar.AutoSize = true; - this.chkMinimizeToTaskbar.Location = new System.Drawing.Point(20, 386); + this.chkMinimizeToTaskbar.Location = new System.Drawing.Point(20, 374); this.chkMinimizeToTaskbar.Name = "chkMinimizeToTaskbar"; this.chkMinimizeToTaskbar.Size = new System.Drawing.Size(116, 17); this.chkMinimizeToTaskbar.TabIndex = 25; @@ -674,7 +908,7 @@ private void InitializeComponent() this.lstRootFolders.FormattingEnabled = true; this.lstRootFolders.Location = new System.Drawing.Point(20, 31); this.lstRootFolders.Name = "lstRootFolders"; - this.lstRootFolders.Size = new System.Drawing.Size(552, 186); + this.lstRootFolders.Size = new System.Drawing.Size(563, 186); this.lstRootFolders.TabIndex = 20; // // lbl_unityCount @@ -682,7 +916,7 @@ private void InitializeComponent() this.lbl_unityCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.lbl_unityCount.AutoSize = true; this.lbl_unityCount.Enabled = false; - this.lbl_unityCount.Location = new System.Drawing.Point(475, 15); + this.lbl_unityCount.Location = new System.Drawing.Point(483, 15); this.lbl_unityCount.Name = "lbl_unityCount"; this.lbl_unityCount.Size = new System.Drawing.Size(97, 13); this.lbl_unityCount.TabIndex = 18; @@ -691,9 +925,9 @@ private void InitializeComponent() // btnRefresh // this.btnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnRefresh.Location = new System.Drawing.Point(435, 223); + this.btnRefresh.Location = new System.Drawing.Point(453, 223); this.btnRefresh.Name = "btnRefresh"; - this.btnRefresh.Size = new System.Drawing.Size(137, 23); + this.btnRefresh.Size = new System.Drawing.Size(119, 23); this.btnRefresh.TabIndex = 19; this.btnRefresh.Text = "Refresh Unity List"; this.toolTip1.SetToolTip(this.btnRefresh, "Refresh Unity Installations List"); @@ -723,22 +957,26 @@ private void InitializeComponent() // // statusStrip1 // + // this next line keeps disappearing : this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.toolStripStatusLabel1}); + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripStatusLabel1 }); this.statusStrip1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.statusStrip1.AutoSize = false; this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1}); this.statusStrip1.Location = new System.Drawing.Point(0, 590); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(166, 22); + this.statusStrip1.Size = new System.Drawing.Size(579, 22); + this.statusStrip1.SizingGrip = false; this.statusStrip1.TabIndex = 7; this.statusStrip1.Text = "statusStrip1"; // // toolStripStatusLabel1 // + this.toolStripStatusLabel1.AutoSize = false; this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; - this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17); + this.toolStripStatusLabel1.Size = new System.Drawing.Size(550, 17); this.toolStripStatusLabel1.Text = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // Form1 // @@ -753,7 +991,8 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(600, 650); this.Name = "Form1"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "UnityLauncher - BuyTheDip Edition 16"; + this.Text = "UnityLauncher - AutumnEdition 29"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); this.Load += new System.EventHandler(this.Form1_Load); this.ResizeEnd += new System.EventHandler(this.Form1_ResizeEnd); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress); @@ -767,13 +1006,13 @@ private void InitializeComponent() this.tabPackages.ResumeLayout(false); this.tabPackages.PerformLayout(); this.tabUpdates.ResumeLayout(false); + this.tabUpdates.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.gridUnityUpdates)).EndInit(); this.tabSettings.ResumeLayout(false); this.tabSettings.PerformLayout(); this.statusStrip1.ResumeLayout(false); this.statusStrip1.PerformLayout(); this.ResumeLayout(false); - this.PerformLayout(); } @@ -793,8 +1032,6 @@ private void InitializeComponent() private System.Windows.Forms.DataGridView gridUnityList; private System.Windows.Forms.Button btnExploreUnity; private System.Windows.Forms.Button btnLaunchUnity; - private System.Windows.Forms.DataGridViewTextBoxColumn _unityVersion; - private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; private System.Windows.Forms.ListBox lstRootFolders; private System.Windows.Forms.Button btnAddUnityFolder; private System.Windows.Forms.Button btnRemoveInstallFolder; @@ -821,10 +1058,6 @@ private void InitializeComponent() private System.Windows.Forms.Button btnOpenLogFolder; private System.Windows.Forms.TextBox tbSearchBar; private System.Windows.Forms.CheckBox ChkQuitAfterOpen; - private System.Windows.Forms.DataGridViewTextBoxColumn _project; - private System.Windows.Forms.DataGridViewTextBoxColumn _version; - private System.Windows.Forms.DataGridViewTextBoxColumn _path; - private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; private System.Windows.Forms.Button btn_refreshUnityList; private System.Windows.Forms.TabPage tabUpdates; private System.Windows.Forms.Button btnFetchUnityVersions; @@ -832,6 +1065,31 @@ private void InitializeComponent() private System.Windows.Forms.Button btnOpenUpdateWebsite; private System.Windows.Forms.DataGridViewTextBoxColumn _Date; private System.Windows.Forms.DataGridViewTextBoxColumn _UnityUpdateVersion; + private System.Windows.Forms.DataGridViewTextBoxColumn _project; + private System.Windows.Forms.DataGridViewTextBoxColumn _version; + private System.Windows.Forms.DataGridViewTextBoxColumn _path; + private System.Windows.Forms.DataGridViewTextBoxColumn _dateModified; + private System.Windows.Forms.DataGridViewTextBoxColumn _launchArguments; + private System.Windows.Forms.DataGridViewTextBoxColumn _gitBranch; + private System.Windows.Forms.CheckBox chkShowGitBranchColumn; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.CheckBox chkShowLauncherArgumentsColumn; + private System.Windows.Forms.LinkLabel linkArgumentsDocs; + private System.Windows.Forms.LinkLabel linkProjectGithub; + private System.Windows.Forms.Button btnCheckUpdates; + private System.Windows.Forms.Button btnRefreshProjectList; + private System.Windows.Forms.Button btnBrowseForProject; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityVersion; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityPath; + private System.Windows.Forms.DataGridViewTextBoxColumn _unityInstallDate; + private System.Windows.Forms.DataGridViewTextBoxColumn _Platforms; + private System.Windows.Forms.TextBox tbSearchUpdates; + private System.ComponentModel.BackgroundWorker backgroundWorker1; + private System.Windows.Forms.CheckBox chkDarkSkin; + private System.Windows.Forms.Button btnOpenLogcatCmd; + private System.Windows.Forms.Button btnDownloadNewUnity; + private System.Windows.Forms.Button btnPlayerLogFolder; + private System.Windows.Forms.Label lblClearSearchField; } } diff --git a/UnityLauncher/Form1.cs b/UnityLauncher/Form1.cs index 5071624..456283e 100644 --- a/UnityLauncher/Form1.cs +++ b/UnityLauncher/Form1.cs @@ -1,1201 +1,1479 @@ -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows.Forms; - -namespace UnityLauncher -{ - public partial class Form1 : Form - { - public static Dictionary unityList = new Dictionary(); - const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; - bool isDownloadUnityList = false; - - - public Form1() - { - InitializeComponent(); - } - - private void Form1_Load(object sender, EventArgs e) - { - Start(); - } - - void Start() - { - SetStatus("Initializing.."); - - // check installations folder - var root = GetRootFolder(); - if (root == null || root.Length == 0) - { - SetStatus("Missing root folder.."); - AddRootFolder(); - SetStatus("Ready"); - } - - LoadSettings(); - - // scan installed unitys, TODO: could cache results, at least fileinfo's - bool foundedUnitys = ScanUnityInstallations(); - if (foundedUnitys == false) - { - SetStatus("Error> Did not found any Unity installations, try setting correct root folder.."); - UpdateRecentProjectsList(); - tabControl1.SelectedIndex = tabControl1.TabCount - 1; // last tab is settings - return; - } - - // check if received -projectPath argument (that means opening from explorer / cmdline) - string[] args = Environment.GetCommandLineArgs(); - if (args != null && args.Length > 2) - { - var commandLineArgs = args[1]; - if (commandLineArgs == "-projectPath") - { - SetStatus("Launching from commandline.."); - - var projectPathArgument = args[2]; - var version = GetProjectVersion(projectPathArgument); - - // try launching it - LaunchProject(projectPathArgument, version, true); - - SetStatus("Ready"); - - // quit after launch if enabled in settings - if (Properties.Settings.Default.closeAfterExplorer == true) - { - Application.Exit(); - } - } - else - { - SetStatus("Error> Invalid arguments:" + args[1]); - } - } - - UpdateRecentProjectsList(); - - // preselect grid - gridRecent.Select(); - - this.gridRecent.ColumnWidthChanged += new System.Windows.Forms.DataGridViewColumnEventHandler(this.gridRecent_ColumnWidthChanged); - } - - void LoadSettings() - { - // form size - this.Width = Properties.Settings.Default.formWidth; - this.Height = Properties.Settings.Default.formHeight; - - // update settings window - chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; - chkQuitAfterCommandline.Checked = Properties.Settings.Default.closeAfterExplorer; - ChkQuitAfterOpen.Checked = Properties.Settings.Default.closeAfterProject; - - // update installations folder listbox - lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); - // update packages folder listbox - lstPackageFolders.Items.AddRange(Properties.Settings.Default.packageFolders.Cast().ToArray()); - - // restore data grid view widths - int[] gridColumnWidths = Properties.Settings.Default.gridColumnWidths; - if (gridColumnWidths != null) - { - - for (int i = 0; i < gridColumnWidths.Length; ++i) - { - gridRecent.Columns[i].Width = gridColumnWidths[i]; - } - } - } - - /// - /// returns true if we have exact version installed - /// - /// - /// - bool HaveExactVersionInstalled(string version) - { - //Console.WriteLine("checking: '" + version + "'"); - var installedExact = unityList.ContainsKey(version); - //Console.WriteLine("have exact:" + installedExact); - return installedExact; - } - - - /// - /// parse project version from ProjectSettings data - /// - /// project base path - /// - string GetProjectVersion(string path) - { - var version = ""; - if (Directory.Exists(Path.Combine(path, "ProjectSettings"))) - { - var versionPath = Path.Combine(path, "ProjectSettings", "ProjectVersion.txt"); - if (File.Exists(versionPath) == true) // 5.x and later - { - var data = File.ReadAllLines(versionPath); - - if (data != null && data.Length > 0) - { - var dd = data[0]; - // check first line - if (dd.Contains("m_EditorVersion")) - { - var t = dd.Split(new string[] { "m_EditorVersion: " }, StringSplitOptions.None); - if (t != null && t.Length > 0) - { - version = t[1].Trim(); - } - else - { - throw new InvalidDataException("invalid version data:" + data); - } - } - else - { - MessageBox.Show("Cannot find m_EditorVersion in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); - } - } - else - { - MessageBox.Show("Invalid projectversion data found in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); - } - } - else // maybe its 4.x - { - versionPath = Path.Combine(path, "ProjectSettings", "ProjectSettings.asset"); - if (File.Exists(versionPath) == true) - { - // first try if its ascii format - var data = File.ReadAllLines(versionPath); - if (data != null && data.Length > 0 && data[0].IndexOf("YAML") > -1) - { - // in text format, then we need to try library file instead - var newVersionPath = Path.Combine(path, "Library", "AnnotationManager"); - if (File.Exists(versionPath) == true) - { - versionPath = newVersionPath; - } - } - - // try to get version data out from binary asset - var binData = File.ReadAllBytes(versionPath); - if (binData != null && binData.Length > 0) - { - int dataLen = 7; - int startIndex = 20; - var bytes = new byte[dataLen]; - for (int i = 0; i < dataLen; i++) - { - bytes[i] = binData[startIndex + i]; - } - version = Encoding.UTF8.GetString(bytes); - } - } - } - } - return version; - } - - - void AddRootFolder() - { - folderBrowserDialog1.Description = "Select root folder"; - var d = folderBrowserDialog1.ShowDialog(); - var newRoot = folderBrowserDialog1.SelectedPath; - - if (String.IsNullOrWhiteSpace(newRoot) == false && Directory.Exists(newRoot) == true) - { - lstRootFolders.Items.Add(newRoot); - Properties.Settings.Default.rootFolders.Add(newRoot); - Properties.Settings.Default.Save(); - } - } - - bool ScanUnityInstallations() - { - SetStatus("Scanning unity installations.."); - - // dictionary to keep version and path - unityList.Clear(); - - // installed unitys list in other tab - gridUnityList.Rows.Clear(); - - // iterate all root folders - foreach (string root in lstRootFolders.Items) - { - // var root = GetRootFolder(); - if (String.IsNullOrWhiteSpace(root) == false && Directory.Exists(root) == true) - { - // parse all folders here, and search for unity editor files - var directories = Directory.GetDirectories(root); - for (int i = 0, length = directories.Length; i < length; i++) - { - var uninstallExe = Path.Combine(directories[i], "Editor", "Uninstall.exe"); - if (File.Exists(uninstallExe) == true) - { - var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); - if (File.Exists(uninstallExe) == true) - { - var unityVersion = GetUnityVersion(uninstallExe).Replace("Unity", "").Trim(); - if (unityList.ContainsKey(unityVersion) == false) - { - unityList.Add(unityVersion, unityExe); - gridUnityList.Rows.Add(unityVersion, unityExe); - } - //Console.WriteLine(unityVersion); - } // have unity.exe - } // have uninstaller.exe - } // got folders - } // failed check - } // all root folders - - - lbl_unityCount.Text = "Founded " + unityList.Count.ToString() + " versions"; - - SetStatus("Finished scanning"); - - // founded any unity installations? - return unityList.Count > 0; - } - - - private string GetUnityVersion(string path) - { - // todo check path - FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(path); - return fvi.ProductName.Replace("(64-bit)", "").Trim(); - } - - void FilterRecentProject(object sender, EventArgs e) - { - SetStatus("Filtering recent projects list.."); - foreach (DataGridViewRow recentProject in gridRecent.Rows) - { - if (recentProject.Cells["_project"].Value.ToString().ToLower().Contains(tbSearchBar.Text.ToLower())) - recentProject.Visible = true; - else recentProject.Visible = false; - } - } - - /// - /// scans registry for recent projects and adds to project grid list - /// - void UpdateRecentProjectsList() - { - SetStatus("Updating recent projects list.."); - - gridRecent.Rows.Clear(); - - var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); - string[] registryPathsToCheck = new string[] { @"SOFTWARE\Unity Technologies\Unity Editor 5.x", @"SOFTWARE\Unity Technologies\Unity Editor 4.x" }; - - // check each version path - for (int i = 0, len = registryPathsToCheck.Length; i < len; i++) - { - RegistryKey key = hklm.OpenSubKey(registryPathsToCheck[i]); - - if (key == null) continue; - - // parse recent project path - foreach (var valueName in key.GetValueNames()) - { - if (valueName.IndexOf("RecentlyUsedProjectPaths-") == 0) - { - string projectPath = ""; - // check if binary or not - var valueKind = key.GetValueKind(valueName); - if (valueKind == RegistryValueKind.Binary) - { - byte[] projectPathBytes = (byte[])key.GetValue(valueName); - projectPath = Encoding.Default.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); - } - else // should be string then - { - projectPath = (string)key.GetValue(valueName); - } - - string projectName = ""; - - // get project name from full path - if (projectPath.IndexOf(Path.PathSeparator) > -1) - { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.PathSeparator) + 1); - } - else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) - { - projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); - } - else // no path separator founded - { - projectName = projectPath; - } - - string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); - - // editor only project - if (File.Exists(csprojFile) == false) - { - csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); - } - - // maybe 4.x project - if (File.Exists(csprojFile) == false) - { - csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); - } - - // get last modified date - DateTime? lastUpdated = GetLastModifiedTime(csprojFile); - - // get project version - string projectVersion = GetProjectVersion(projectPath); - - gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated); - gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; - } - } - } - - SetStatus("Ready"); - } - - DateTime? GetLastModifiedTime(string path) - { - if (File.Exists(path) == true) - { - DateTime modification = File.GetLastWriteTime(path); - //return modification.ToShortDateString(); - return modification; - } - else - { - return null; - } - } - - void LaunchProject(string projectPath, string version, bool openProject = true) - { - if (Directory.Exists(projectPath) == true) - { - // no assets path, probably we want to create new project then - var assetsFolder = Path.Combine(projectPath, "Assets"); - if (Directory.Exists(assetsFolder) == false) - { - // TODO could ask if want to create project.. - Directory.CreateDirectory(assetsFolder); - } - - // check for crashed backup scene first - var cancelLaunch = CheckCrashBackupScene(projectPath); - if (cancelLaunch == true) - { - return; - } - - if (HaveExactVersionInstalled(version) == true) - { - //Console.WriteLine("Opening unity version " + version); - SetStatus("Launching project in unity " + version); - - try - { - Process myProcess = new Process(); - var cmd = "\"" + unityList[version] + "\""; - myProcess.StartInfo.FileName = cmd; - if (openProject == true) - { - var pars = " -projectPath " + "\"" + projectPath + "\""; - myProcess.StartInfo.Arguments = pars; - } - myProcess.Start(); - - if (Properties.Settings.Default.closeAfterProject) - { - Environment.Exit(0); - } - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - } - else // we dont have this version installed (or no version info available) - { - SetStatus("Missing unity version: " + version); - DisplayUpgradeDialog(version, projectPath); - } - } - else // given path doesnt exists, strange - { - SetStatus("Invalid Path: " + projectPath); - } - } - - bool CheckCrashBackupScene(string projectPath) - { - var cancelRunningUnity = false; - var recoveryFile = Path.Combine(projectPath, "Temp", "__Backupscenes", "0.backup"); - if (File.Exists(recoveryFile)) - { - DialogResult dialogResult = MessageBox.Show("Crash recovery scene founded, do you want to copy it into Assets/_Recovery/-folder?", "UnityLauncher - Scene Recovery", MessageBoxButtons.YesNoCancel); - if (dialogResult == DialogResult.Yes) // restore - { - var restoreFolder = Path.Combine(projectPath, "Assets", "_Recovery"); - if (Directory.Exists(restoreFolder) == false) - { - Directory.CreateDirectory(restoreFolder); - } - if (Directory.Exists(restoreFolder) == true) - { - Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; - var uniqueFileName = "Recovered_Scene" + unixTimestamp + ".unity"; - File.Copy(recoveryFile, Path.Combine(restoreFolder, uniqueFileName)); - SetStatus("Recovered crashed scene into: " + restoreFolder); - } - else - { - SetStatus("Error: Failed to create restore folder: " + restoreFolder); - cancelRunningUnity = true; - } - } - else if (dialogResult == DialogResult.Cancel) // dont do restore, but run unity - { - cancelRunningUnity = true; - } - } - return cancelRunningUnity; - } - - // parse unity installer exe from release page - // thanks to https://github.com/softfruit - string GetDownloadUrlForUnityVersion(string releaseUrl) - { - string url = ""; - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - using (WebClient client = new WebClient()) - { - string html = client.DownloadString(releaseUrl); - Regex regex = new Regex(@"(http).+(UnityDownloadAssistant)+[^\s*]*(.exe)"); - Match match = regex.Match(html); - if (match.Success == true) - { - url = match.Groups[0].Captures[0].Value; - // Console.WriteLine(url); - } - else - { - SetStatus("Cannot find UnityDownloadAssistant.exe for this version.."); - } - } - return url; - } - - /// - /// downloads unity installer and launches it - /// - /// - void DownloadAndRun(string url) - { - string exeURL = GetDownloadUrlForUnityVersion(url); - - if (string.IsNullOrEmpty(exeURL) == false) - { - SetStatus("Download installer: " + exeURL); - // download temp file - using (WebClient downloader = new WebClient()) - { - var f = GetFileNameFromUrl(exeURL); - FileInfo fileInfo = new FileInfo(f); - downloader.DownloadFile(exeURL, f); - if (File.Exists(fileInfo.FullName)) - { - SetStatus("Running installer"); - try - { - Process myProcess = new Process(); - myProcess.StartInfo.FileName = fileInfo.FullName; - myProcess.Start(); - myProcess.WaitForExit(); - } - catch (Exception ex) - { - Console.WriteLine(ex); - SetStatus("Failed running installer"); - } - - } - } - SetStatus("Finished Running installer"); - } - else // not found - { - SetStatus("Error> Cannot find installer exe.. opening website instead"); - Process.Start(url + "#installer-exe-not-found"); - } - } - - /// - /// parse unity installer filename from url - /// - /// - /// - string GetFileNameFromUrl(string url) - { - var uri = new Uri(url); - var filename = uri.Segments.Last(); - return filename; - } - - /// - /// get rootfolder from settings, default is c:\program files\ - /// - /// - string[] GetRootFolder() - { - string[] rootFolders = null; - try - { - // if settings exists, use that - rootFolders = new string[Properties.Settings.Default.rootFolders.Count]; - Properties.Settings.Default.rootFolders.CopyTo(rootFolders, 0); - } - catch (Exception e) - { - Console.WriteLine(e); - // this doesnt work? - Properties.Settings.Default.Reset(); - Properties.Settings.Default.Save(); - } - return rootFolders; - } - - /// - /// launch windows explorer to selected project folder - /// - /// - void LaunchExplorer(string folder) - { - if (Directory.Exists(folder) == true) - { - Process.Start(folder); - } - else - { - SetStatus("Error> Directory not found: " + folder); - } - } - - void SetStatus(string msg) - { - toolStripStatusLabel1.Text = msg; - this.Refresh(); - } - - private void ShowForm() - { - this.WindowState = FormWindowState.Minimized; - this.Show(); - this.WindowState = FormWindowState.Normal; - notifyIcon.Visible = false; - } - - void LaunchSelectedProject(bool openProject = true) - { - var selected = gridRecent.CurrentCell.RowIndex; - if (selected > -1) - { - SetStatus("Launching project.."); - var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); - var version = GetProjectVersion(projectPath); - LaunchProject(projectPath, version, openProject); - SetStatus("Ready"); - } - } - - void LaunchSelectedUnity() - { - var selected = gridUnityList.CurrentCell.RowIndex; - if (selected > -1) - { - SetStatus("Launching Unity.."); - var version = gridUnityList.Rows[selected].Cells["_unityVersion"].Value.ToString(); - try - { - Process myProcess = new Process(); - var cmd = "\"" + unityList[version] + "\""; - myProcess.StartInfo.FileName = cmd; - myProcess.Start(); - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - SetStatus("Ready"); - } - } - - - string GetUnityReleaseURL(string version) - { - string url = ""; - if (version.Contains("f")) // archived - { - version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); - url = "https://unity3d.com/unity/whats-new/unity-" + version; - } - if (version.Contains("p")) // patch version - { - url = "https://unity3d.com/unity/qa/patch-releases/" + version; - } - if (version.Contains("b")) // beta version - { - url = "https://unity3d.com/unity/beta/unity" + version; - } - return url; - } - - void AddPackageFolder() - { - folderBrowserDialog1.Description = "Select package folder"; - var d = folderBrowserDialog1.ShowDialog(); - var newPackageFolder = folderBrowserDialog1.SelectedPath; - - if (String.IsNullOrWhiteSpace(newPackageFolder) == false && Directory.Exists(newPackageFolder) == true) - { - lstPackageFolders.Items.Add(newPackageFolder); - Properties.Settings.Default.packageFolders.Add(newPackageFolder); - Properties.Settings.Default.Save(); - } - } - - void AddContextMenuRegistry() - { - RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); - if (key != null) - { - var appName = "UnityLauncher"; - key.CreateSubKey(appName); - - key = key.OpenSubKey(appName, true); - key.SetValue("", "Open with UnityLauncher"); - key.SetValue("Icon", "\"" + Application.ExecutablePath + "\""); - - key.CreateSubKey("command"); - key = key.OpenSubKey("command", true); - var executeString = "\"" + Application.ExecutablePath + "\""; - executeString += " -projectPath \"%V\""; - key.SetValue("", executeString); - SetStatus("Added context menu registry items"); - } - else - { - SetStatus("Error> Cannot find registry key: " + contextRegRoot); - } - } - - void RemoveContextMenuRegistry() - { - RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); - if (key != null) - { - var appName = "UnityLauncher"; - RegistryKey appKey = Registry.CurrentUser.OpenSubKey(contextRegRoot + "\\" + appName, false); - if (appKey != null) - { - key.DeleteSubKeyTree(appName); - SetStatus("Removed context menu registry items"); - } - else - { - SetStatus("Nothing to uninstall.."); - } - } - else - { - SetStatus("Error> Cannot find registry key: " + contextRegRoot); - } - } - - #region Buttons and UI events - - private void btnRemoveRegister_Click(object sender, EventArgs e) - { - RemoveContextMenuRegistry(); - } - - private void chkMinimizeToTaskbar_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.minimizeToTaskbar = chkMinimizeToTaskbar.Checked; - Properties.Settings.Default.Save(); - } - - private void btnAddPackageFolder_Click(object sender, EventArgs e) - { - AddPackageFolder(); - } - - private void btnRemovePackFolder_Click(object sender, EventArgs e) - { - if (lstPackageFolders.SelectedIndex > -1) - { - lstPackageFolders.Items.RemoveAt(lstPackageFolders.SelectedIndex); - } - } - - private void btnOpenReleasePage_Click(object sender, EventArgs e) - { - var selected = gridUnityList.CurrentCell.RowIndex; - if (selected > -1) - { - var version = gridUnityList.Rows[selected].Cells["_unityVersion"].Value.ToString(); - OpenReleaseNotes(version); - } - } - - private void btnLaunchUnity_Click(object sender, EventArgs e) - { - LaunchSelectedUnity(); - } - - private void btnExploreUnity_Click(object sender, EventArgs e) - { - var selected = gridUnityList.CurrentCell.RowIndex; - if (selected > -1) - { - var unityPath = Path.GetDirectoryName(gridUnityList.Rows[selected].Cells["_unityPath"].Value.ToString()); - LaunchExplorer(unityPath); - } - } - - private void btnAddUnityFolder_Click(object sender, EventArgs e) - { - AddRootFolder(); - ScanUnityInstallations(); - } - - private void btnRemoveInstallFolder_Click(object sender, EventArgs e) - { - if (lstRootFolders.SelectedIndex > -1) - { - Properties.Settings.Default.rootFolders.Remove(lstRootFolders.Items[lstRootFolders.SelectedIndex].ToString()); - Properties.Settings.Default.Save(); - lstRootFolders.Items.RemoveAt(lstRootFolders.SelectedIndex); - ScanUnityInstallations(); - } - } - - private void btnFetchUnityVersions_Click(object sender, EventArgs e) - { - FetchListOfUnityUpdates(); - } - - private void unityGridView_KeyDown(object sender, KeyEventArgs e) - { - switch (e.KeyCode) - { - case Keys.Return: // launch selected unity - e.SuppressKeyPress = true; - LaunchSelectedUnity(); - break; - case Keys.F5: // refresh installed unitys list - ScanUnityInstallations(); - break; - default: - break; - } - } - - /// - /// global keys - /// - /// - /// - private void Form1_KeyPress(object sender, KeyPressEventArgs e) - { - //Console.WriteLine((int)e.KeyChar); - switch ((int)e.KeyChar) - { - case 27: // ESC - clear search - if (tabControl1.SelectedIndex == 0 && tbSearchBar.Text != "") - { - tbSearchBar.Text = ""; - } - break; - default: // any key - // activate searchbar if not active and we are in tab#1 - if (tabControl1.SelectedIndex == 0 && tbSearchBar.Focused == false) - { - // skip tab key on search field - if ((int)e.KeyChar == 9) - { - break; - } - tbSearchBar.Focus(); - tbSearchBar.Text += e.KeyChar; - tbSearchBar.Select(tbSearchBar.Text.Length, 0); - } - break; - } - } - - /// - /// grid keys - /// - /// - /// - private void gridRecent_KeyDown(object sender, KeyEventArgs e) - { - //Console.WriteLine(e.KeyValue); - switch (e.KeyCode) - { - case Keys.Return: // launch selected project - e.SuppressKeyPress = true; - LaunchSelectedProject(); - break; - case Keys.F5: // refresh recent projects list - UpdateRecentProjectsList(); - break; - default: - break; - } - } - - //Checks if you are doubleclicking the current cell - private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) - { - if (e.Button == MouseButtons.Left && e.RowIndex == gridRecent.CurrentCell.RowIndex) - { - LaunchSelectedProject(); - } - } - - // set basefolder of all unity installations - private void btn_setinstallfolder_Click(object sender, EventArgs e) - { - AddRootFolder(); - ScanUnityInstallations(); - UpdateRecentProjectsList(); - } - - private void btnLaunch_Click(object sender, EventArgs e) - { - LaunchSelectedProject(); - } - - private void Form1_Resize(object sender, EventArgs e) - { - if (chkMinimizeToTaskbar.Checked == true) - { - if (FormWindowState.Minimized == this.WindowState) - { - notifyIcon.Visible = true; - this.Hide(); - } - else if (FormWindowState.Normal == this.WindowState) - { - notifyIcon.Visible = false; - } - } - } - - private void btnRefresh_Click(object sender, EventArgs e) - { - ScanUnityInstallations(); - } - - private void notifyIcon_MouseClick(object sender, MouseEventArgs e) - { - ShowForm(); - } - - private void btn_openFolder_Click(object sender, EventArgs e) - { - var selected = gridRecent.CurrentCell.RowIndex; - if (selected > -1) - { - LaunchExplorer(gridRecent.Rows[selected].Cells["_path"].Value.ToString()); - } - } - - private void btnExplorePackageFolder_Click(object sender, EventArgs e) - { - var selected = lstPackageFolders.SelectedIndex; - //Console.WriteLine(lstPackageFolders.Items[selected].ToString()); - if (selected > -1) - { - var path = lstPackageFolders.Items[selected].ToString(); - LaunchExplorer(path); - } - } - - private void btnAddAssetStoreFolder_Click(object sender, EventArgs e) - { - var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Unity", "Asset Store-5.x"); - if (Directory.Exists(path) == true) - { - if (lstPackageFolders.Items.Contains(path) == false) - { - lstPackageFolders.Items.Add(path); - Properties.Settings.Default.packageFolders.Add(path); - Properties.Settings.Default.Save(); - } - } - } - - private void btnAddRegister_Click(object sender, EventArgs e) - { - AddContextMenuRegistry(); - } - - private void ChkQuitAfterOpen_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.closeAfterProject = ChkQuitAfterOpen.Checked; - Properties.Settings.Default.Save(); - } - - private void chkQuitAfterCommandline_CheckedChanged(object sender, EventArgs e) - { - Properties.Settings.Default.closeAfterExplorer = chkQuitAfterCommandline.Checked; - Properties.Settings.Default.Save(); - } - - private void btnRunUnityOnly_Click(object sender, EventArgs e) - { - LaunchSelectedProject(openProject: false); - } - - private void btnUpgradeProject_Click(object sender, EventArgs e) - { - UpgradeProject(); - } - - private void btnOpenLogFolder_Click(object sender, EventArgs e) - { - var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Unity", "Editor"); - //Console.WriteLine(logfolder); - if (Directory.Exists(logfolder) == true) - { - LaunchExplorer(logfolder); - } - } - - private void gridRecent_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) - { - List gridWidths = new List(Properties.Settings.Default.gridColumnWidths); - // restore data grid view widths - var colum = gridRecent.Columns[0]; - for (int i = 0; i < gridRecent.Columns.Count; ++i) - { - if (Properties.Settings.Default.gridColumnWidths.Length > i) - { - gridWidths[i] = gridRecent.Columns[i].Width; - } - else - { - gridWidths.Add(gridRecent.Columns[i].Width); - } - } - Properties.Settings.Default.gridColumnWidths = gridWidths.ToArray(); - Properties.Settings.Default.Save(); - } - - private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) - { - var selected = gridUnityUpdates?.CurrentCell?.RowIndex; - if (selected != null && selected > -1) - { - var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); - OpenReleaseNotes(version); - } - } - - private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) - { - // if enter Updates tab, then automatically fetch list of unity versions if list is empty (not fetched) - if (((TabControl)sender).SelectedIndex == 3) // FIXME: fixed index 3 for this tab.. - { - if (gridUnityUpdates.Rows.Count == 0) - { - FetchListOfUnityUpdates(); - } - } - } - - private void Form1_ResizeEnd(object sender, EventArgs e) - { - var form = (Form)sender; - Properties.Settings.Default.formWidth = form.Size.Width; - Properties.Settings.Default.formHeight = form.Size.Height; - Properties.Settings.Default.Save(); - } - - - #endregion UI events - - - - void OpenReleaseNotes(string version) - { - SetStatus("Opening release notes for version " + version); - var url = GetUnityReleaseURL(version); - if (string.IsNullOrEmpty(url) == false) - { - Process.Start(url); - } - else - { - SetStatus("Failed opening Release Notes URL for version " + version); - } - } - - public static string FindNearestVersion(string version, List allAvailable) - { - if (version.Contains("2017")) - { - return FindNearestVersionFromSimilarVersions(version, allAvailable.Where(x => x.Contains("2017"))); - } - return FindNearestVersionFromSimilarVersions(version, allAvailable.Where(x => !x.Contains("2017"))); - } - - private static string FindNearestVersionFromSimilarVersions(string version, IEnumerable allAvailable) - { - Dictionary stripped = new Dictionary(); - var enumerable = allAvailable as string[] ?? allAvailable.ToArray(); - - foreach (var t in enumerable) - { - stripped.Add(new Regex("[a-zA-z]").Replace(t, "."), t); - } - - var comparableVersion = new Regex("[a-zA-z]").Replace(version, "."); - if (!stripped.ContainsKey(comparableVersion)) - { - stripped.Add(comparableVersion, version); - } - - var comparables = stripped.Keys.OrderBy(x => x).ToList(); - var actualIndex = comparables.IndexOf(comparableVersion); - - if (actualIndex < stripped.Count - 1) return stripped[comparables[actualIndex + 1]]; - return null; - } - - // displays version selector to upgrade project - void UpgradeProject() - { - var selected = gridRecent.CurrentCell.RowIndex; - if (selected > -1) - { - SetStatus("Upgrading project.."); - - var projectPath = gridRecent.Rows[selected].Cells["_path"].Value.ToString(); - var currentVersion = GetProjectVersion(projectPath); - - if (string.IsNullOrEmpty(currentVersion) == true) - { - // TODO no version info available, should handle errors? - } - else // have version info - { - bool haveExactVersion = HaveExactVersionInstalled(currentVersion); - if (haveExactVersion == true) - { - // you already have exact version, are you sure about upgrade? - } - } - DisplayUpgradeDialog(currentVersion, projectPath, true); - } - } - - void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launchProject = true) - { - // display upgrade dialog (version selector) - Form2 upgradeDialog = new Form2(); - Form2.currentVersion = currentVersion; - - // check what user selected - var results = upgradeDialog.ShowDialog(this); - switch (results) - { - case DialogResult.Ignore: // view release notes page - OpenReleaseNotes(currentVersion); - // display window again for now.. - DisplayUpgradeDialog(currentVersion, projectPath, launchProject); - break; - case DialogResult.Cancel: // cancelled - SetStatus("Cancelled project upgrade"); - break; - case DialogResult.Retry: // download and install missing version - SetStatus("Download and Install missing version " + currentVersion); - string url = GetUnityReleaseURL(currentVersion); - if (string.IsNullOrEmpty(url) == false) - { - DownloadAndRun(url); - } - else - { - SetStatus("Failed getting Unity Installer URL"); - } - break; - case DialogResult.Yes: // upgrade - SetStatus("Upgrading project to " + Form2.currentVersion); - if (launchProject == true) LaunchProject(projectPath, Form2.currentVersion); - break; - default: - Console.WriteLine("Unknown DialogResult: " + results); - break; - } - upgradeDialog.Close(); - } - - void FetchListOfUnityUpdates() - { - if (isDownloadUnityList == true) - { - SetStatus("We are already downloading.."); - return; - } - isDownloadUnityList = true; - SetStatus("Downloading list of unity versions.."); - - // download list of unity versions - using (WebClient webClient = new WebClient()) - { - webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(UnityVersionsListDownloaded); - var unityVersionsURL = @"http://symbolserver.unity3d.com/000Admin/history.txt"; - webClient.DownloadStringAsync(new Uri(unityVersionsURL)); - } - } - - private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedEventArgs e) - { - // TODO check for error.. - SetStatus("Downloading list of unity versions..Done"); - isDownloadUnityList = false; - // parse to list - var unityList = e.Result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - Array.Reverse(unityList); - gridUnityUpdates.Rows.Clear(); - for (int i = 0, len = unityList.Length; i < len; i++) - { - var row = unityList[i].Split(','); - gridUnityUpdates.Rows.Add(row[3], row[6].Trim('"')); - } - } - } -} +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using UnityLauncherTools; + +namespace UnityLauncher +{ + public partial class Form1 : Form + { + public static Dictionary unityList = new Dictionary(); + const string contextRegRoot = "Software\\Classes\\Directory\\Background\\shell"; + const string launcherArgumentsFile = "LauncherArguments.txt"; + const string githubReleasesLinkURL = "https://github.com/unitycoder/UnityLauncher/releases"; + + bool isDownloadingUnityList = false; + string previousGitRelease = "0"; + + + public Form1() + { + InitializeComponent(); + } + + private void Form1_Load(object sender, EventArgs e) + { + Start(); + } + + + + void Start() + { + SetStatus("Initializing ..."); + // check installations folder + var root = GetUnityInstallationsRootFolder(); + if (root == null || root.Length == 0) + { + SetStatus("Missing root folder ..."); + AddUnityInstallationRootFolder(); + SetStatus("Ready"); + } + + LoadSettings(); + + // scan installed unitys + bool foundUnitys = ScanUnityInstallations(); + if (foundUnitys == false) + { + SetStatus("Error> Did not find any Unity installations, try setting correct root folder ..."); + UpdateRecentProjectsList(); + tabControl1.SelectedIndex = tabControl1.TabCount - 1; // last tab is settings + return; + } + + + + // check if received -projectPath argument (that means opening from explorer / cmdline) + string[] args = Environment.GetCommandLineArgs(); + if (args != null && args.Length > 2) + { + // first argument needs to be -projectPath + var commandLineArgs = args[1]; + if (commandLineArgs == "-projectPath") + { + SetStatus("Launching from commandline ..."); + + // path + var projectPathArgument = args[2]; + + // resolve full path if path parameter isn't a rooted path + if (!Path.IsPathRooted(projectPathArgument)) + { + projectPathArgument = Directory.GetCurrentDirectory() + projectPathArgument; + } + + var version = Tools.GetProjectVersion(projectPathArgument); + + // take extra arguments also + var commandLineArguments = ""; + for (int i = 3, len = args.Length; i < len; i++) + { + commandLineArguments += " " + args[i]; + } + + // check if force-update button is down + if ((Control.ModifierKeys & Keys.Shift) != 0) + { + DisplayUpgradeDialog(version, projectPathArgument, launchProject: true, commandLineArguments: commandLineArguments); + } + else + { + // try launching it + LaunchProject(projectPathArgument, version, openProject: true, commandLineArguments: commandLineArguments); + } + + + // quit after launch if enabled in settings + if (Properties.Settings.Default.closeAfterExplorer == true) + { + Application.Exit(); + } + + //SetStatus("Ready"); + } + else + { + SetStatus("Error> Invalid arguments:" + args[1]); + } + } + + UpdateRecentProjectsList(); + + // preselect grid + gridRecent.Select(); + + // get previous version build info string + // this string is release tag for latest release when this app was compiled + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("UnityLauncher." + "PreviousVersion.txt")) + using (StreamReader reader = new StreamReader(stream)) + { + previousGitRelease = reader.ReadToEnd().Trim(); + } + } + + void LoadSettings() + { + // form size + this.Width = Properties.Settings.Default.formWidth; + this.Height = Properties.Settings.Default.formHeight; + + // update settings window + chkMinimizeToTaskbar.Checked = Properties.Settings.Default.minimizeToTaskbar; + chkQuitAfterCommandline.Checked = Properties.Settings.Default.closeAfterExplorer; + ChkQuitAfterOpen.Checked = Properties.Settings.Default.closeAfterProject; + chkShowLauncherArgumentsColumn.Checked = Properties.Settings.Default.showArgumentsColumn; + chkShowGitBranchColumn.Checked = Properties.Settings.Default.showGitBranchColumn; + chkDarkSkin.Checked = Properties.Settings.Default.useDarkSkin; + + // update optional grid columns, hidden or visible + gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; + gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; + + // update installations folder listbox + lstRootFolders.Items.Clear(); + lstRootFolders.Items.AddRange(Properties.Settings.Default.rootFolders.Cast().ToArray()); + // update packages folder listbox + lstPackageFolders.Items.AddRange(Properties.Settings.Default.packageFolders.Cast().ToArray()); + + // restore data grid view widths + int[] gridColumnWidths = Properties.Settings.Default.gridColumnWidths; + if (gridColumnWidths != null) + { + + for (int i = 0; i < gridColumnWidths.Length; ++i) + { + gridRecent.Columns[i].Width = gridColumnWidths[i]; + } + } + + // TODO assign colors for dark theme + if (chkDarkSkin.Checked == true) + { + var darkBg = Color.FromArgb(32, 37, 41); + var darkRaised = Color.FromArgb(50, 56, 61); + var darkBright = Color.FromArgb(161, 180, 196); + + + this.BackColor = darkBg; + tabProjects.BackColor = darkRaised; + gridRecent.BackgroundColor = darkRaised; + + gridRecent.GridColor = darkBg; + var dgs = new DataGridViewCellStyle(); + dgs.BackColor = darkRaised; + dgs.ForeColor = darkBright; + gridRecent.DefaultCellStyle = dgs; + + statusStrip1.BackColor = darkRaised; + } + } + + /// + /// returns true if we have exact version installed + /// + /// + /// + bool HaveExactVersionInstalled(string version) + { + return string.IsNullOrEmpty(version) == false && unityList.ContainsKey(version); + } + + + void AddUnityInstallationRootFolder() + { + folderBrowserDialog1.Description = "Select Unity installations root folder"; + var d = folderBrowserDialog1.ShowDialog(); + var newRoot = folderBrowserDialog1.SelectedPath; + + if (String.IsNullOrWhiteSpace(newRoot) == false && Directory.Exists(newRoot) == true) + { + lstRootFolders.Items.Add(newRoot); + Properties.Settings.Default.rootFolders.Add(newRoot); + Properties.Settings.Default.Save(); + } + } + + bool ScanUnityInstallations() + { + SetStatus("Scanning Unity installations ..."); + + // dictionary to keep version and path + unityList.Clear(); + + // installed unitys list in other tab + gridUnityList.Rows.Clear(); + + // iterate all root folders + foreach (string root in lstRootFolders.Items) + { + if (String.IsNullOrWhiteSpace(root) == false && Directory.Exists(root) == true) + { + // parse all folders here, and search for unity editor files + var directories = Directory.GetDirectories(root); + for (int i = 0, length = directories.Length; i < length; i++) + { + var uninstallExe = Path.Combine(directories[i], "Editor", "Uninstall.exe"); + if (File.Exists(uninstallExe) == true) + { + var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); + if (File.Exists(unityExe) == true) + { + // get full version number from uninstaller + var unityVersion = Tools.GetFileVersionData(uninstallExe).Replace("Unity", "").Trim(); + if (unityList.ContainsKey(unityVersion) == false) + { + unityList.Add(unityVersion, unityExe); + var dataFolder = Path.Combine(directories[i], "Editor", "Data"); + DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); + // TODO add platforms: PC|iOS|tvOS|Android|UWP|WebGL|Facebook|XBox|PSVita|PS4 + gridUnityList.Rows.Add(unityVersion, unityExe, installDate); + } + } // have unity.exe + } // have uninstaller.exe + else // no uninstaller, probably preview builds + { + var unityExe = Path.Combine(directories[i], "Editor", "Unity.exe"); + if (File.Exists(unityExe) == true) + { + // get full version number from uninstaller + var unityVersion = Tools.GetFileVersionData(unityExe).Replace("Unity", "").Trim(); + if (unityList.ContainsKey(unityVersion) == false) + { + unityList.Add(unityVersion, unityExe); + var dataFolder = Path.Combine(directories[i], "Editor", "Data"); + DateTime? installDate = Tools.GetLastModifiedTime(dataFolder); + // TODO add platforms: PC|iOS|tvOS|Android|UWP|WebGL|Facebook|XBox|PSVita|PS4 + gridUnityList.Rows.Add(unityVersion, unityExe, installDate); + } + } // have unity.exe + } + } // got folders + } // failed check + } // all root folders + + lbl_unityCount.Text = "Found " + unityList.Count.ToString() + " versions"; + + SetStatus("Finished scanning"); + + // found any Unity installations? + return unityList.Count > 0; + } + + + void FilterRecentProject(object sender, EventArgs e) + { + SetStatus("Filtering recent projects list ..."); + string searchString = tbSearchBar.Text; + + foreach (DataGridViewRow row in gridRecent.Rows) + { + if (row.Cells["_project"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) + { + row.Visible = true; + } + else + { + row.Visible = false; + } + } + + lblClearSearchField.Visible = tbSearchBar.Text.Length > 0; + + } + + void FilterUnityUpdates(object sender, EventArgs e) + { + SetStatus("Filtering Unity updates list ..."); + string searchString = tbSearchUpdates.Text; + foreach (DataGridViewRow row in gridUnityUpdates.Rows) + { + if (row.Cells["_UnityUpdateVersion"].Value.ToString().IndexOf(searchString, StringComparison.OrdinalIgnoreCase) > -1) + { + row.Visible = true; + } + else + { + row.Visible = false; + } + } + } + + /// + /// scans registry for recent projects and adds to project grid list + /// + void UpdateRecentProjectsList() + { + SetStatus("Updating recent projects list ..."); + + gridRecent.Rows.Clear(); + + var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); + string[] registryPathsToCheck = new string[] { @"SOFTWARE\Unity Technologies\Unity Editor 5.x", @"SOFTWARE\Unity Technologies\Unity Editor 4.x" }; + + // check each version path + for (int i = 0, len = registryPathsToCheck.Length; i < len; i++) + { + RegistryKey key = hklm.OpenSubKey(registryPathsToCheck[i]); + + if (key == null) + { + continue; + } + else + { + //Console.WriteLine("Null registry key at " + registryPathsToCheck[i]); + } + + // parse recent project path + foreach (var valueName in key.GetValueNames()) + { + if (valueName.IndexOf("RecentlyUsedProjectPaths-") == 0) + { + string projectPath = ""; + // check if binary or not + var valueKind = key.GetValueKind(valueName); + if (valueKind == RegistryValueKind.Binary) + { + byte[] projectPathBytes = (byte[])key.GetValue(valueName); + projectPath = Encoding.UTF8.GetString(projectPathBytes, 0, projectPathBytes.Length - 1); + } + else // should be string then + { + projectPath = (string)key.GetValue(valueName); + } + + // first check if whole folder exists, if not, skip + if (Directory.Exists(projectPath) == false) + { + //Console.WriteLine("Recent project directory not found, skipping: " + projectPath); + continue; + } + + string projectName = ""; + + // get project name from full path + if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); + } + else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); + } + else // no path separator found + { + projectName = projectPath; + } + + string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); + + // solution only + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".sln"); + } + + // editor only project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); + } + + // maybe 4.x project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); + } + + // get last modified date + DateTime? lastUpdated = Tools.GetLastModifiedTime(csprojFile); + + // get project version + string projectVersion = Tools.GetProjectVersion(projectPath); + + // get custom launch arguments, only if column in enabled + string customArgs = ""; + if (chkShowLauncherArgumentsColumn.Checked == true) + { + customArgs = Tools.ReadCustomLaunchArguments(projectPath, launcherArgumentsFile); + } + + // get git branchinfo, only if column in enabled + string gitBranch = ""; + if (chkShowGitBranchColumn.Checked == true) + { + gitBranch = Tools.ReadGitBranchInfo(projectPath); + } + + gridRecent.Rows.Add(projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); + gridRecent.Rows[gridRecent.Rows.Count - 1].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; + } + } + } + //SetStatus("Ready"); + } + + void LaunchProject(string projectPath, string version, bool openProject = true, string commandLineArguments = "") + { + if (Directory.Exists(projectPath) == true) + { + // no assets path, probably we want to create new project then + var assetsFolder = Path.Combine(projectPath, "Assets"); + if (Directory.Exists(assetsFolder) == false) + { + // TODO could ask if want to create project.. + Directory.CreateDirectory(assetsFolder); + } + + // when opening project, check for crashed backup scene first + if (openProject == true) + { + var cancelLaunch = CheckCrashBackupScene(projectPath); + if (cancelLaunch == true) + { + return; + } + } + + if (HaveExactVersionInstalled(version) == true) + { + if (openProject == true) + { + SetStatus("Launching project in Unity " + version); + } + else + { + SetStatus("Launching Unity " + version); + } + + try + { + Process myProcess = new Process(); + var cmd = "\"" + unityList[version] + "\""; + myProcess.StartInfo.FileName = cmd; + if (openProject == true) + { + var pars = " -projectPath " + "\"" + projectPath + "\""; + + // check for custom launch parameters and append them + string customArguments = GetSelectedRowData("_launchArguments"); + if (string.IsNullOrEmpty(customArguments) == false) + { + pars += " " + customArguments; + } + + myProcess.StartInfo.Arguments = pars + commandLineArguments; + } + myProcess.Start(); + + if (Properties.Settings.Default.closeAfterProject) + { + Environment.Exit(0); + } + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + else // we dont have this version installed (or no version info available) + { + SetStatus("Missing Unity version: " + version); + // if only running only, stop here + if (openProject == true) DisplayUpgradeDialog(version, projectPath); + } + } + else // given path doesnt exists, strange + { + SetStatus("Invalid path: " + projectPath); + } + } + + bool CheckCrashBackupScene(string projectPath) + { + var cancelRunningUnity = false; + var recoveryFile = Path.Combine(projectPath, "Temp", "__Backupscenes", "0.backup"); + if (File.Exists(recoveryFile)) + { + DialogResult dialogResult = MessageBox.Show("Crash recovery scene found, do you want to copy it into Assets/_Recovery/-folder?", "UnityLauncher - Scene Recovery", MessageBoxButtons.YesNoCancel); + if (dialogResult == DialogResult.Yes) // restore + { + var restoreFolder = Path.Combine(projectPath, "Assets", "_Recovery"); + if (Directory.Exists(restoreFolder) == false) + { + Directory.CreateDirectory(restoreFolder); + } + if (Directory.Exists(restoreFolder) == true) + { + Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; + var uniqueFileName = "Recovered_Scene" + unixTimestamp + ".unity"; + File.Copy(recoveryFile, Path.Combine(restoreFolder, uniqueFileName)); + SetStatus("Recovered crashed scene into: " + restoreFolder); + } + else + { + SetStatus("Error: Failed to create restore folder: " + restoreFolder); + cancelRunningUnity = true; + } + } + else if (dialogResult == DialogResult.Cancel) // dont do restore, but run Unity + { + cancelRunningUnity = true; + } + } + return cancelRunningUnity; + } + + // parse Unity installer exe from release page + // thanks to https://github.com/softfruit + string ParseDownloadURLFromWebpage(string version) + { + string url = ""; + + using (WebClient client = new WebClient()) + { + // get correct page url + string website = "https://unity3d.com/get-unity/download/archive"; + if (Tools.VersionIsPatch(version)) website = "https://unity3d.com/unity/qa/patch-releases"; + if (Tools.VersionIsBeta(version)) website = "https://unity3d.com/unity/beta/" + version; + if (Tools.VersionIsAlpha(version)) website = "https://unity3d.com/unity/alpha/" + version; + + // download html + string sourceHTML = client.DownloadString(website); + string[] lines = sourceHTML.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + + // patch version download assistant finder + if (Tools.VersionIsPatch(version)) + { + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].Contains("UnityDownloadAssistant-" + version + ".exe")) + { + int start = lines[i].IndexOf('"') + 1; + int end = lines[i].IndexOf('"', start); + url = lines[i].Substring(start, end - start); + break; + } + } + } + else if (Tools.VersionIsArchived(version)) + { + // archived version download assistant finder + for (int i = 0; i < lines.Length; i++) + { + // find line where full installer is (from archive page) + if (lines[i].Contains("UnitySetup64-" + version)) + { + // take previous line, which contains download assistant url + string line = lines[i - 1]; + int start = line.IndexOf('"') + 1; + int end = line.IndexOf('"', start); + url = @"https://unity3d.com" + line.Substring(start, end - start); + break; + } + } + } + else // alpha or beta version download assistant finder + { + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].Contains("UnityDownloadAssistant.exe")) + { + int start = lines[i].IndexOf('"') + 1; + int end = lines[i].IndexOf('"', start); + url = lines[i].Substring(start, end - start) + "#version=" + version; + break; + } + } + } + } + + // didnt find installer + if (string.IsNullOrEmpty(url)) + { + SetStatus("Cannot find UnityDownloadAssistant.exe for this version."); + } + + return url; + } + + /// + /// launches browser to download installer + /// + /// full url to installer + void DownloadInBrowser(string url, string version) + { + string exeURL = ParseDownloadURLFromWebpage(version); + + if (string.IsNullOrEmpty(exeURL) == false) + { + SetStatus("Download installer in browser: " + exeURL); + Process.Start(exeURL); + } + else // not found + { + SetStatus("Error> Cannot find installer executable ... opening website instead"); + url = "https://unity3d.com/get-unity/download/archive"; + Process.Start(url + "#installer-not-found---version-" + version); + } + } + + /// + /// get rootfolder from settings, default is c:\program files\ + /// + /// + string[] GetUnityInstallationsRootFolder() + { + string[] rootFolders = null; + try + { + // if settings exists, use that value + rootFolders = new string[Properties.Settings.Default.rootFolders.Count]; + Properties.Settings.Default.rootFolders.CopyTo(rootFolders, 0); + } + catch (Exception e) + { + MessageBox.Show("Rare error while checking Unity installation folder settings: " + e.Message, "UnityLauncher", MessageBoxButtons.OK); + + // this doesnt work? + Properties.Settings.Default.Reset(); + Properties.Settings.Default.Save(); + } + return rootFolders; + } + + void SetStatus(string msg) + { + toolStripStatusLabel1.Text = msg; + this.Refresh(); + } + + private void ShowForm() + { + this.WindowState = FormWindowState.Minimized; + this.Show(); + this.WindowState = FormWindowState.Normal; + notifyIcon.Visible = false; + } + + void LaunchSelectedProject(bool openProject = true) + { + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + + if (selected.HasValue && selected > -1) + { + var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); + var version = Tools.GetProjectVersion(projectPath); + Console.WriteLine("version: '" + version + "'"); + LaunchProject(projectPath, version, openProject); + //SetStatus("Ready"); + } + } + + void LaunchSelectedUnity() + { + + var selected = gridUnityList?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); + SetStatus("Launching Unity: " + version); + try + { + Process myProcess = new Process(); + var cmd = "\"" + unityList[version] + "\""; + myProcess.StartInfo.FileName = cmd; + myProcess.Start(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + //SetStatus("Ready"); + } + } + + void AddPackageFolder() + { + folderBrowserDialog1.Description = "Select package folder"; + var d = folderBrowserDialog1.ShowDialog(); + var newPackageFolder = folderBrowserDialog1.SelectedPath; + + if (String.IsNullOrWhiteSpace(newPackageFolder) == false && Directory.Exists(newPackageFolder) == true) + { + lstPackageFolders.Items.Add(newPackageFolder); + Properties.Settings.Default.packageFolders.Add(newPackageFolder); + Properties.Settings.Default.Save(); + } + } + + + #region Buttons and UI events + + private void btnRemoveRegister_Click(object sender, EventArgs e) + { + Tools.RemoveContextMenuRegistry(contextRegRoot); + } + + private void chkMinimizeToTaskbar_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.minimizeToTaskbar = chkMinimizeToTaskbar.Checked; + Properties.Settings.Default.Save(); + } + + + + private void btnAddPackageFolder_Click(object sender, EventArgs e) + { + AddPackageFolder(); + } + + private void btnRemovePackFolder_Click(object sender, EventArgs e) + { + if (lstPackageFolders.SelectedIndex > -1) + { + lstPackageFolders.Items.RemoveAt(lstPackageFolders.SelectedIndex); + } + } + + private void btnOpenReleasePage_Click(object sender, EventArgs e) + { + var selected = gridUnityList?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var version = gridUnityList.Rows[(int)selected].Cells["_unityVersion"].Value.ToString(); + if (Tools.OpenReleaseNotes(version) == true) + { + SetStatus("Opening release notes for version " + version); + } + else + { + SetStatus("Failed opening Release Notes URL for version " + version); + } + } + } + + private void btnLaunchUnity_Click(object sender, EventArgs e) + { + LaunchSelectedUnity(); + } + + private void btnExploreUnity_Click(object sender, EventArgs e) + { + + var selected = gridUnityList?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var unityPath = Path.GetDirectoryName(gridUnityList.Rows[(int)selected].Cells["_unityPath"].Value.ToString()); + if (Tools.LaunchExplorer(unityPath) == false) + { + SetStatus("Error> Directory not found: " + unityPath); + } + } + } + + private void btnAddUnityFolder_Click(object sender, EventArgs e) + { + AddUnityInstallationRootFolder(); + ScanUnityInstallations(); + UpdateRecentProjectsList(); + } + + private void btnRemoveInstallFolder_Click(object sender, EventArgs e) + { + if (lstRootFolders.SelectedIndex > -1) + { + Properties.Settings.Default.rootFolders.Remove(lstRootFolders.Items[lstRootFolders.SelectedIndex].ToString()); + Properties.Settings.Default.Save(); + lstRootFolders.Items.RemoveAt(lstRootFolders.SelectedIndex); + ScanUnityInstallations(); + } + } + + private void btnFetchUnityVersions_Click(object sender, EventArgs e) + { + FetchListOfUnityUpdates(); + } + + int lastKnownSelectedRow = -1; + private void unityGridView_KeyDown(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Return: // launch selected Unity + e.SuppressKeyPress = true; + LaunchSelectedUnity(); + break; + case Keys.F5: // refresh installed Unity versions list + ScanUnityInstallations(); + UpdateRecentProjectsList(); + break; + default: + break; + } + } + + /// + /// global keys + /// + /// + /// + private void Form1_KeyPress(object sender, KeyPressEventArgs e) + { + // if editing cells, dont focus on search + if (gridRecent.IsCurrentCellInEditMode == true) return; + + switch ((int)e.KeyChar) + { + case 27: // ESCAPE - clear search + if (tabControl1.SelectedIndex == 0 && tbSearchBar.Text != "") + { + tbSearchBar.Text = ""; + lblClearSearchField.Visible = false; + } + else if (tabControl1.SelectedIndex == 3 && tbSearchUpdates.Text != "") + { + tbSearchUpdates.Text = ""; + } + break; + default: // any key + // activate searchbar if not active and we are in tab#1 + if (tabControl1.SelectedIndex == 0 && tbSearchBar.Focused == false) + { + // skip tab key on search field + if ((int)e.KeyChar == 9) + { + break; + } + tbSearchBar.Focus(); + tbSearchBar.Text += e.KeyChar; + tbSearchBar.Select(tbSearchBar.Text.Length, 0); + lblClearSearchField.Visible = tbSearchBar.Text.Length > 0; + } + break; + } + } + + /// + /// grid keys + /// + /// + /// + private void gridRecent_KeyDown(object sender, KeyEventArgs e) + { + // if editing cells, dont search or launch + if (gridRecent.IsCurrentCellInEditMode == true) return; + + switch (e.KeyCode) + { + case Keys.Return: // launch selected project + e.SuppressKeyPress = true; + LaunchSelectedProject(); + break; + case Keys.F5: // refresh recent projects list + lastKnownSelectedRow = GetSelectedRowIndex(); + Console.WriteLine(lastKnownSelectedRow); + UpdateRecentProjectsList(); + SetSelectedRowIndex(lastKnownSelectedRow); + break; + default: + break; + } + } + + //Checks if you are doubleclicking the current cell + private void GridRecent_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) + { + if (e.Button == MouseButtons.Left && e.RowIndex == gridRecent.CurrentCell.RowIndex) + { + LaunchSelectedProject(); + } + } + + // set basefolder of all Unity installations + private void btn_setinstallfolder_Click(object sender, EventArgs e) + { + AddUnityInstallationRootFolder(); + ScanUnityInstallations(); + UpdateRecentProjectsList(); + } + + private void btnLaunch_Click(object sender, EventArgs e) + { + LaunchSelectedProject(); + } + + private void Form1_Resize(object sender, EventArgs e) + { + if (chkMinimizeToTaskbar.Checked == true) + { + if (FormWindowState.Minimized == this.WindowState) + { + notifyIcon.Visible = true; + this.Hide(); + } + else if (FormWindowState.Normal == this.WindowState) + { + notifyIcon.Visible = false; + } + } + } + + private void btnRefresh_Click(object sender, EventArgs e) + { + ScanUnityInstallations(); + UpdateRecentProjectsList(); + } + + private void notifyIcon_MouseClick(object sender, MouseEventArgs e) + { + ShowForm(); + } + + private void btn_openFolder_Click(object sender, EventArgs e) + { + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + string folder = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); + if (Tools.LaunchExplorer(folder) == false) + { + SetStatus("Error> Directory not found: " + folder); + } + } + } + + private void btnExplorePackageFolder_Click(object sender, EventArgs e) + { + var selected = lstPackageFolders.SelectedIndex; + //Console.WriteLine(lstPackageFolders.Items[selected].ToString()); + if (selected > -1) + { + string folder = lstPackageFolders.Items[selected].ToString(); + if (Tools.LaunchExplorer(folder) == false) + { + SetStatus("Error> Directory not found: " + folder); + } + } + } + + private void btnAddAssetStoreFolder_Click(object sender, EventArgs e) + { + var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Unity", "Asset Store-5.x"); + if (Directory.Exists(path) == true) + { + if (lstPackageFolders.Items.Contains(path) == false) + { + lstPackageFolders.Items.Add(path); + Properties.Settings.Default.packageFolders.Add(path); + Properties.Settings.Default.Save(); + } + } + } + + private void btnAddRegister_Click(object sender, EventArgs e) + { + Tools.AddContextMenuRegistry(contextRegRoot); + } + + private void ChkQuitAfterOpen_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.closeAfterProject = ChkQuitAfterOpen.Checked; + Properties.Settings.Default.Save(); + } + + private void chkQuitAfterCommandline_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.closeAfterExplorer = chkQuitAfterCommandline.Checked; + Properties.Settings.Default.Save(); + } + + private void chkDarkSkin_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.useDarkSkin = chkDarkSkin.Checked; + Properties.Settings.Default.Save(); + } + + private void btnRunUnityOnly_Click(object sender, EventArgs e) + { + LaunchSelectedProject(openProject: false); + } + + private void btnUpgradeProject_Click(object sender, EventArgs e) + { + UpgradeProject(); + } + + private void btnOpenLogFolder_Click(object sender, EventArgs e) + { + var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Unity", "Editor"); + if (Directory.Exists(logfolder) == true) + { + if (Tools.LaunchExplorer(logfolder) == false) + { + SetStatus("Error> Directory not found: " + logfolder); + } + } + } + + private void btnOpenUpdateWebsite_Click(object sender, EventArgs e) + { + FixSelectedRow(); + var selected = gridUnityUpdates?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); + Tools.OpenReleaseNotes(version); + } + } + + private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) + { + // if enter Updates tab, then automatically fetch list of Unity versions if list is empty (not fetched) + if (((TabControl)sender).SelectedIndex == 3) // FIXME: fixed index 3 for this tab.. + { + if (gridUnityUpdates.Rows.Count == 0) + { + FetchListOfUnityUpdates(); + } + } + } + + private void Form1_ResizeEnd(object sender, EventArgs e) + { + var form = (Form)sender; + Properties.Settings.Default.formWidth = form.Size.Width; + Properties.Settings.Default.formHeight = form.Size.Height; + Properties.Settings.Default.Save(); + } + + private void checkShowLauncherArgumentsColumn_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.showArgumentsColumn = chkShowLauncherArgumentsColumn.Checked; + Properties.Settings.Default.Save(); + gridRecent.Columns["_launchArguments"].Visible = chkShowLauncherArgumentsColumn.Checked; + // reload list data, if enabled (otherwise missing data) + if (chkShowLauncherArgumentsColumn.Checked == true) UpdateRecentProjectsList(); + } + + private void checkShowGitBranchColumn_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default.showGitBranchColumn = chkShowGitBranchColumn.Checked; + Properties.Settings.Default.Save(); + gridRecent.Columns["_gitBranch"].Visible = chkShowGitBranchColumn.Checked; + // reload list data, if enabled (otherwise missing data) + if (chkShowGitBranchColumn.Checked == true) UpdateRecentProjectsList(); + } + + + private void linkArgumentsDocs_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Tools.OpenURL("https://docs.unity3d.com/Manual/CommandLineArguments.html"); + } + + private void linkProjectGithub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Tools.OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); + } + + + // after editing launch arguments cell + private void gridRecent_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + string path = GetSelectedRowData("_path"); + if (string.IsNullOrEmpty(path)) return; + + string arguments = GetSelectedRowData("_launchArguments"); + + // check folder first + string outputFolder = Path.Combine(path, "ProjectSettings"); + if (Directory.Exists(outputFolder) == false) + { + Directory.CreateDirectory(outputFolder); + } + + // save arguments to projectsettings folder + string outputFile = Path.Combine(path, "ProjectSettings", launcherArgumentsFile); + + try + { + StreamWriter sw = new StreamWriter(outputFile); + sw.WriteLine(arguments); + sw.Close(); + } + catch (Exception exception) + { + SetStatus("File error: " + exception.Message); + } + + // select the same row again (dont move to next), doesnt work here + // var previousRow = gridRecent.CurrentCell.RowIndex; + // gridRecent.Rows[previousRow].Selected = true; + } + + private void btnCheckUpdates_Click(object sender, EventArgs e) + { + Tools.OpenURL("https://github.com/unitycoder/UnityLauncher/releases"); + } + + private void btnRefreshProjectList_Click(object sender, EventArgs e) + { + UpdateRecentProjectsList(); + } + + private void btnBrowseForProject_Click(object sender, EventArgs e) + { + BrowseForExistingProjectFolder(); + } + + private void Form1_FormClosing(object sender, FormClosingEventArgs e) + { + SaveSettingsOnExit(); + } + + #endregion UI events + + + + + // displays version selector to upgrade project + void UpgradeProject() + { + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + SetStatus("Upgrading project ..."); + + var projectPath = gridRecent.Rows[(int)selected].Cells["_path"].Value.ToString(); + var currentVersion = Tools.GetProjectVersion(projectPath); + + if (string.IsNullOrEmpty(currentVersion) == true) + { + // TODO no version info available, should handle errors? + } + else // have version info + { + bool haveExactVersion = HaveExactVersionInstalled(currentVersion); + if (haveExactVersion == true) + { + // you already have exact version, are you sure about upgrade? + } + } + DisplayUpgradeDialog(currentVersion, projectPath, true); + } + } + + void DisplayUpgradeDialog(string currentVersion, string projectPath, bool launchProject = true, string commandLineArguments = "") + { + // display upgrade dialog (version selector) + Form2 upgradeDialog = new Form2(); + Form2.currentVersion = currentVersion; + + // check what user selected + var results = upgradeDialog.ShowDialog(this); + switch (results) + { + case DialogResult.Ignore: // view release notes page + Tools.OpenReleaseNotes(currentVersion); + // display window again for now.. + DisplayUpgradeDialog(currentVersion, projectPath, launchProject, commandLineArguments); + break; + case DialogResult.Cancel: // cancelled + SetStatus("Cancelled project upgrade"); + break; + case DialogResult.Retry: // download and install missing version + SetStatus("Download and install missing version " + currentVersion); + string url = Tools.GetUnityReleaseURL(currentVersion); + if (string.IsNullOrEmpty(url) == false) + { + DownloadInBrowser(url, currentVersion); + } + else + { + SetStatus("Failed getting Unity Installer URL"); + } + break; + case DialogResult.Yes: // upgrade + SetStatus("Upgrading project to " + Form2.currentVersion); + if (launchProject == true) LaunchProject(projectPath, Form2.currentVersion); + break; + default: + Console.WriteLine("Unknown DialogResult: " + results); + break; + } + upgradeDialog.Close(); + } + + private void FetchListOfUnityUpdates() + { + if (isDownloadingUnityList == true) + { + SetStatus("We are already downloading ..."); + return; + } + isDownloadingUnityList = true; + SetStatus("Downloading list of Unity versions ..."); + + // download list of Unity versions + using (WebClient webClient = new WebClient()) + { + webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(UnityVersionsListDownloaded); + var unityVersionsURL = @"http://symbolserver.unity3d.com/000Admin/history.txt"; + webClient.DownloadStringAsync(new Uri(unityVersionsURL)); + } + } + + private void UnityVersionsListDownloaded(object sender, DownloadStringCompletedEventArgs e) + { + // TODO check for error.. + SetStatus("Downloading list of Unity versions ... done"); + isDownloadingUnityList = false; + + // parse to list + var receivedList = e.Result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + Array.Reverse(receivedList); + gridUnityUpdates.Rows.Clear(); + // fill in, TODO: show only top 50 or so + for (int i = 0, len = receivedList.Length; i < len; i++) + { + var row = receivedList[i].Split(','); + var versionTemp = row[6].Trim('"'); + gridUnityUpdates.Rows.Add(row[3], versionTemp); + + // set color if we already have it installed + gridUnityUpdates.Rows[i].Cells[1].Style.ForeColor = unityList.ContainsKey(versionTemp) ? Color.Green : Color.Black; + } + } + + // returns currently selected rows path string + string GetSelectedRowData(string key) + { + string path = null; + FixSelectedRow(); + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + path = gridRecent.Rows[(int)selected].Cells[key].Value?.ToString(); + } + return path; + } + + void BrowseForExistingProjectFolder() + { + folderBrowserDialog1.Description = "Select existing project folder"; + var d = folderBrowserDialog1.ShowDialog(); + var projectPath = folderBrowserDialog1.SelectedPath; + + // NOTE: if user didnt click enter or deselect-select newly created folder, this fails as it returns "new folder" instead of actual name + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/cc7f1d54-c1a0-45de-9611-7f69873f32df/folderbrowserdialog-bug-when-click-ok-while-modify-new-folders-name?forum=netfxbcl + + if (String.IsNullOrWhiteSpace(projectPath) == false && Directory.Exists(projectPath) == true) + { + // TODO: remove duplicate code (from UpdateRecentList()) + string projectName = ""; + + // get project name from full path + if (projectPath.IndexOf(Path.DirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); + } + else if (projectPath.IndexOf(Path.AltDirectorySeparatorChar) > -1) + { + projectName = projectPath.Substring(projectPath.LastIndexOf(Path.AltDirectorySeparatorChar) + 1); + } + else // no path separator found + { + projectName = projectPath; + } + + string csprojFile = Path.Combine(projectPath, projectName + ".csproj"); + + // editor only project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, projectName + ".Editor.csproj"); + } + + // maybe 4.x project + if (File.Exists(csprojFile) == false) + { + csprojFile = Path.Combine(projectPath, "Assembly-CSharp.csproj"); + } + + // get last modified date + DateTime? lastUpdated = Tools.GetLastModifiedTime(csprojFile); + + // get project version + string projectVersion = Tools.GetProjectVersion(projectPath); + + // get custom launch arguments, only if column in enabled + string customArgs = ""; + if (chkShowLauncherArgumentsColumn.Checked == true) + { + customArgs = Tools.ReadCustomLaunchArguments(projectPath, launcherArgumentsFile); + } + + // get git branchinfo, only if column in enabled + string gitBranch = ""; + if (chkShowGitBranchColumn.Checked == true) + { + gitBranch = Tools.ReadGitBranchInfo(projectPath); + } + + // NOTE: list item will disappear if you dont open the project once.. + + // TODO: dont add if not a project?? + + gridRecent.Rows.Insert(0, projectName, projectVersion, projectPath, lastUpdated, customArgs, gitBranch); + gridRecent.Rows[0].Cells[1].Style.ForeColor = HaveExactVersionInstalled(projectVersion) ? Color.Green : Color.Red; + gridRecent.Rows[0].Selected = true; + gridRecent.CurrentCell = gridRecent[0, 0]; // reset position to first item + } + } + + private void SaveSettingsOnExit() + { + // save list column widths + List gridWidths; + if (Properties.Settings.Default.gridColumnWidths != null) + { + gridWidths = new List(Properties.Settings.Default.gridColumnWidths); + } + else + { + gridWidths = new List(); + } + + // restore data grid view widths + var colum = gridRecent.Columns[0]; + for (int i = 0; i < gridRecent.Columns.Count; ++i) + { + if (Properties.Settings.Default.gridColumnWidths != null && Properties.Settings.Default.gridColumnWidths.Length > i) + { + gridWidths[i] = gridRecent.Columns[i].Width; + } + else + { + gridWidths.Add(gridRecent.Columns[i].Width); + } + } + Properties.Settings.Default.gridColumnWidths = gridWidths.ToArray(); + Properties.Settings.Default.Save(); + } + + void FixSelectedRow() + { + if (gridRecent.CurrentCell == null) + { + if (gridRecent.SelectedRows.Count != 0) + { + DataGridViewRow row = gridRecent.SelectedRows[0]; + gridRecent.CurrentCell = row.Cells[0]; + } + } + } + + private void btnOpenLogcatCmd_Click(object sender, EventArgs e) + { + try + { + Process myProcess = new Process(); + var cmd = "cmd.exe"; + myProcess.StartInfo.FileName = cmd; + // NOTE windows 10 cmd line supports ansi colors, otherwise remove -v color + var pars = " /c adb logcat -s Unity ActivityManager PackageManager dalvikvm DEBUG -v color"; + myProcess.StartInfo.Arguments = pars; + myProcess.Start(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + int GetSelectedRowIndex() + { + var selected = gridRecent?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + return (int)selected; + } + else + { + return -1; + } + } + + void SetSelectedRowIndex(int index) + { + if (index > -1 && index < gridRecent.Rows.Count) gridRecent.Rows[index].Selected = true; + } + + private void btnDownloadNewUnity_Click(object sender, EventArgs e) + { + FixSelectedRow(); + var selected = gridUnityUpdates?.CurrentCell?.RowIndex; + if (selected.HasValue && selected > -1) + { + var version = gridUnityUpdates.Rows[(int)selected].Cells["_UnityUpdateVersion"].Value.ToString(); + string url = Tools.GetUnityReleaseURL(version); + if (string.IsNullOrEmpty(url) == false) + { + DownloadInBrowser(url, version); + } + } + + } + + // open LocalLow folder + private void btnPlayerLogFolder_Click(object sender, EventArgs e) + { + var logfolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/../LocalLow"); + if (Directory.Exists(logfolder) == true) + { + if (Tools.LaunchExplorer(logfolder) == false) + { + SetStatus("Error> Directory not found: " + logfolder); + } + } + } + + private void lblClearSearchField_Click(object sender, EventArgs e) + { + tbSearchBar.Text = ""; + } + + private void lblClearSearchField_MouseEnter(object sender, EventArgs e) + { + ((Label)sender).ForeColor = Color.FromArgb(255, 0, 0, 0); + } + + private void lblClearSearchField_MouseLeave(object sender, EventArgs e) + { + ((Label)sender).ForeColor = Color.FromArgb(128, 128, 128, 128); + } + } // class Form +} // namespace \ No newline at end of file diff --git a/UnityLauncher/Form1.resx b/UnityLauncher/Form1.resx index 4902c55..83ebd0f 100644 --- a/UnityLauncher/Form1.resx +++ b/UnityLauncher/Form1.resx @@ -132,6 +132,12 @@ True + + True + + + True + True @@ -144,18 +150,36 @@ True + + True + + + True + True True + + True + + + True + True True + + True + + + True + True @@ -1066,6 +1090,9 @@ 374, 17 + + 17, 56 + 25 diff --git a/UnityLauncher/Form2.Designer.cs b/UnityLauncher/Form2.Designer.cs index ce7d9fe..5f5e19c 100644 --- a/UnityLauncher/Form2.Designer.cs +++ b/UnityLauncher/Form2.Designer.cs @@ -54,6 +54,7 @@ private void InitializeComponent() this.lstUnityVersions.Name = "lstUnityVersions"; this.lstUnityVersions.Size = new System.Drawing.Size(235, 303); this.lstUnityVersions.TabIndex = 1; + this.lstUnityVersions.KeyDown += new System.Windows.Forms.KeyEventHandler(this.lstUnityVersions_KeyDown); // // btnCancelUpgrade // @@ -99,7 +100,7 @@ private void InitializeComponent() this.btn_GoInstallMissingVersion.Name = "btn_GoInstallMissingVersion"; this.btn_GoInstallMissingVersion.Size = new System.Drawing.Size(111, 22); this.btn_GoInstallMissingVersion.TabIndex = 6; - this.btn_GoInstallMissingVersion.Text = "Download && Install"; + this.btn_GoInstallMissingVersion.Text = "Download"; this.btn_GoInstallMissingVersion.UseVisualStyleBackColor = true; this.btn_GoInstallMissingVersion.Click += new System.EventHandler(this.btn_GoInstallMissingVersion_Click); // @@ -132,6 +133,7 @@ private void InitializeComponent() this.Name = "Form2"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Missing Exact Unity Version"; + this.TopMost = true; this.Load += new System.EventHandler(this.Form2_Load); this.ResumeLayout(false); this.PerformLayout(); diff --git a/UnityLauncher/Form2.cs b/UnityLauncher/Form2.cs index 4d5e919..d8df7aa 100644 --- a/UnityLauncher/Form2.cs +++ b/UnityLauncher/Form2.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using UnityLauncherTools; namespace UnityLauncher { @@ -32,8 +33,7 @@ void Start() // show available versions, autoselect nearest one if (string.IsNullOrEmpty(currentVersion) == false) { - string nearestVersion = Form1.FindNearestVersion(currentVersion, Form1.unityList.Keys.ToList()); - //Console.WriteLine("nearest:" + nearestVersion); + string nearestVersion = Tools.FindNearestVersion(currentVersion, Form1.unityList.Keys.ToList()); // preselect most likely version int likelyIndex = lstUnityVersions.FindString(nearestVersion); @@ -41,6 +41,11 @@ void Start() { lstUnityVersions.SetSelected(likelyIndex, true); } + else + { + // just select first item then + lstUnityVersions.SetSelected(0, true); + } // enable release and dl buttons btn_GoInstallMissingVersion.Enabled = true; @@ -53,6 +58,8 @@ void Start() btn_OpenMissingVersionReleasePage.Enabled = false; currentVersion = "None"; + // just select first item then + if (lstUnityVersions != null && lstUnityVersions.Items.Count > 0) lstUnityVersions.SetSelected(0, true); } // fill textbox @@ -63,15 +70,7 @@ void Start() private void btnConfirmUpgrade_Click(object sender, EventArgs e) { - if (lstUnityVersions.SelectedIndex > -1) - { - currentVersion = lstUnityVersions.Items[lstUnityVersions.SelectedIndex].ToString(); - DialogResult = DialogResult.Yes; - } - else - { - // no version selected - } + UpgradeToSelected(); } private void btnCancelUpgrade_Click(object sender, EventArgs e) @@ -90,5 +89,30 @@ private void btn_GoInstallMissingVersion_Click(object sender, EventArgs e) } #endregion + + private void lstUnityVersions_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Return) + { + UpgradeToSelected(); + } + else if (e.KeyCode == Keys.Escape) + { + DialogResult = DialogResult.Cancel; + } + } + + void UpgradeToSelected() + { + if (lstUnityVersions.SelectedIndex > -1) + { + currentVersion = lstUnityVersions.Items[lstUnityVersions.SelectedIndex].ToString(); + DialogResult = DialogResult.Yes; + } + else + { + // no version selected + } + } } } diff --git a/UnityLauncher/PreviousVersion.txt b/UnityLauncher/PreviousVersion.txt new file mode 100644 index 0000000..03acb06 Binary files /dev/null and b/UnityLauncher/PreviousVersion.txt differ diff --git a/UnityLauncher/Properties/Settings.Designer.cs b/UnityLauncher/Properties/Settings.Designer.cs index 5637586..89b70cd 100644 --- a/UnityLauncher/Properties/Settings.Designer.cs +++ b/UnityLauncher/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace UnityLauncher.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -76,7 +76,7 @@ public bool closeAfterExplorer { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] + [global::System.Configuration.DefaultSettingValueAttribute("False")] public bool closeAfterProject { get { return ((bool)(this["closeAfterProject"])); @@ -112,14 +112,49 @@ public int formHeight { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("")] - public System.Int32[] gridColumnWidths { + public int[] gridColumnWidths { get { - return (System.Int32[]) (this["gridColumnWidths"]); + return ((int[])(this["gridColumnWidths"])); } set { this["gridColumnWidths"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool showArgumentsColumn { + get { + return ((bool)(this["showArgumentsColumn"])); + } + set { + this["showArgumentsColumn"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool showGitBranchColumn { + get { + return ((bool)(this["showGitBranchColumn"])); + } + set { + this["showGitBranchColumn"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool useDarkSkin { + get { + return ((bool)(this["useDarkSkin"])); + } + set { + this["useDarkSkin"] = value; + } + } } } diff --git a/UnityLauncher/Properties/Settings.settings b/UnityLauncher/Properties/Settings.settings index ff93822..b18b7e0 100644 --- a/UnityLauncher/Properties/Settings.settings +++ b/UnityLauncher/Properties/Settings.settings @@ -19,19 +19,25 @@ True - True + False - -+ -+ <ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> -+ </ArrayOfInt> -+ -+ 600 650 + + + + + False + + + False + + + False + \ No newline at end of file diff --git a/UnityLauncher/Tools.cs b/UnityLauncher/Tools.cs new file mode 100644 index 0000000..1dc5e63 --- /dev/null +++ b/UnityLauncher/Tools.cs @@ -0,0 +1,418 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +namespace UnityLauncherTools +{ + public static class Tools + { + /// + /// open url with default browser + /// + /// + public static void OpenURL(string url) + { + Process.Start(url); + } + + /// + /// reads .git/HEAD file from the project to get current branch name + /// + /// + /// + public static string ReadGitBranchInfo(string projectPath) + { + string results = null; + DirectoryInfo gitDirectory = FindDir(".git", projectPath); + if (gitDirectory != null) + { + string branchFile = Path.Combine(gitDirectory.FullName, "HEAD"); + if (File.Exists(branchFile)) + { + results = File.ReadAllText(branchFile); + // get branch only + int pos = results.LastIndexOf("/") + 1; + results = results.Substring(pos, results.Length - pos); + } + } + return results; + } + + /// + /// Searches for a directory beginning with "startPath". + /// If the directory is not found, then parent folders are searched until + /// either it is found or the root folder has been reached. + /// Null is returned if the directory was not found. + /// + /// + /// + /// + public static DirectoryInfo FindDir(string dirName, string startPath) + { + DirectoryInfo dirInfo = new DirectoryInfo(Path.Combine(startPath, dirName)); + while (!dirInfo.Exists) + { + if (dirInfo.Parent.Parent == null) + { + return null; + } + dirInfo = new DirectoryInfo(Path.Combine(dirInfo.Parent.Parent.FullName, dirName)); + } + return dirInfo; + } + + /// + /// returns last-write-time for a file or folder + /// + /// full path to file or folder + /// + public static DateTime? GetLastModifiedTime(string path) + { + if (File.Exists(path) == true || Directory.Exists(path) == true) + { + DateTime modification = File.GetLastWriteTime(path); + return modification; + } + else + { + return null; + } + } + + /// + /// reads LauncherArguments.txt file from ProjectSettings-folder + /// + /// full project root path + /// default filename is "LauncherArguments.txt" + /// + public static string ReadCustomLaunchArguments(string projectPath, string launcherArgumentsFile) + { + string results = null; + string argumentsFile = Path.Combine(projectPath, "ProjectSettings", launcherArgumentsFile); + if (File.Exists(argumentsFile) == true) + { + results = File.ReadAllText(argumentsFile); + } + return results; + } + + /// + /// tries to find next higher version + /// + /// + /// + /// + public static string FindNearestVersion(string currentVersion, List allAvailable) + { + if (currentVersion.Contains("2019")) + { + return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => x.Contains("2019"))); + } + if (currentVersion.Contains("2018")) + { + return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => x.Contains("2018"))); + } + if (currentVersion.Contains("2017")) + { + return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => x.Contains("2017"))); + } + return FindNearestVersionFromSimilarVersions(currentVersion, allAvailable.Where(x => !x.Contains("2017"))); + } + + private static string FindNearestVersionFromSimilarVersions(string version, IEnumerable allAvailable) + { + Dictionary stripped = new Dictionary(); + var enumerable = allAvailable as string[] ?? allAvailable.ToArray(); + + foreach (var t in enumerable) + { + stripped.Add(new Regex("[a-zA-z]").Replace(t, "."), t); + } + + var comparableVersion = new Regex("[a-zA-z]").Replace(version, "."); + if (!stripped.ContainsKey(comparableVersion)) + { + stripped.Add(comparableVersion, version); + } + + var comparables = stripped.Keys.OrderBy(x => x).ToList(); + var actualIndex = comparables.IndexOf(comparableVersion); + + if (actualIndex < stripped.Count - 1) return stripped[comparables[actualIndex + 1]]; + return null; + } + + /// + /// opens release notes url in default browser + /// + /// + /// + public static bool OpenReleaseNotes(string version) + { + bool result = false; + var url = GetUnityReleaseURL(version); + if (string.IsNullOrEmpty(url) == false) + { + Process.Start(url); + result = true; + } + else + { + } + return result; + } + + /// + /// returns release page URL to given version + /// NOTE: doesnt parse alpha versions, since they are not visible + /// + /// + /// + public static string GetUnityReleaseURL(string version) + { + string url = ""; + if (VersionIsArchived(version)) + { + // remove f# + version = Regex.Replace(version, @"f.", "", RegexOptions.IgnoreCase); + + string padding = "unity-"; + string whatsnew = "whats-new"; + + if (version.Contains("5.6")) padding = ""; + if (version.Contains("2017.1")) whatsnew = "whatsnew"; + if (version.Contains("2018.2")) whatsnew = "whatsnew"; + if (version.Contains("2018.3")) padding = ""; + if (version.Contains("2018.1")) whatsnew = "whatsnew"; // doesnt work + if (version.Contains("2017.4.")) padding = ""; // doesnt work for all versions + if (version.Contains("2018.4.")) padding = ""; + if (version.Contains("2019")) padding = ""; + url = "https://unity3d.com/unity/" + whatsnew + "/" + padding + version; + } + else + if (VersionIsPatch(version)) + { + url = "https://unity3d.com/unity/qa/patch-releases/" + version; + } + else + if (VersionIsBeta(version)) + { + url = "https://unity3d.com/unity/beta/" + version; + } + else + if (VersionIsAlpha(version)) + { + url = "https://unity3d.com/unity/alpha/" + version; + } + + Console.WriteLine(url); + + return url; + } + + // if version contains *f* its archived version + public static bool VersionIsArchived(string version) + { + return version.Contains("f"); + } + + public static bool VersionIsPatch(string version) + { + return version.Contains("p"); + } + + public static bool VersionIsBeta(string version) + { + return version.Contains("b"); + } + + public static bool VersionIsAlpha(string version) + { + return version.Contains("a"); + } + + /// + /// uninstall context menu item from registry + /// + /// + public static void RemoveContextMenuRegistry(string contextRegRoot) + { + RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); + if (key != null) + { + var appName = "UnityLauncher"; + RegistryKey appKey = Registry.CurrentUser.OpenSubKey(contextRegRoot + "\\" + appName, false); + if (appKey != null) + { + key.DeleteSubKeyTree(appName); + //SetStatus("Removed context menu registry items"); + } + else + { + //SetStatus("Nothing to uninstall.."); + } + } + else + { + //SetStatus("Error> Cannot find registry key: " + contextRegRoot); + } + } + + /// + /// install context menu item to registry + /// + /// + public static void AddContextMenuRegistry(string contextRegRoot) + { + RegistryKey key = Registry.CurrentUser.OpenSubKey(contextRegRoot, true); + + // add folder if missing + if (key == null) + { + key = Registry.CurrentUser.CreateSubKey(@"Software\Classes\Directory\Background\Shell"); + } + + if (key != null) + { + var appName = "UnityLauncher"; + key.CreateSubKey(appName); + + key = key.OpenSubKey(appName, true); + key.SetValue("", "Open with UnityLauncher"); + key.SetValue("Icon", "\"" + Application.ExecutablePath + "\""); + + key.CreateSubKey("command"); + key = key.OpenSubKey("command", true); + var executeString = "\"" + Application.ExecutablePath + "\""; + executeString += " -projectPath \"%V\""; + key.SetValue("", executeString); + } + else + { + Console.WriteLine("Error> Cannot find registry key: " + contextRegRoot); + } + } + + + /// + /// parse project version from ProjectSettings/ data + /// + /// project base path + /// + public static string GetProjectVersion(string path) + { + var version = ""; + + if (File.Exists(Path.Combine(path, "ProjectVersionOverride.txt"))) + { + version = File.ReadAllText(Path.Combine(path, "ProjectVersionOverride.txt")); + } + else if (Directory.Exists(Path.Combine(path, "ProjectSettings"))) + { + var versionPath = Path.Combine(path, "ProjectSettings", "ProjectVersion.txt"); + if (File.Exists(versionPath) == true) // 5.x and later + { + var data = File.ReadAllLines(versionPath); + + if (data != null && data.Length > 0) + { + var dd = data[0]; + // check first line + if (dd.Contains("m_EditorVersion")) + { + var t = dd.Split(new string[] { "m_EditorVersion: " }, StringSplitOptions.None); + if (t != null && t.Length > 0) + { + version = t[1].Trim(); + } + else + { + throw new InvalidDataException("invalid version data:" + data); + } + } + else + { + MessageBox.Show("Cannot find m_EditorVersion in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); + } + } + else + { + MessageBox.Show("Invalid projectversion data found in '" + versionPath + "'.\n\nFile Content:\n" + string.Join("\n", data).ToString()); + } + } + else // maybe its 4.x + { + versionPath = Path.Combine(path, "ProjectSettings", "ProjectSettings.asset"); + if (File.Exists(versionPath) == true) + { + // first try if its ascii format + var data = File.ReadAllLines(versionPath); + if (data != null && data.Length > 0 && data[0].IndexOf("YAML") > -1) + { + // in text format, then we need to try library file instead + var newVersionPath = Path.Combine(path, "Library", "AnnotationManager"); + if (File.Exists(newVersionPath) == true) + { + versionPath = newVersionPath; + } + } + + // try to get version data out from binary asset + var binData = File.ReadAllBytes(versionPath); + if (binData != null && binData.Length > 0) + { + int dataLen = 7; + int startIndex = 20; + var bytes = new byte[dataLen]; + for (int i = 0; i < dataLen; i++) + { + bytes[i] = binData[startIndex + i]; + } + version = Encoding.UTF8.GetString(bytes); + } + } + } + } + return version; + } + + /// + /// checks file version info + /// + /// + /// + public static string GetFileVersionData(string path) + { + FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(path); + return fvi.ProductName.Replace("(64-bit)", "").Trim(); + //return fvi.FileVersion.Replace("(64-bit)", "").Trim(); + } + + /// + /// launch windows explorer to selected project folder + /// + /// + public static bool LaunchExplorer(string folder) + { + bool result = false; + if (Directory.Exists(folder) == true) + { + Process.Start(folder); + result = true; + } + else + { + result = false; + } + return result; + } + + } +} diff --git a/UnityLauncher/UnityLauncher.csproj b/UnityLauncher/UnityLauncher.csproj index 890845b..8bd73a9 100644 --- a/UnityLauncher/UnityLauncher.csproj +++ b/UnityLauncher/UnityLauncher.csproj @@ -56,7 +56,7 @@ true - true + false unitylauncher.ico @@ -75,6 +75,7 @@ + Form @@ -126,7 +127,12 @@ + + + + + \ No newline at end of file