Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 37ea41d

Browse files
committedDec 20, 2024·
Merge branch 'dev'
* dev: make upgrade window wider install apk: display error message if failed add disable unity hub from launching on Editor start #95 add setting for using unoffical releases list adding unofficial releases watchlist downloads
2 parents b105fca + efb21fb commit 37ea41d

File tree

8 files changed

+521
-31
lines changed

8 files changed

+521
-31
lines changed
 

‎UnityLauncherPro/Data/UnityVersion.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public class UnityVersion
88
public string Version { get; set; }
99
public UnityVersionStream Stream { get; set; }
1010
public DateTime ReleaseDate { get; set; }
11+
public string directURL { get; set; } = null; // if found from unofficial releases list
1112

1213
public static UnityVersion FromJson(string json)
1314
{

‎UnityLauncherPro/GetUnityUpdates.cs

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,31 @@ public static class GetUnityUpdates
1717
private const string CacheFileName = "UnityVersionCache.json";
1818
private static readonly HttpClient Client = new HttpClient();
1919

20-
public static async Task<List<UnityVersion>> FetchAll()
20+
static Dictionary<string, string> unofficialReleaseURLs = new Dictionary<string, string>();
21+
22+
public static async Task<List<UnityVersion>> FetchAll(bool useUnofficialList = false)
2123
{
2224
var cachedVersions = LoadCachedVersions();
2325
var newVersions = await FetchNewVersions(cachedVersions);
2426

2527
var allVersions = newVersions.Concat(cachedVersions).ToList();
2628

29+
if (useUnofficialList == true)
30+
{
31+
var unofficialVersions = await FetchUnofficialVersions(cachedVersions);
32+
unofficialReleaseURLs.Clear();
33+
// TODO modify FetchUnofficialVersions to put items in this dictionary directlys
34+
foreach (var version in unofficialVersions)
35+
{
36+
//Console.WriteLine("unofficial: " + version.Version + " , " + version.directURL);
37+
if (unofficialReleaseURLs.ContainsKey(version.Version) == false)
38+
{
39+
unofficialReleaseURLs.Add(version.Version, version.directURL);
40+
}
41+
}
42+
allVersions = unofficialVersions.Concat(allVersions).ToList();
43+
}
44+
2745
if (newVersions.Count > 0)
2846
{
2947
SaveCachedVersions(allVersions);
@@ -32,13 +50,89 @@ public static async Task<List<UnityVersion>> FetchAll()
3250
return allVersions;
3351
}
3452

53+
public static async Task<List<UnityVersion>> FetchUnofficialVersions(List<UnityVersion> cachedVersions)
54+
{
55+
var unofficialVersions = new List<UnityVersion>();
56+
var existingVersions = new HashSet<string>(cachedVersions.Select(v => v.Version));
57+
58+
try
59+
{
60+
string url = "https://raw.githubusercontent.com/unitycoder/UnofficialUnityReleasesWatcher/refs/heads/main/unity-releases.md";
61+
62+
var content = await Client.GetStringAsync(url);
63+
64+
// Parse the Markdown content
65+
var lines = content.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
66+
foreach (var line in lines)
67+
{
68+
if (line.StartsWith("- ")) // Identify Markdown list items
69+
{
70+
var urlPart = line.Substring(2).Trim();
71+
var version = ExtractVersionFromUrl(urlPart);
72+
73+
if (!string.IsNullOrEmpty(version) && !existingVersions.Contains(version))
74+
{
75+
var stream = InferStreamFromVersion(version);
76+
77+
unofficialVersions.Add(new UnityVersion
78+
{
79+
Version = version,
80+
Stream = stream,
81+
ReleaseDate = DateTime.Now, // NOTE not correct, but we don't have known release date for unofficial versions (its only when they are found..)
82+
//ReleaseDate = DateTime.MinValue // Release date is unavailable in the MD format, TODO add to md as #2021-01-01 ?
83+
directURL = urlPart, // this is available only for unofficial releases
84+
});
85+
}
86+
}
87+
}
88+
}
89+
catch (Exception ex)
90+
{
91+
Console.WriteLine($"Error fetching unofficial versions: {ex.Message}");
92+
}
93+
94+
return unofficialVersions;
95+
}
96+
97+
// TODO fixme, f is not always LTS
98+
private static UnityVersionStream InferStreamFromVersion(string version)
99+
{
100+
if (Tools.IsAlpha(version)) return UnityVersionStream.Alpha;
101+
if (Tools.IsBeta(version)) return UnityVersionStream.Beta;
102+
if (Tools.IsLTS(version)) return UnityVersionStream.LTS;
103+
104+
//if (version.Contains("a")) return UnityVersionStream.Alpha;
105+
//if (version.Contains("b")) return UnityVersionStream.Beta;
106+
//if (version.Contains("f")) return UnityVersionStream.LTS;
107+
return UnityVersionStream.Tech; // Default to Tech if no identifier is found
108+
}
109+
110+
/// <summary>
111+
/// Extracts the Unity version from the given URL.
112+
/// </summary>
113+
/// <param name="url">The URL to parse.</param>
114+
/// <returns>The Unity version string.</returns>
115+
private static string ExtractVersionFromUrl(string url)
116+
{
117+
try
118+
{
119+
var versionStart = url.LastIndexOf('#') + 1;
120+
return versionStart > 0 && versionStart < url.Length ? url.Substring(versionStart) : null;
121+
}
122+
catch
123+
{
124+
return null;
125+
}
126+
}
127+
35128
public static async Task<string> FetchDownloadUrl(string unityVersion)
36129
{
37130
if (string.IsNullOrEmpty(unityVersion))
38131
{
39132
return null;
40133
}
41134

135+
// unity release api
42136
string apiUrl = $"{BaseApiUrl}?limit=1&version={unityVersion}&architecture=X86_64&platform=WINDOWS";
43137

44138
try
@@ -53,8 +147,37 @@ public static async Task<string> FetchDownloadUrl(string unityVersion)
53147
}
54148
}
55149

150+
static string ParseHashCodeFromURL(string url)
151+
{
152+
// https://beta.unity3d.com/download/330fbefc18b7/download.html#6000.1.0a8 > 330fbefc18b7
153+
154+
int hashStart = url.IndexOf("download/") + 9;
155+
int hashEnd = url.IndexOf("/download.html", hashStart);
156+
return url.Substring(hashStart, hashEnd - hashStart);
157+
}
158+
56159
private static async Task<string> ExtractDownloadUrlAsync(string json, string unityVersion)
57160
{
161+
//Console.WriteLine("json: " + json + " vers: " + unityVersion);
162+
163+
if (json.Contains("\"results\":[]"))
164+
{
165+
Console.WriteLine("No results found from releases API, checking unofficial list (if enabled)");
166+
167+
if (unofficialReleaseURLs.ContainsKey(unityVersion))
168+
{
169+
Console.WriteLine("Unofficial release found in the list.");
170+
171+
string unityHash = ParseHashCodeFromURL(unofficialReleaseURLs[unityVersion]);
172+
// Console.WriteLine(unityHash);
173+
string downloadURL = Tools.ParseDownloadURLFromWebpage(unityVersion, unityHash, false, true);
174+
// Console.WriteLine("direct download url: "+downloadURL);
175+
return downloadURL;
176+
}
177+
178+
return null;
179+
}
180+
58181
int resultsIndex = json.IndexOf("\"results\":");
59182
if (resultsIndex == -1) return null;
60183

@@ -84,7 +207,7 @@ private static async Task<string> ExtractDownloadUrlAsync(string json, string un
84207

85208
if (await CheckAssistantUrl(assistantUrl))
86209
{
87-
Console.WriteLine("Assistant download URL found.");
210+
//Console.WriteLine("ExtractDownloadUrlAsync: Assistant download URL found.");
88211
return assistantUrl;
89212
}
90213
else
@@ -279,6 +402,7 @@ private static void SaveCachedVersions(List<UnityVersion> versions)
279402
if (configDirectory == null) return;
280403

281404
string cacheFilePath = Path.Combine(configDirectory, CacheFileName);
405+
//Console.WriteLine("Saving cachedrelease: " + cacheFilePath);
282406
File.WriteAllText(cacheFilePath, json);
283407
}
284408
}

‎UnityLauncherPro/MainWindow.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,8 @@
810810
<CheckBox x:Name="chkQuitAfterCommandline" Content="Close after launching from Explorer" Unchecked="ChkQuitAfterCommandline_CheckedChanged" Checked="ChkQuitAfterCommandline_CheckedChanged" ToolTip="Close launcher after running from commandline or Explorer (recommended)" HorizontalAlignment="Left"/>
811811
<CheckBox x:Name="chkAllowSingleInstanceOnly" Content="Allow single instance only" Checked="ChkAllowSingleInstanceOnly_CheckedChanged" Unchecked="ChkAllowSingleInstanceOnly_CheckedChanged" ToolTip="Activates already running instance, instead of starting new exe (not working if app is minized to taskbar)" HorizontalAlignment="Left"/>
812812
<CheckBox x:Name="useAlphaReleaseNotesSite" Content="Use Unity Alpha Release Notes Site (only for final versions) " ToolTip="Use the superior (but alpha) Unity Release Notes (https://alpha.release-notes.ds.unity3d.com/) site when clicking on the ReleaseNotes button. Otherwise will default to the normal build page." Checked="UseAlphaReleaseNotes_Checked" Unchecked="UseAlphaReleaseNotes_Checked"/>
813+
<CheckBox x:Name="useUnofficialReleaseList" Content="Use Unofficial Release Watch List (for latest downloads)" ToolTip="Checks latest releases from https://github.com/unitycoder/UnofficialUnityReleasesWatcher (if not yet available in The Unity Releases API)" Checked="useUnofficialReleaseList_Checked" Unchecked="useUnofficialReleaseList_Checked"/>
814+
<CheckBox x:Name="chkDisableUnityHubLaunch" Content="Disable UnityHub launch at Editor start" ToolTip="Overrides UnityHub IPC port. Note: You will be logged out in Editor!" Checked="chkDisableUnityHubLaunch_Checked" Unchecked="chkDisableUnityHubLaunch_Checked"/>
813815
<CheckBox x:Name="chkStreamerMode" Content="Streamer Mode (hide project names and folders)" ToolTip="Hide project names and folders in main view" Checked="ChkStreamerMode_Checked" Unchecked="ChkStreamerMode_Checked" HorizontalAlignment="Left"/>
814816
<!--<StackPanel Orientation="Horizontal" Margin="0,0,0,4">
815817
<TextBox x:Name="txtTemplatePackagesFolder" BorderBrush="Transparent" CaretBrush="{DynamicResource ThemeSearchCaret}" Background="{DynamicResource ThemeTextBoxBackground}" SelectionBrush="{DynamicResource ThemeSearchSelection}" Foreground="{DynamicResource ThemeSearchForeground}" ToolTip="Folder for your custom unitypackage templates (for new project)" Padding="0,3,0,0" Width="110" TextChanged="TxtTemplatePackagesFolder_TextChanged" />

‎UnityLauncherPro/MainWindow.xaml.cs

Lines changed: 167 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public partial class MainWindow : Window
5555
string _filterString = null;
5656
bool multiWordSearch = false;
5757
string[] searchWords;
58+
bool isDirtyCell = false;
5859

5960
int lastSelectedProjectIndex = 0;
6061
Mutex myMutex;
@@ -73,8 +74,9 @@ public partial class MainWindow : Window
7374
List<BuildReport> buildReports = new List<BuildReport>(); // multiple reports, each contains their own stats and items
7475
int currentBuildReport = 0;
7576

76-
private NamedPipeServerStream pipeServer;
77-
private const string PipeName = appName;
77+
private NamedPipeServerStream launcherPipeServer;
78+
private const string launcherPipeName = appName;
79+
readonly string unityHubPipeName = "Unity-hubIPCService";
7880

7981
[DllImport("user32", CharSet = CharSet.Unicode)]
8082
static extern IntPtr FindWindow(string cls, string win);
@@ -190,9 +192,61 @@ void Start()
190192
//themeEditorWindow = new ThemeEditor();
191193
//themeEditorWindow.Show();
192194

195+
// test override IPC so that unityhub doesnt start
196+
// open "Unity-hubIPCService" pipe, if not already open
197+
198+
if (Settings.Default.disableUnityHubLaunch == true) StartHubPipe();
199+
193200
isInitializing = false;
194201
}
195202

