diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index ba5e6aa..89e3ff3 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,7 +1,6 @@
-# This is a basic workflow to help you get started with Actions
name: CI
-# Controls when the workflow will run
+
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
@@ -10,52 +9,183 @@ on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
-# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
- runs-on: windows-2019
+ runs-on: windows-2022
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- - name: Check Commit and Install 7Zip PowerShell Module
+ # Step to check if the commit message contains #GITBUILD
+ - name: Check Commit Message
shell: powershell
run: |
- # cancel early, if not build commit
- $strVal ='${{ github.event.commits[0].message }}'
+ # Get the commit message
+ $strVal = '${{ github.event.commits[0].message }}'
# Convert commit message to a single line if multiline
$singleLineStrVal = $strVal -replace "`r`n", " " -replace "`n", " "
- if($singleLineStrVal -match '#GITBUILD')
- {
- Write-Host 'True'
+ if ($singleLineStrVal -match '#GITBUILD') {
+ Write-Host 'Build commit detected. Proceeding with build...'
+ echo "build_trigger=true" >> $env:GITHUB_ENV
} else {
- Write-Host 'False'
- exit(1)
+ Write-Host 'No build commit. Skipping build steps...'
+ echo "build_trigger=false" >> $env:GITHUB_ENV
}
- Install-Module 7Zip4PowerShell -Force -Verbose
+ # Step to ensure the repository is checked out
- uses: actions/checkout@v2
+ # Inform if build steps are skipped
+ - name: Inform Skipped Build Steps
+ if: env.build_trigger != 'true'
+ shell: powershell
+ run: |
+ Write-Host "Skipping build steps because the commit message does not contain #GITBUILD."
+
+ # Install 7Zip PowerShell module
+ - name: Install 7Zip PowerShell Module
+ if: env.build_trigger == 'true'
+ shell: powershell
+ run: Install-Module 7Zip4PowerShell -Force -Verbose
+
+ # Restore NuGet packages
- name: Restore NuGet packages
+ if: env.build_trigger == 'true'
run: nuget restore UnityLauncherPro.sln
-
+
+ # Build the binary
- name: Build Binary
+ if: env.build_trigger == 'true'
shell: cmd
run: call .\Build.cmd
-
+
+ # Build the artifact
- name: Build Artifact
+ if: env.build_trigger == 'true'
shell: cmd
run: call .\ArtifactBuild.cmd
+ # Check that output exists
+ - name: Validate UnityLauncherPro.exe exists
+ if: env.build_trigger == 'true'
+ shell: cmd
+ run: |
+ if not exist "UnityLauncherPro\bin\Release\UnityLauncherPro.exe" (
+ echo ERROR: UnityLauncherPro.exe not found.
+ exit /b 1
+ )
+ echo Found UnityLauncherPro.exe
+
+ # 1) Compute a wrapped major.minor.build from the run number
+ - name: Compute installer version
+ if: env.build_trigger == 'true'
+ shell: bash
+ run: |
+ TOTAL=${{ github.run_number }}
+ BUILD=$(( TOTAL % 65536 ))
+ MINOR_TOTAL=$(( TOTAL / 65536 ))
+ MINOR=$(( MINOR_TOTAL % 256 ))
+ MAJOR=$(( MINOR_TOTAL / 256 ))
+ echo "INSTALLER_MAJOR=$MAJOR" >> $GITHUB_ENV
+ echo "INSTALLER_MINOR=$MINOR" >> $GITHUB_ENV
+ echo "INSTALLER_BUILD=$BUILD" >> $GITHUB_ENV
+ echo "INSTALLER_VER=$MAJOR.$MINOR.$BUILD" >> $GITHUB_ENV
+ echo "Computed installer version → $MAJOR.$MINOR.$BUILD (run #${{ github.run_number }})"
+
+ # 2) Patch your .vdproj in place (inject ProductVersion and a new GUID)
+ - name: Patch .vdproj ProductVersion & ProductCode
+ if: env.build_trigger == 'true'
+ shell: pwsh
+ run: |
+ $proj = 'UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj'
+ $ver = "${{ env.INSTALLER_VER }}" # e.g. 0.0.118
+ $guid = [Guid]::NewGuid().ToString("B").ToUpper() # e.g. {E821A3F5-1F84-4A4B-BE9D-115D93E9E6F0}
+
+ # Read & rewrite line-by-line
+ $fixed = Get-Content $proj | ForEach-Object {
+ if ($_ -match '^(\s*)"ProductVersion"') {
+ # preserve indentation, then inject exactly one pair of braces
+ "$($Matches[1])""ProductVersion"" = ""8:$ver"""
+ }
+ elseif ($_ -match '^(\s*)"ProductCode"') {
+ "$($Matches[1])""ProductCode"" = ""8:$guid"""
+ }
+ else {
+ $_
+ }
+ }
+
+ # Overwrite the project
+ Set-Content -Path $proj -Value $fixed
+
+ Write-Host "→ ProductVersion patched to 8:$ver"
+ Write-Host "→ ProductCode patched to 8:$guid"
+
+
+ # 3) **DEBUG**: print out the patched .vdproj so you can inspect it
+ - name: Show patched .vdproj
+ if: env.build_trigger == 'true'
+ shell: pwsh
+ run: |
+ $proj = 'UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj'
+ Write-Host "=== BEGIN .vdproj CONTENT ==="
+ Get-Content $proj
+ Write-Host "=== END .vdproj CONTENT ==="
+
+ # locate VS 2022
+ - name: Locate Visual Studio 2022
+ id: vswhere
+ shell: pwsh
+ run: |
+ $installPath = vswhere -latest -products * -requires Microsoft.Component.MSBuild `
+ -property installationPath
+ if (-not $installPath) { throw 'VS 2022 not found' }
+ Write-Host "##[set-output name=installPath]$installPath"
+
+ # download vs installer builder (v2.0.1)
+ - name: Download Installer-Projects VSIX
+ shell: pwsh
+ run: |
+ $vsixUrl = "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/VisualStudioClient/vsextensions/MicrosoftVisualStudio2022InstallerProjects/2.0.1/vspackage"
+ Invoke-WebRequest $vsixUrl -OutFile installerprojects.vsix
+
+ # install vs installer builder
+ - name: Install Installer-Projects extension
+ shell: pwsh
+ run: |
+ $vsixInstaller = Join-Path "${{ steps.vswhere.outputs.installPath }}" 'Common7\IDE\VSIXInstaller.exe'
+ Write-Host "Running: $vsixInstaller installerprojects.vsix /quiet"
+ & $vsixInstaller installerprojects.vsix /quiet
+
+ # Build MSI installer project using Visual Studio 2022 workaround
+ - name: Build Installer MSI
+ if: env.build_trigger == 'true'
+ shell: cmd
+ run: |
+ echo === Running BuildInstaller.bat ===
+ call .\BuildInstaller.bat || echo WARNING: BuildInstaller.bat exited with %ERRORLEVEL%, continuing...
+ echo === Verifying MSI ===
+ if exist "UnityLauncherProInstaller\Release\UnityLauncherPro-Installer.msi" (
+ echo Success: MSI found at UnityLauncherProInstaller\Release\UnityLauncherPro-Installer.msi
+ exit /b 0
+ ) else (
+ echo ERROR: MSI not found in UnityLauncherProInstaller\Release
+ exit /b 1
+ )
+
+ # Get the current date and time
- name: Get current date and time
id: datetime
+ if: env.build_trigger == 'true' # Only run if build was triggered
run: |
+ # Save the current date and time to an environment variable
echo "current_datetime=$(date +'%d/%m/%Y %H:%M')" >> $GITHUB_ENV
# Step to get previous tag and commits
- name: Get commits since last release
id: get_commits
+ if: env.build_trigger == 'true' # Only run if build was triggered
shell: bash
run: |
# Get the most recent tag
@@ -68,13 +198,13 @@ jobs:
# List commits since last tag
COMMITS=$(git log $PREV_TAG..HEAD --pretty=format:"* %s" --no-merges)
fi
- echo "Commits since last release: $COMMITS"
-
- # Save commits to environment file for later use
+ # Save commits to the environment
echo "commits=$COMMITS" >> $GITHUB_ENV
+ # Create a release
- name: Create Release
id: create_release
+ if: env.build_trigger == 'true' # Execute only if build was triggered
uses: actions/create-release@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -87,10 +217,12 @@ jobs:
### Commits in this release:
${{ env.commits }}
draft: false
- prerelease: false
-
+ prerelease: false
+
+ # Upload the release asset
- name: Upload Release Asset
id: upload-release-asset
+ if: env.build_trigger == 'true' # Execute only if build was triggered
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -99,3 +231,15 @@ jobs:
asset_path: ./UnityLauncherPro.zip
asset_name: UnityLauncherPro.zip
asset_content_type: application/zip
+
+ # Upload MSI installer to release
+ - name: Upload MSI Installer
+ if: env.build_trigger == 'true'
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./UnityLauncherProInstaller/Release/UnityLauncherPro-Installer.msi
+ asset_name: UnityLauncherPro-Installer.msi
+ asset_content_type: application/x-msi
diff --git a/Build.cmd b/Build.cmd
index 96f1597..80288d1 100644
--- a/Build.cmd
+++ b/Build.cmd
@@ -1,10 +1,10 @@
@echo off
REM Default VS paths to check if no Paths.cmd file exists
-set VISUAL_STUDIO_PATH_0="%programfiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe"
-set VISUAL_STUDIO_PATH_1="%programfiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe"
-set VISUAL_STUDIO_PATH_2="%programfiles(x86)%\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe"
-set VISUAL_STUDIO_PATH_3="%programfiles(x86)%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe"
+set VISUAL_STUDIO_PATH_0="%programfiles%\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe"
+set VISUAL_STUDIO_PATH_1="%programfiles%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe"
+set VISUAL_STUDIO_PATH_2="%programfiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe"
+set VISUAL_STUDIO_PATH_3="%programfiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe"
pushd "%~dp0"
if exist Debug rd /s /q Debug
diff --git a/BuildInstaller.bat b/BuildInstaller.bat
new file mode 100644
index 0000000..97b0d01
--- /dev/null
+++ b/BuildInstaller.bat
@@ -0,0 +1,75 @@
+@ECHO OFF
+SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
+
+ECHO:
+ECHO === Starting Installer Build Workaround ===
+
+REM Store current directory
+SET "current_path=%CD%"
+
+REM Try all known editions of Visual Studio 2022
+SET "vs_base_path=%ProgramFiles%\Microsoft Visual Studio\2022"
+FOR %%E IN (Community Professional Enterprise) DO (
+ IF EXIST "%vs_base_path%\%%E\Common7\IDE\CommonExtensions\Microsoft\VSI\DisableOutOfProcBuild\DisableOutOfProcBuild.exe" (
+ SET "buildfix_path=%vs_base_path%\%%E\Common7\IDE\CommonExtensions\Microsoft\VSI\DisableOutOfProcBuild"
+ SET "devenv_path=%vs_base_path%\%%E\Common7\IDE\devenv.exe"
+ SET "vs_edition=%%E"
+ GOTO :FoundEdition
+ )
+)
+
+ECHO [ERROR] Could not find DisableOutOfProcBuild.exe in any known VS2022 edition.
+EXIT /B 1
+
+:FoundEdition
+ECHO Found Visual Studio 2022 Edition: %vs_edition%
+CD /D "%buildfix_path%"
+CALL DisableOutOfProcBuild.exe
+
+REM Restore previous directory
+CD /D "%current_path%"
+
+REM === Validate required files ===
+ECHO:
+ECHO === Checking required files ===
+
+SET "error=0"
+
+IF NOT EXIST "UnityLauncherPro\bin\Release\UnityLauncherPro.exe" (
+ ECHO [ERROR] Missing file: UnityLauncherPro\bin\Release\UnityLauncherPro.exe
+ SET "error=1"
+)
+IF NOT EXIST "UnityLauncherPro\Images\icon.ico" (
+ ECHO [ERROR] Missing file: UnityLauncherPro\Images\icon.ico
+ SET "error=1"
+)
+
+IF %error% NEQ 0 (
+ ECHO [ERROR] Required files are missing. Aborting installer build.
+ EXIT /B 1
+)
+
+
+ECHO:
+ECHO === Building Installer ===
+"%devenv_path%" UnityLauncherPro.sln /Rebuild Release /Project UnityLauncherProInstaller > build_output.log 2>&1
+SET "exitCode=%ERRORLEVEL%"
+
+TYPE build_output.log
+ECHO:
+ECHO === devenv.exe exit code: %exitCode% ===
+
+IF NOT "%exitCode%"=="0" (
+ ECHO [ERROR] Installer build failed. Check build_output.log for details.
+ EXIT /B %exitCode%
+)
+
+
+ECHO:
+ECHO === Build Complete ===
+
+REM Optional cleanup: disable workaround
+REG DELETE "HKCU\Software\Microsoft\VisualStudio\Setup" /v VSDisableOutOfProcBuild /f >NUL 2>&1
+
+ENDLOCAL
+EXIT /B %exitCode%
diff --git a/README.md b/README.md
index c6af1d1..f221013 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
# UnityLauncherPro
-[](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [](https://github.com/unitycoder/UnityLauncherPro/blob/master/LICENSE) [](https://discord.gg/cXT97hU)
[](https://www.virustotal.com/gui/url/e123b616cf4cbe3d3f7ba13b0d88cf5fff4638f72d5b9461088d0b11e9a41de3?nocache=1) [](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml)
-
+[](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [](https://github.com/unitycoder/UnityLauncherPro/blob/master/LICENSE) [](https://discord.gg/cXT97hU)
[](https://www.virustotal.com/gui/url/e123b616cf4cbe3d3f7ba13b0d88cf5fff4638f72d5b9461088d0b11e9a41de3?nocache=1) [](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml)
Handle all your Unity versions and Projects easily!
@@ -27,6 +26,9 @@ Handle all your Unity versions and Projects easily!
- Select template for new project (template based on selected unity version)
- And more: https://github.com/unitycoder/UnityLauncherPro/wiki/Launcher-Comparison
+### Powered by
+[](https://jb.gg/OpenSourceSupport)
+
### Forum Thread
https://forum.unity.com/threads/unity-launcher-launch-correct-unity-versions-for-each-project-automatically.488718/
@@ -39,7 +41,7 @@ Pre-releases are sometimes available from dev branch: https://github.com/unityco
### Screenshots
-
+

@@ -47,7 +49,7 @@ Pre-releases are sometimes available from dev branch: https://github.com/unityco

-
+
### Perform tasks on selected project

@@ -69,3 +71,5 @@ Pre-releases are sometimes available from dev branch: https://github.com/unityco
Old (winforms) version is here: https://github.com/unitycoder/UnityLauncher
+
+
diff --git a/UnityLauncherPro.sln b/UnityLauncherPro.sln
index 63fd938..2314601 100644
--- a/UnityLauncherPro.sln
+++ b/UnityLauncherPro.sln
@@ -1,14 +1,13 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28307.539
+# Visual Studio Version 17
+VisualStudioVersion = 17.13.35931.197
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityLauncherPro", "UnityLauncherPro\UnityLauncherPro.csproj", "{EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}"
EndProject
+Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "UnityLauncherProInstaller", "UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj", "{249180EF-BFC1-9DD7-48CC-E2B9253A64E0}"
+EndProject
Global
- GlobalSection(Performance) = preSolution
- HasPerformanceSessions = true
- EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
@@ -18,6 +17,9 @@ Global
{EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Release|Any CPU.Build.0 = Release|Any CPU
+ {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Debug|Any CPU.ActiveCfg = Debug
+ {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Release|Any CPU.ActiveCfg = Release
+ {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Release|Any CPU.Build.0 = Release
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -28,4 +30,7 @@ Global
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
EndGlobal
diff --git a/UnityLauncherPro/App.xaml.cs b/UnityLauncherPro/App.xaml.cs
index 180b5f2..d14e416 100644
--- a/UnityLauncherPro/App.xaml.cs
+++ b/UnityLauncherPro/App.xaml.cs
@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Configuration;
-using System.Data;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Windows;
+using System.Windows;
namespace UnityLauncherPro
{
diff --git a/UnityLauncherPro/Converters/LastModifiedConverter.cs b/UnityLauncherPro/Converters/LastModifiedConverter.cs
index 710dd14..a0f2b45 100644
--- a/UnityLauncherPro/Converters/LastModifiedConverter.cs
+++ b/UnityLauncherPro/Converters/LastModifiedConverter.cs
@@ -23,5 +23,23 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu
return DateTime.ParseExact((string)value, MainWindow.currentDateFormat, culture);
}
+ }
+
+ // just for tooltip
+ [ValueConversion(typeof(DateTime), typeof(String))]
+ public class LastModifiedConverterTooltip : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value == null) return null;
+ DateTime date = (DateTime)value;
+ return date.ToString(MainWindow.currentDateFormat);
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return DateTime.ParseExact((string)value, MainWindow.currentDateFormat, culture);
+ }
+
}
}
diff --git a/UnityLauncherPro/Data/MessageType.cs b/UnityLauncherPro/Data/MessageType.cs
new file mode 100644
index 0000000..febb9be
--- /dev/null
+++ b/UnityLauncherPro/Data/MessageType.cs
@@ -0,0 +1,9 @@
+namespace UnityLauncherPro.Data
+{
+ public enum MessageType
+ {
+ Info,
+ Warning,
+ Error
+ }
+}
diff --git a/UnityLauncherPro/Data/Project.cs b/UnityLauncherPro/Data/Project.cs
index 6bf8621..5f422d3 100644
--- a/UnityLauncherPro/Data/Project.cs
+++ b/UnityLauncherPro/Data/Project.cs
@@ -16,6 +16,7 @@ public class Project : IValueConverter
public string TargetPlatform { set; get; } // TODO rename to Platform
public string[] TargetPlatforms { set; get; }
public bool folderExists { set; get; }
+ public string SRP { set; get; } // Scriptable Render Pipeline, TODO add version info?
// WPF keeps calling this method from AppendFormatHelper, GetNameCore..? not sure if need to return something else or default would be faster?
public override string ToString()
diff --git a/UnityLauncherPro/Data/ThemeColor.cs b/UnityLauncherPro/Data/ThemeColor.cs
index 24a6232..2dcbd02 100644
--- a/UnityLauncherPro/Data/ThemeColor.cs
+++ b/UnityLauncherPro/Data/ThemeColor.cs
@@ -1,5 +1,4 @@
using System;
-using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
diff --git a/UnityLauncherPro/Data/UnityInstallation.cs b/UnityLauncherPro/Data/UnityInstallation.cs
index 3647bf6..c43d7f8 100644
--- a/UnityLauncherPro/Data/UnityInstallation.cs
+++ b/UnityLauncherPro/Data/UnityInstallation.cs
@@ -9,13 +9,10 @@ public class UnityInstallation : IValueConverter
public long VersionCode { set; get; } // version as number, cached for sorting
public string Path { set; get; } // exe path
public DateTime? Installed { set; get; }
-
public string PlatformsCombined { set; get; }
public string[] Platforms { set; get; }
public int ProjectCount { set; get; }
-
public bool IsPreferred { set; get; }
-
public string ReleaseType { set; get; } // Alpha, Beta, LTS.. TODO could be enum
// https://stackoverflow.com/a/5551986/5452781
diff --git a/UnityLauncherPro/Data/UnityVersion.cs b/UnityLauncherPro/Data/UnityVersion.cs
index f616aaa..e4a0649 100644
--- a/UnityLauncherPro/Data/UnityVersion.cs
+++ b/UnityLauncherPro/Data/UnityVersion.cs
@@ -8,6 +8,7 @@ public class UnityVersion
public string Version { get; set; }
public UnityVersionStream Stream { get; set; }
public DateTime ReleaseDate { get; set; }
+ public string directURL { get; set; } = null; // if found from unofficial releases list
public static UnityVersion FromJson(string json)
{
diff --git a/UnityLauncherPro/GetProjects.cs b/UnityLauncherPro/GetProjects.cs
index caa05a9..3011595 100644
--- a/UnityLauncherPro/GetProjects.cs
+++ b/UnityLauncherPro/GetProjects.cs
@@ -15,7 +15,7 @@ public static class GetProjects
// convert target platform name into valid buildtarget platform name, NOTE this depends on unity version, now only 2019 and later are supported
public static Dictionary remapPlatformNames = new Dictionary { { "StandaloneWindows64", "Win64" }, { "StandaloneWindows", "Win" }, { "Android", "Android" }, { "WebGL", "WebGL" } };
- public static List Scan(bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, StringCollection AllProjectPaths = null, bool searchGitbranchRecursivly = false)
+ public static List Scan(bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, StringCollection AllProjectPaths = null, bool searchGitbranchRecursively = false, bool showSRP = false)
{
List projectsFound = new List();
@@ -53,12 +53,12 @@ public static List Scan(bool getGitBranch = false, bool getPlasticBranc
projectPath = (string)key.GetValue(valueName);
}
- var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursivly);
+ var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursively, showSRP);
//Console.WriteLine(projectPath+" "+p.TargetPlatform);
// if want to hide project and folder path for screenshot
- //p.Title = "Example Project ";
- //p.Path = "C:/Projects/ExamplePath/MyProj";
+ //p.Title = "Example Project";
+ //p.Path = "C:/Projects/MyProj";
if (p != null)
{
@@ -94,7 +94,7 @@ public static List Scan(bool getGitBranch = false, bool getPlasticBranc
// if not found from registry, add to recent projects list
if (found == false)
{
- var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursivly);
+ var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursively, showSRP);
if (p != null) projectsFound.Add(p);
}
}
@@ -117,11 +117,10 @@ public static List Scan(bool getGitBranch = false, bool getPlasticBranc
//Console.WriteLine("Trimming projects list to " + MainWindow.maxProjectCount + " projects");
projectsFound.RemoveRange(MainWindow.maxProjectCount, projectsFound.Count - MainWindow.maxProjectCount);
}
-
return projectsFound;
} // Scan()
- static Project GetProjectInfo(string projectPath, bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, bool searchGitbranchRecursivly = false)
+ static Project GetProjectInfo(string projectPath, bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, bool searchGitbranchRecursively = false, bool showSRP = false)
{
bool folderExists = Directory.Exists(projectPath);
@@ -166,11 +165,12 @@ static Project GetProjectInfo(string projectPath, bool getGitBranch = false, boo
string gitBranch = "";
if (getGitBranch == true)
{
- gitBranch = folderExists ? Tools.ReadGitBranchInfo(projectPath, searchGitbranchRecursivly) : null;
+ gitBranch = folderExists ? Tools.ReadGitBranchInfo(projectPath, searchGitbranchRecursively) : null;
+
// check for plastic, if enabled
if (getPlasticBranch == true && gitBranch == null)
{
- gitBranch = folderExists ? Tools.ReadPlasticBranchInfo(projectPath) : null;
+ gitBranch = folderExists ? Tools.ReadPlasticBranchInfo(projectPath, searchGitbranchRecursively) : null;
}
}
@@ -209,6 +209,9 @@ static Project GetProjectInfo(string projectPath, bool getGitBranch = false, boo
// bubblegum(TM) solution, fill available platforms for this unity version, for this project
p.TargetPlatforms = Tools.GetPlatformsForUnityVersion(projectVersion);
p.folderExists = folderExists;
+
+ if (showSRP == true) p.SRP = Tools.GetSRP(projectPath);
+
return p;
}
diff --git a/UnityLauncherPro/GetUnityUpdates.cs b/UnityLauncherPro/GetUnityUpdates.cs
index 3c614e0..631b7e7 100644
--- a/UnityLauncherPro/GetUnityUpdates.cs
+++ b/UnityLauncherPro/GetUnityUpdates.cs
@@ -17,21 +17,115 @@ public static class GetUnityUpdates
private const string CacheFileName = "UnityVersionCache.json";
private static readonly HttpClient Client = new HttpClient();
- public static async Task> FetchAll()
+ static Dictionary unofficialReleaseURLs = new Dictionary();
+
+ public static async Task> FetchAll(bool useUnofficialList = false)
{
var cachedVersions = LoadCachedVersions();
var newVersions = await FetchNewVersions(cachedVersions);
var allVersions = newVersions.Concat(cachedVersions).ToList();
- if (newVersions.Count > 0)
+ if (useUnofficialList == true)
+ {
+ var unofficialVersions = await FetchUnofficialVersions(cachedVersions);
+ unofficialReleaseURLs.Clear();
+ // TODO modify FetchUnofficialVersions to put items in this dictionary directlys
+ foreach (var version in unofficialVersions)
+ {
+ //Console.WriteLine("unofficial: " + version.Version + " , " + version.directURL);
+ if (unofficialReleaseURLs.ContainsKey(version.Version) == false)
+ {
+ unofficialReleaseURLs.Add(version.Version, version.directURL);
+ }
+ }
+ allVersions = unofficialVersions.Concat(allVersions).ToList();
+ }
+
+ if (newVersions.Count > 0 || (useUnofficialList && unofficialReleaseURLs.Count > 0))
{
SaveCachedVersions(allVersions);
}
+
return allVersions;
}
+ public static async Task> FetchUnofficialVersions(List cachedVersions)
+ {
+ var unofficialVersions = new List();
+ var existingVersions = new HashSet(cachedVersions.Select(v => v.Version));
+
+ try
+ {
+ string url = "https://raw.githubusercontent.com/unitycoder/UnofficialUnityReleasesWatcher/refs/heads/main/unity-releases.md";
+
+ var content = await Client.GetStringAsync(url);
+
+ // Parse the Markdown content
+ var lines = content.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ if (line.StartsWith("- ")) // Identify Markdown list items
+ {
+ var urlPart = line.Substring(2).Trim();
+ var version = ExtractVersionFromUrl(urlPart);
+
+ if (!string.IsNullOrEmpty(version) && !existingVersions.Contains(version))
+ {
+ var stream = InferStreamFromVersion(version);
+
+ unofficialVersions.Add(new UnityVersion
+ {
+ Version = version,
+ Stream = stream,
+ ReleaseDate = DateTime.Now, // NOTE not correct, but we don't have known release date for unofficial versions (its only when they are found..)
+ //ReleaseDate = DateTime.MinValue // Release date is unavailable in the MD format, TODO add to md as #2021-01-01 ?
+ directURL = urlPart, // this is available only for unofficial releases
+ });
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error fetching unofficial versions: {ex.Message}");
+ }
+
+ return unofficialVersions;
+ }
+
+ // TODO fixme, f is not always LTS
+ private static UnityVersionStream InferStreamFromVersion(string version)
+ {
+ if (Tools.IsAlpha(version)) return UnityVersionStream.Alpha;
+ if (Tools.IsBeta(version)) return UnityVersionStream.Beta;
+ if (Tools.IsLTS(version)) return UnityVersionStream.LTS;
+
+ //if (version.Contains("a")) return UnityVersionStream.Alpha;
+ //if (version.Contains("b")) return UnityVersionStream.Beta;
+ //if (version.Contains("f")) return UnityVersionStream.LTS;
+ return UnityVersionStream.Tech; // Default to Tech if no identifier is found
+ }
+
+ ///
+ /// Extracts the Unity version from the given URL.
+ ///
+ /// The URL to parse.
+ /// The Unity version string.
+ private static string ExtractVersionFromUrl(string url)
+ {
+ try
+ {
+ var versionStart = url.LastIndexOf('#') + 1;
+ return versionStart > 0 && versionStart < url.Length ? url.Substring(versionStart) : null;
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
public static async Task FetchDownloadUrl(string unityVersion)
{
if (string.IsNullOrEmpty(unityVersion))
@@ -39,6 +133,7 @@ public static async Task FetchDownloadUrl(string unityVersion)
return null;
}
+ // unity release api
string apiUrl = $"{BaseApiUrl}?limit=1&version={unityVersion}&architecture=X86_64&platform=WINDOWS";
try
@@ -53,8 +148,37 @@ public static async Task FetchDownloadUrl(string unityVersion)
}
}
+ static string ParseHashCodeFromURL(string url)
+ {
+ // https://beta.unity3d.com/download/330fbefc18b7/download.html#6000.1.0a8 > 330fbefc18b7
+
+ int hashStart = url.IndexOf("download/") + 9;
+ int hashEnd = url.IndexOf("/download.html", hashStart);
+ return url.Substring(hashStart, hashEnd - hashStart);
+ }
+
private static async Task ExtractDownloadUrlAsync(string json, string unityVersion)
{
+ //Console.WriteLine("json: " + json + " vers: " + unityVersion);
+
+ if (json.Contains("\"results\":[]"))
+ {
+ Console.WriteLine("No results found from releases API, checking unofficial list (if enabled)");
+
+ if (unofficialReleaseURLs.ContainsKey(unityVersion))
+ {
+ Console.WriteLine("Unofficial release found in the list.");
+
+ string unityHash = ParseHashCodeFromURL(unofficialReleaseURLs[unityVersion]);
+ // Console.WriteLine(unityHash);
+ string downloadURL = Tools.ParseDownloadURLFromWebpage(unityVersion, unityHash, false, true);
+ // Console.WriteLine("direct download url: "+downloadURL);
+ return downloadURL;
+ }
+
+ return null;
+ }
+
int resultsIndex = json.IndexOf("\"results\":");
if (resultsIndex == -1) return null;
@@ -84,7 +208,7 @@ private static async Task ExtractDownloadUrlAsync(string json, string un
if (await CheckAssistantUrl(assistantUrl))
{
- Console.WriteLine("Assistant download URL found.");
+ //Console.WriteLine("ExtractDownloadUrlAsync: Assistant download URL found.");
return assistantUrl;
}
else
@@ -279,6 +403,7 @@ private static void SaveCachedVersions(List versions)
if (configDirectory == null) return;
string cacheFilePath = Path.Combine(configDirectory, CacheFileName);
+ //Console.WriteLine("Saving cachedrelease: " + cacheFilePath);
File.WriteAllText(cacheFilePath, json);
}
}
diff --git a/UnityLauncherPro/MainWindow.xaml b/UnityLauncherPro/MainWindow.xaml
index bf95317..49083d2 100644
--- a/UnityLauncherPro/MainWindow.xaml
+++ b/UnityLauncherPro/MainWindow.xaml
@@ -7,9 +7,10 @@
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:converters="clr-namespace:UnityLauncherPro.Converters" x:Class="UnityLauncherPro.MainWindow"
mc:Ignorable="d"
- Title="UnityLauncherPro" Height="650" Width="880" WindowStartupLocation="CenterScreen" Background="{DynamicResource ThemeDarkestBackground}" MinWidth="780" MinHeight="650" AllowsTransparency="True" WindowStyle="None" Margin="0" KeyDown="OnWindowKeyDown" Closing="Window_Closing" SizeChanged="Window_SizeChanged" Icon="Images/icon.ico" SourceInitialized="Window_SourceInitialized" MouseDown="Window_MouseDown">
+ Title="UnityLauncherPro" Height="670" Width="880" WindowStartupLocation="CenterScreen" Background="{DynamicResource ThemeDarkestBackground}" MinWidth="780" MinHeight="650" AllowsTransparency="True" WindowStyle="None" Margin="0" KeyDown="OnWindowKeyDown" Closing="Window_Closing" SizeChanged="Window_SizeChanged" Icon="Images/icon.ico" SourceInitialized="Window_SourceInitialized" MouseDown="Window_MouseDown">
+
@@ -30,7 +31,7 @@
-
+