203+
private static NamedPipeServerStream hubPipeServer;
204+
private CancellationTokenSource _hubCancellationTokenSource;
205+
206+
private async Task StartPipeServerAsync(string pipeName, Action<string> onMessageReceived, CancellationToken cancellationToken)
207+
{
208+
try
209+
{
210+
while (!cancellationToken.IsCancellationRequested)
211+
{
212+
using (var pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
213+
{
214+
await pipeServer.WaitForConnectionAsync(cancellationToken);
215+
Console.WriteLine($"Client connected to pipe '{pipeName}'!");
216+
217+
using (var reader = new StreamReader(pipeServer))
218+
{
219+
while (!cancellationToken.IsCancellationRequested)
220+
{
221+
string message = await reader.ReadLineAsync();
222+
if (message == null) break; // End of stream
223+
onMessageReceived(message);
224+
}
225+
}
226+
}
227+
}
228+
}
229+
catch (OperationCanceledException)
230+
{
231+
// Expected when the cancellation token is triggered
232+
Console.WriteLine("Pipe server operation canceled.");
233+
}
234+
catch (Exception ex)
235+
{
236+
Console.WriteLine($"Error in pipe server: {ex.Message}");
237+
}
238+
finally
239+
{
240+
Console.WriteLine("Named pipe server stopped.");
241+
}
242+
}
243+
244+
245+
private void OnHubMessageReceived(string message)
246+
{
247+
//Console.WriteLine(message);
248+
}
249+
196250
private void DataGridUpdates_SelectionChanged(object sender, SelectionChangedEventArgs e)
197251
{
198252
var selectedUp = GetSelectedUpdate();
@@ -459,6 +513,8 @@ void LoadSettings()
459513
txtWebglRelativePath.Text = Settings.Default.webglBuildPath;
460514
txtCustomThemeFile.Text = Settings.Default.themeFile;
461515
useAlphaReleaseNotesSite.IsChecked = Settings.Default.useAlphaReleaseNotes;
516+
useUnofficialReleaseList.IsChecked = Settings.Default.useUnofficialReleaseList;
517+
chkDisableUnityHubLaunch.IsChecked = Settings.Default.disableUnityHubLaunch;
462518

463519
chkEnablePlatformSelection.IsChecked = Settings.Default.enablePlatformSelection;
464520
chkRunAutomatically.IsChecked = Settings.Default.runAutomatically;
@@ -783,7 +839,7 @@ void AddUnityInstallationRootFolder()
783839
async Task CallGetUnityUpdates()
784840
{
785841
dataGridUpdates.ItemsSource = null;
786-
var task = GetUnityUpdates.FetchAll();
842+
var task = GetUnityUpdates.FetchAll((bool)useUnofficialReleaseList.IsChecked);
787843
var items = await task;
788844
updatesSource = items.ToArray();
789845
if (updatesSource == null) return;
@@ -1105,7 +1161,7 @@ private async void OnTabSelectionChanged(object sender, SelectionChangedEventArg
11051161
// if we dont have previous results yet, TODO scan again if previous was 24hrs ago
11061162
if (updatesSource == null)
11071163
{
1108-
var task = GetUnityUpdates.FetchAll();
1164+
var task = GetUnityUpdates.FetchAll((bool)useUnofficialReleaseList.IsChecked);
11091165
var items = await task;
11101166
if (task.IsCompleted == false || task.IsFaulted == true) return;
11111167
if (items == null) return;
@@ -1136,8 +1192,8 @@ private void Window_Closing(object sender, CancelEventArgs e)
11361192
{
11371193
// (TODO force) close theme editor, if still open, TODO NEED to cancel all changes
11381194
CloseThemeEditor();
1139-
11401195
SaveSettingsOnExit();
1196+
CloseHubPipeAsync();
11411197
}
11421198

11431199
private void CloseThemeEditor()
@@ -2149,7 +2205,6 @@ public void CanExecute_Copy(object sender, CanExecuteRoutedEventArgs e)
21492205
e.CanExecute = true;
21502206
}
21512207

2152-
bool isDirtyCell = false;
21532208
private void GridRecent_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
21542209
{
21552210
isDirtyCell = true;
@@ -3528,24 +3583,38 @@ private void menuInstallLastAPK_Click(object sender, RoutedEventArgs e)
35283583
pars += $" && adb shell monkey -p {packageName} 1";
35293584
}
35303585

3531-
//Tools.LaunchExe(cmd, pars);
3532-
var process = Tools.LaunchExe(cmd, pars, captureOutput: true);
3533-
var output = process.StandardOutput.ReadToEnd();
3534-
var errorOutput = process.StandardError.ReadToEnd().Replace("\r", "").Replace("\n", "");
3586+
try
3587+
{
3588+
//Tools.LaunchExe(cmd, pars);
3589+
var process = Tools.LaunchExe(cmd, pars, captureOutput: true);
3590+
var output = process.StandardOutput.ReadToEnd();
3591+
var errorOutput = process.StandardError.ReadToEnd().Replace("\r", "").Replace("\n", "");
3592+
3593+
process.WaitForExit();
35353594

3536-
process.WaitForExit();
3595+
// Console.WriteLine(output);
3596+
if (!string.IsNullOrEmpty(errorOutput))
3597+
{
3598+
SetStatus("Error installing APK: " + errorOutput);
3599+
}
3600+
else
3601+
{
3602+
// get apk name from path
3603+
var apkName = Path.GetFileName(playerPath);
3604+
if (chkStreamerMode.IsChecked == true) apkName = " (hidden in streamermode)";
3605+
SetStatus("Installed APK:" + apkName);
3606+
}
35373607

3538-
// Console.WriteLine(output);
3539-
if (!string.IsNullOrEmpty(errorOutput))
3608+
}
3609+
catch (Win32Exception ex)
35403610
{
3541-
SetStatus("Error installing APK: " + errorOutput);
3611+
// Handle case where 'adb' is not found
3612+
SetStatus($"Error: 'adb' not found. Ensure it's installed and added to PATH. Details: {ex.Message}");
35423613
}
3543-
else
3614+
catch (Exception ex)
35443615
{
3545-
// get apk name from path
3546-
var apkName = Path.GetFileName(playerPath);
3547-
if (chkStreamerMode.IsChecked == true) apkName = " (hidden in streamermode)";
3548-
SetStatus("Installed APK:" + apkName);
3616+
// Handle other unexpected exceptions
3617+
SetStatus($"An unexpected error occurred: {ex.Message}");
35493618
}
35503619
}
35513620

@@ -3729,7 +3798,7 @@ private void ActivateRunningInstance()
37293798
{
37303799
try
37313800
{
3732-
using (var pipeClient = new NamedPipeClientStream(".", PipeName, PipeDirection.Out))
3801+
using (var pipeClient = new NamedPipeClientStream(".", launcherPipeName, PipeDirection.Out))
37333802
{
37343803
pipeClient.Connect(1000); // Wait for 1 second to connect
37353804
using (var writer = new StreamWriter(pipeClient))
@@ -3748,18 +3817,18 @@ private void ActivateRunningInstance()
37483817

37493818
private void StartPipeServer()
37503819
{
3751-
pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
3752-
pipeServer.BeginWaitForConnection(OnPipeConnection, null);
3820+
launcherPipeServer = new NamedPipeServerStream(launcherPipeName, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
3821+
launcherPipeServer.BeginWaitForConnection(OnPipeConnection, null);
37533822
}
37543823

37553824
private void OnPipeConnection(IAsyncResult result)
37563825
{
37573826
try
37583827
{
3759-
pipeServer.EndWaitForConnection(result);
3828+
launcherPipeServer.EndWaitForConnection(result);
37603829

37613830
// Read the message
3762-
using (var reader = new StreamReader(pipeServer))
3831+
using (var reader = new StreamReader(launcherPipeServer))
37633832
{
37643833
string message = reader.ReadLine();
37653834
if (message == "WakeUp")
@@ -3832,6 +3901,80 @@ private void chkCheckSRP_Checked(object sender, RoutedEventArgs e)
38323901
Settings.Default.Save();
38333902
RefreshRecentProjects();
38343903
}
3904+
3905+
private void useUnofficialReleaseList_Checked(object sender, RoutedEventArgs e)
3906+
{
3907+
if (this.IsActive == false) return; // dont run code on window init
3908+
3909+
Settings.Default.useUnofficialReleaseList = (bool)useUnofficialReleaseList.IsChecked;
3910+
Settings.Default.Save();
3911+
}
3912+
3913+
private async void chkDisableUnityHubLaunch_Checked(object sender, RoutedEventArgs e)
3914+
{
3915+
if (!this.IsActive) return; // Don't run code during window initialization
3916+
3917+
Console.WriteLine((bool)chkDisableUnityHubLaunch.IsChecked);
3918+
3919+
if ((bool)chkDisableUnityHubLaunch.IsChecked)
3920+
{
3921+
await CloseHubPipeAsync(); // Ensure old task is closed before starting a new one
3922+
StartHubPipe();
3923+
}
3924+
else
3925+
{
3926+
await CloseHubPipeAsync();
3927+
}
3928+
3929+
Settings.Default.disableUnityHubLaunch = (bool)chkDisableUnityHubLaunch.IsChecked;
3930+
Settings.Default.Save();
3931+
}
3932+
3933+
private void StartHubPipe()
3934+
{
3935+
if (_hubCancellationTokenSource != null && !_hubCancellationTokenSource.IsCancellationRequested)
3936+
{
3937+
Console.WriteLine("Pipe server already running.");
3938+
return; // Avoid starting multiple instances
3939+
}
3940+
3941+
_hubCancellationTokenSource = new CancellationTokenSource();
3942+
Task.Run(() => StartPipeServerAsync("Unity-hubIPCService", OnHubMessageReceived, _hubCancellationTokenSource.Token));
3943+
Console.WriteLine("StartHubPipe");
3944+
}
3945+
3946+
private async Task CloseHubPipeAsync()
3947+
{
3948+
if (_hubCancellationTokenSource == null || _hubCancellationTokenSource.IsCancellationRequested)
3949+
{
3950+
Console.WriteLine("Pipe server already stopped.");
3951+
return;
3952+
}
3953+
3954+
Console.WriteLine("CloseHubPipe..");
3955+
3956+
// Cancel the token to stop the server task
3957+
_hubCancellationTokenSource.Cancel();
3958+
3959+
try
3960+
{
3961+
// Allow the server to shut down gracefully
3962+
await Task.Delay(100); // Optional: Give some time for clean-up
3963+
}
3964+
catch (Exception ex)
3965+
{
3966+
Console.WriteLine($"Error during pipe server shutdown: {ex.Message}");
3967+
}
3968+
finally
3969+
{
3970+
_hubCancellationTokenSource.Dispose();
3971+
_hubCancellationTokenSource = null;
3972+
Console.WriteLine("Pipe server stopped.");
3973+
}
3974+
}
3975+
3976+
3977+
38353978
//private void menuProjectProperties_Click(object sender, RoutedEventArgs e)
38363979
//{
38373980
// var proj = GetSelectedProject();

‎UnityLauncherPro/Properties/Settings.Designer.cs

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎UnityLauncherPro/Properties/Settings.settings

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,11 @@
148148
<Setting Name="checkSRP" Type="System.Boolean" Scope="User">
149149
<Value Profile="(Default)">False</Value>
150150
</Setting>
151+
<Setting Name="useUnofficialReleaseList" Type="System.Boolean" Scope="User">
152+
<Value Profile="(Default)">False</Value>
153+
</Setting>
154+
<Setting Name="disableUnityHubLaunch" Type="System.Boolean" Scope="User">
155+
<Value Profile="(Default)">False</Value>
156+
</Setting>
151157
</Settings>
152158
</SettingsFile>

‎UnityLauncherPro/Tools.cs

Lines changed: 194 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ public static bool LaunchExplorerSelectFile(string fileName)
488488
}
489489

490490
// run any exe, return process
491-
public static Process LaunchExe(string path, string param = null, bool captureOutput=false)
491+
public static Process LaunchExe(string path, string param = null, bool captureOutput = false)
492492
{
493493
if (string.IsNullOrEmpty(path)) return null;
494494

@@ -526,8 +526,8 @@ public static Process LaunchExe(string path, string param = null, bool captureOu
526526
}
527527
return newProcess;
528528
}
529-
// Console.WriteLine("Failed to run exe: " + path + " " + param);
530-
// return null;
529+
// Console.WriteLine("Failed to run exe: " + path + " " + param);
530+
// return null;
531531
}
532532

533533

@@ -673,6 +673,13 @@ public static async void DownloadInBrowser(string version, bool preferFullInstal
673673
if (version == null) return;
674674
string exeURL = await GetUnityUpdates.FetchDownloadUrl(version);
675675

676+
// null from unity api? then try direct download
677+
// https://beta.unity3d.com/download/330fbefc18b7/UnityDownloadAssistant-6000.1.0a8.exe
678+
if (exeURL == null)
679+
{
680+
Console.WriteLine("TODO DownloadInBrowser");
681+
}
682+
676683
if (preferFullInstaller == true)
677684
{
678685
exeURL = exeURL.Replace("UnityDownloadAssistant-" + version + ".exe", "Windows64EditorInstaller/UnitySetup64-" + version + ".exe");
@@ -837,6 +844,8 @@ static void DeleteTempFile(string path)
837844

838845
public static string DownloadHTML(string url)
839846
{
847+
Console.WriteLine("DownloadHTML: " + url);
848+
840849
if (string.IsNullOrEmpty(url) == true) return null;
841850
using (WebClient client = new WebClient())
842851
{
@@ -872,6 +881,187 @@ public static string CleanVersionNumber(string version)
872881
return version;
873882
}
874883

884+
// TODO only hash version is used, cleanup the rest
885+
public static string ParseDownloadURLFromWebpage(string version, string hash = null, bool preferFullInstaller = false, bool useHash = false)
886+
{
887+
string exeURL = "";
888+
889+
//Console.WriteLine("ParseDownloadURLFromWebpage: " + version + ", hash: " + useHash);
890+
891+
if (string.IsNullOrEmpty(version)) return null;
892+
893+
// NOTE no longer uses f# in the end
894+
895+
string url = null;
896+
if (useHash == false)
897+
{
898+
var cleanVersion = CleanVersionNumber(version);
899+
// NOTE 2024 June, installs are now located on separate pages, like https://unity.com/releases/editor/whats-new/6000.0.5#installs
900+
901+
// get correct page url
902+
//url = "https://unity3d.com/get-unity/download/archive";
903+
// fix unity server problem, some pages says 404 found if no url params
904+
url = "https://unity.com/releases/editor/whats-new/" + cleanVersion + "?unitylauncherpro#installs";
905+
//if (VersionIsPatch(version)) url = "https://unity3d.com/unity/qa/patch-releases";
906+
if (VersionIsBeta(version)) url = "https://unity.com/releases/editor/beta/" + version;
907+
if (VersionIsAlpha(version)) url = "https://unity.com/releases/editor/alpha/" + version;
908+
//url += "?unitylauncherpro";
909+
}
910+
else
911+
{
912+
// NOTE version here is actually VERSION|HASH
913+
//string hash = version;
914+
url = $"https://beta.unity3d.com/download/{hash}/download.html";
915+
916+
//Console.WriteLine("hashurl: " + url);
917+
918+
//version = FetchUnityVersionNumberFromHTML(url);
919+
//Console.WriteLine(url);
920+
//Console.WriteLine("got "+version);
921+
if (string.IsNullOrEmpty(version))
922+
{
923+
SetStatus("Failed to get version (" + version + ") number from hash: " + hash);
924+
return null;
925+
}
926+
}
927+
928+
//Console.WriteLine("scanning installers from url: " + url);
929+
930+
//string sourceHTML = DownloadHTML(url);
931+
932+
//if (string.IsNullOrEmpty(sourceHTML) == true)
933+
//{
934+
// Console.WriteLine("Failed to download html from: " + url);
935+
// return null;
936+
//}
937+
938+
//// parse changeset hash from html
939+
//string pattern = $@"href=""unityhub://{version}/([^""]+)""";
940+
//Regex regex = new Regex(pattern);
941+
//Match match = regex.Match(sourceHTML);
942+
943+
//if (match.Success == true)
944+
//{
945+
// string changeSet = match.Groups[1].Value;
946+
// Console.WriteLine("changeSet: " + changeSet);
947+
//}
948+
949+
exeURL = $"https://beta.unity3d.com/download/{hash}/UnityDownloadAssistant-{version}.exe";
950+
//string[] lines = sourceHTML.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
951+
952+
// patch version download assistant finder
953+
//if (useHash == false && VersionIsPatch(version))
954+
//{
955+
// for (int i = 0; i < lines.Length; i++)
956+
// {
957+
// //if (lines[i].Contains("UnityDownloadAssistant-" + version + ".exe"))
958+
// if (lines[i].Contains("UnitySetup64-" + version + ".exe"))
959+
// {
960+
// int start = lines[i].IndexOf('"') + 1;
961+
// int end = lines[i].IndexOf('"', start);
962+
// exeURL = lines[i].Substring(start, end - start);
963+
// break;
964+
// }
965+
// }
966+
//}
967+
//else if (useHash == false && VersionIsArchived(version))
968+
//{
969+
// // archived version download assistant finder
970+
// for (int i = 0; i < lines.Length; i++)
971+
// {
972+
// // find line where full installer is (from archive page)
973+
// if (lines[i].Contains("UnitySetup64-" + version))
974+
// {
975+
976+
// Console.WriteLine(lines[i]);
977+
978+
// // take full exe installer line, to have changeset hash, then replace with download assistant filepath
979+
// string line = lines[i];
980+
// int start = line.IndexOf('"') + 1;
981+
// int end = line.IndexOf('"', start);
982+
// exeURL = line.Substring(start, end - start);
983+
// exeURL = exeURL.Replace("Windows64EditorInstaller/UnitySetup64-", "UnityDownloadAssistant-");
984+
// break;
985+
// }
986+
// }
987+
//}
988+
//else // alpha or beta version download assistant finder
989+
//{
990+
// // regular beta
991+
// // <a href="https://beta.unity3d.com/download/21aeb48b6ed2/UnityDownloadAssistant.exe">
992+
// // https://beta.unity3d.com/download/21aeb48b6ed2/UnityDownloadAssistant.exe
993+
994+
// // hidden beta
995+
// // <a href='UnityDownloadAssistant-6000.0.0b15.exe'>
996+
// // https://beta.unity3d.com/download/8008bc0c1b74/UnityDownloadAssistant-6000.0.0b15.exe
997+
998+
// // new 10.06.2024, no more downloadassistant.exe in html
999+
1000+
// // check html lines
1001+
// for (int i = 0; i < lines.Length; i++)
1002+
// {
1003+
// //Console.WriteLine(lines[i]);
1004+
// //if (lines[i].Contains("UnityDownloadAssistant"))
1005+
// if (lines[i].Contains("UnityDownloadAssistant"))
1006+
// {
1007+
// if (useHash == false)
1008+
// {
1009+
// string pattern = @"https://beta\.unity3d\.com/download/[a-zA-Z0-9]+/UnityDownloadAssistant\.exe";
1010+
// Match match = Regex.Match(lines[i], pattern);
1011+
// if (match.Success)
1012+
// {
1013+
// exeURL = match.Value;
1014+
// }
1015+
// else
1016+
// {
1017+
// Console.WriteLine("No match found for download base url..");
1018+
// }
1019+
// }
1020+
// else // hidden download page
1021+
// {
1022+
// string pattern = @"UnityDownloadAssistant(?:-\d+\.\d+\.\d+[bf]\d*)?\.exe";
1023+
// Match match = Regex.Match(lines[i], pattern);
1024+
// if (match.Success)
1025+
// {
1026+
// // append base url
1027+
// Regex regex = new Regex(@"(https://beta\.unity3d\.com/download/[a-zA-Z0-9]+/)");
1028+
// Match match2 = regex.Match(url);
1029+
1030+
// //Console.WriteLine("source url: " + url);
1031+
1032+
// if (match2.Success)
1033+
// {
1034+
// string capturedUrl = match2.Groups[1].Value;
1035+
// exeURL = capturedUrl + match.Value;
1036+
// }
1037+
// else
1038+
// {
1039+
// Console.WriteLine("No match found for download base url..");
1040+
// }
1041+
// }
1042+
// break;
1043+
// }
1044+
// }
1045+
// } // for lines
1046+
//} // alpha or beta
1047+
1048+
// download full installer instead, TODO probably not needed anymore?
1049+
if (useHash == false && preferFullInstaller == true)
1050+
{
1051+
exeURL = exeURL.Replace("UnityDownloadAssistant-" + version + ".exe", "Windows64EditorInstaller/UnitySetup64-" + version + ".exe");
1052+
// handle alpha/beta
1053+
exeURL = exeURL.Replace("UnityDownloadAssistant.exe", "Windows64EditorInstaller/UnitySetup64-" + version + ".exe");
1054+
}
1055+
1056+
// didnt find installer
1057+
if (string.IsNullOrEmpty(exeURL))
1058+
{
1059+
//SetStatus("Cannot find UnityDownloadAssistant.exe for this version.");
1060+
Console.WriteLine("Installer not found from URL: " + url);
1061+
}
1062+
return exeURL;
1063+
}
1064+
8751065
private static string FetchUnityVersionNumberFromHTML(string url)
8761066
{
8771067
string sourceHTML = DownloadHTML(url);
@@ -891,7 +1081,7 @@ private static string FetchUnityVersionNumberFromHTML(string url)
8911081
}
8921082
else
8931083
{
894-
Console.WriteLine("No match found.");
1084+
Console.WriteLine("FetchUnityVersionNumberFromHTML: No match found.");
8951085
}
8961086

8971087
return null;

‎UnityLauncherPro/UpgradeWindow.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
66
xmlns:local="clr-namespace:UnityLauncherPro"
77
mc:Ignorable="d"
8-
Title="Upgrade Project Version" Height="533.165" Width="552" Background="{DynamicResource ThemeDarkestBackground}" MinWidth="319" MinHeight="555" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewKeyDown="Window_PreviewKeyDown" ShowInTaskbar="False">
8+
Title="Upgrade Project Version" Height="540" Width="580" Background="{DynamicResource ThemeDarkestBackground}" MinWidth="319" MinHeight="555" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewKeyDown="Window_PreviewKeyDown" ShowInTaskbar="False">
99

1010
<Grid>
1111
<StackPanel Orientation="Horizontal">

0 commit comments

Comments
 (0)
Please sign in to comment.