|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.IO; |
| 4 | +using System.Net.Http; |
| 5 | +using System.Text; |
4 | 6 | using System.Windows; |
5 | 7 | using System.Windows.Controls; |
6 | 8 | using System.Windows.Input; |
7 | 9 | using System.Windows.Media; |
8 | 10 | using UnityLauncherPro.Data; |
| 11 | +using UnityLauncherPro.Properties; |
9 | 12 |
|
10 | 13 | namespace UnityLauncherPro |
11 | 14 | { |
@@ -35,6 +38,8 @@ public NewProject(string unityVersion, string suggestedName, string targetFolder |
35 | 38 | // TODO could optionally disable templates in settings |
36 | 39 | _ = LoadOnlineTemplatesAsync(); |
37 | 40 |
|
| 41 | + LoadSettings(); |
| 42 | + |
38 | 43 | // get version |
39 | 44 | newVersion = unityVersion; |
40 | 45 | newName = suggestedName; |
@@ -83,6 +88,11 @@ public NewProject(string unityVersion, string suggestedName, string targetFolder |
83 | 88 | isInitializing = false; |
84 | 89 | } // NewProject |
85 | 90 |
|
| 91 | + private void LoadSettings() |
| 92 | + { |
| 93 | + chkForceDX11.IsChecked = Settings.Default.forceDX11; |
| 94 | + } |
| 95 | + |
86 | 96 | void UpdateTemplatesDropDown(string unityPath) |
87 | 97 | { |
88 | 98 | // scan available templates, TODO could cache this at least per session? |
@@ -296,7 +306,9 @@ private void GridAvailableVersions_SelectionChanged(object sender, SelectionChan |
296 | 306 |
|
297 | 307 | // hide forceDX11 checkbox if version is below 6000 |
298 | 308 | bool is6000 = k.Version.Contains("6000"); |
299 | | - chkForceDX11.Visibility = is6000 ? Visibility.Visible : Visibility.Collapsed; |
| 309 | + lblOverride.Visibility = chkForceDX11.Visibility = is6000 ? Visibility.Visible : Visibility.Collapsed; |
| 310 | + //chkForceDX11.IsChecked = chkForceDX11.Visibility == Visibility.Visible ? forceDX11 : false; |
| 311 | + forceDX11 = Settings.Default.forceDX11 && is6000; |
300 | 312 | } |
301 | 313 |
|
302 | 314 | private void GridAvailableVersions_Loaded(object sender, RoutedEventArgs e) |
@@ -334,7 +346,10 @@ private void gridAvailableVersions_PreviewMouseDoubleClick(object sender, MouseB |
334 | 346 |
|
335 | 347 | private void chkForceDX11_Checked(object sender, RoutedEventArgs e) |
336 | 348 | { |
337 | | - forceDX11 = chkForceDX11.IsChecked == true; |
| 349 | + if (isInitializing) return; // Don't save during initialization |
| 350 | + |
| 351 | + Settings.Default.forceDX11 = forceDX11; |
| 352 | + Settings.Default.Save(); |
338 | 353 | } |
339 | 354 |
|
340 | 355 | private void btnBrowseForProjectFolder_Click(object sender, RoutedEventArgs e) |
@@ -405,55 +420,181 @@ private void btnCreateMissingFolder_Click(object sender, RoutedEventArgs e) |
405 | 420 |
|
406 | 421 | private async System.Threading.Tasks.Task LoadOnlineTemplatesAsync() |
407 | 422 | { |
408 | | - // Simulate async loading (replace with actual async HTTP call later) |
409 | | - await System.Threading.Tasks.Task.Run(() => |
| 423 | + try |
410 | 424 | { |
411 | | - var templates = new List<OnlineTemplateItem> |
412 | | - { |
413 | | - new OnlineTemplateItem |
| 425 | + using (var client = new HttpClient()) |
| 426 | + { |
| 427 | + client.DefaultRequestHeaders.Add("Accept", "application/json"); |
| 428 | + |
| 429 | + // Build JSON manually |
| 430 | + var graphqlJson = "{\"query\":\"fragment TemplateEntity on Template { __typename name packageName description type buildPlatforms renderPipeline previewImage { url } versions { name tarball { url } } } query HUB__getTemplates($limit: Int! $skip: Int! $orderBy: TemplateOrder! $supportedUnityEditorVersions: [String!]!) { getTemplates(limit: $limit skip: $skip orderBy: $orderBy supportedUnityEditorVersions: $supportedUnityEditorVersions) { edges { node { ...TemplateEntity } } } }\",\"variables\":{\"limit\":50,\"skip\":0,\"orderBy\":\"WEIGHTED_DESC\",\"supportedUnityEditorVersions\":[\"6000.0\"]}}"; |
| 431 | + |
| 432 | + var content = new StringContent(graphqlJson, Encoding.UTF8, "application/json"); |
| 433 | + |
| 434 | + var response = await client.PostAsync("https://live-platform-api.prd.ld.unity3d.com/graphql", content); |
| 435 | + |
| 436 | + if (response.IsSuccessStatusCode) |
| 437 | + { |
| 438 | + var responseString = await response.Content.ReadAsStringAsync(); |
| 439 | + var templates = ParseTemplatesFromJson(responseString); |
| 440 | + |
| 441 | + // Update UI on dispatcher thread |
| 442 | + Dispatcher.Invoke(() => |
| 443 | + { |
| 444 | + listOnlineTemplates.Items.Clear(); |
| 445 | + listOnlineTemplates.ItemsSource = templates; |
| 446 | + }); |
| 447 | + } |
| 448 | + else |
| 449 | + { |
| 450 | + Console.WriteLine($"GraphQL request failed: {response.StatusCode}"); |
| 451 | + LoadFallbackTemplates(); |
| 452 | + } |
| 453 | + } |
| 454 | + } |
| 455 | + catch (Exception ex) |
414 | 456 | { |
415 | | - Name = "3D Template", |
416 | | - Description = "A great starting point for 3D projects using the Universal Render Pipeline (URP).", |
417 | | - PreviewImageURL = "https://storage.googleapis.com/live-platform-resources-prd/templates/assets/AR_Mobile_Thumbnail_HUB_464008d11a/AR_Mobile_Thumbnail_HUB_464008d11a.png", |
418 | | - Type = "CORE", |
419 | | - RenderPipeline = "URP", |
420 | | - TarBallURL = "https://download.packages.unity.com/com.unity.template.hdrp-blank/-/com.unity.template.hdrp-blank-17.0.2.tgz" |
421 | | - }, |
422 | | - new OnlineTemplateItem |
| 457 | + Console.WriteLine($"Error loading online templates: {ex.Message}"); |
| 458 | + LoadFallbackTemplates(); |
| 459 | + } |
| 460 | + } |
| 461 | + |
| 462 | + private List<OnlineTemplateItem> ParseTemplatesFromJson(string json) |
| 463 | + { |
| 464 | + var templates = new List<OnlineTemplateItem>(); |
| 465 | + |
| 466 | + try |
423 | 467 | { |
424 | | - Name = "2D Template", |
425 | | - Description = "A great starting point for 2D projects using the Built-in Render Pipeline.", |
426 | | - PreviewImageURL = "https://storage.googleapis.com/live-platform-resources-prd/templates/assets/Platformer_preview_887cd85a63/Platformer_preview_887cd85a63.png", |
427 | | - Type = "CORE", |
428 | | - RenderPipeline = "Built-in", |
429 | | - TarBallURL = "https://download.packages.unity.com/com.unity.template.mr-multiplayer/-/com.unity.template.mr-multiplayer-1.0.3.tgz" |
430 | | - }, |
431 | | - new OnlineTemplateItem |
| 468 | + // Find the edges array |
| 469 | + int edgesStart = json.IndexOf("\"edges\":"); |
| 470 | + if (edgesStart == -1) return templates; |
| 471 | + |
| 472 | + // Find all node objects |
| 473 | + int currentPos = edgesStart; |
| 474 | + while (true) |
| 475 | + { |
| 476 | + int nodeStart = json.IndexOf("{\"__typename\":\"Template\"", currentPos); |
| 477 | + if (nodeStart == -1) break; |
| 478 | + |
| 479 | + // Find the end of this node object (simplified - find matching brace) |
| 480 | + int nodeEnd = FindMatchingBrace(json, nodeStart); |
| 481 | + if (nodeEnd == -1) break; |
| 482 | + |
| 483 | + string nodeJson = json.Substring(nodeStart, nodeEnd - nodeStart + 1); |
| 484 | + |
| 485 | + // Parse individual fields |
| 486 | + var template = new OnlineTemplateItem |
| 487 | + { |
| 488 | + Name = ExtractJsonString(nodeJson, "\"name\""), |
| 489 | + Description = ExtractJsonString(nodeJson, "\"description\""), |
| 490 | + Type = ExtractJsonString(nodeJson, "\"type\""), |
| 491 | + RenderPipeline = ExtractJsonString(nodeJson, "\"renderPipeline\""), |
| 492 | + PreviewImageURL = ExtractNestedJsonString(nodeJson, "\"previewImage\"", "\"url\"") ?? "pack://application:,,,/Images/icon.png", |
| 493 | + TarBallURL = ExtractNestedJsonString(nodeJson, "\"tarball\"", "\"url\"") |
| 494 | + }; |
| 495 | + |
| 496 | + templates.Add(template); |
| 497 | + currentPos = nodeEnd + 1; |
| 498 | + } |
| 499 | + } |
| 500 | + catch (Exception ex) |
432 | 501 | { |
433 | | - Name = "Wubba Template", |
434 | | - Description = "A great asdfasdf projects using.", |
435 | | - PreviewImageURL = "https://storage.googleapis.com/live-platform-resources-prd/templates/assets/2_4_1_Overview_627c09d1be/2_4_1_Overview_627c09d1be.png", |
436 | | - Type = "SAMPLES", |
437 | | - RenderPipeline = "URP", |
438 | | - TarBallURL = "https://download.packages.unity.com/com.unity.template.vr/-/com.unity.template.vr-9.2.0.tgz" |
439 | | - }, |
440 | | - new OnlineTemplateItem |
| 502 | + Console.WriteLine($"Error parsing templates: {ex.Message}"); |
| 503 | + } |
| 504 | + |
| 505 | + return templates; |
| 506 | + } |
| 507 | + |
| 508 | + private string ExtractJsonString(string json, string key) |
| 509 | + { |
| 510 | + int keyIndex = json.IndexOf(key + ":"); |
| 511 | + if (keyIndex == -1) return null; |
| 512 | + |
| 513 | + int valueStart = json.IndexOf("\"", keyIndex + key.Length + 1); |
| 514 | + if (valueStart == -1) return null; |
| 515 | + |
| 516 | + int valueEnd = json.IndexOf("\"", valueStart + 1); |
| 517 | + if (valueEnd == -1) return null; |
| 518 | + |
| 519 | + return json.Substring(valueStart + 1, valueEnd - valueStart - 1); |
| 520 | + } |
| 521 | + |
| 522 | + private string ExtractNestedJsonString(string json, string parentKey, string childKey) |
| 523 | + { |
| 524 | + int parentIndex = json.IndexOf(parentKey + ":"); |
| 525 | + if (parentIndex == -1) return null; |
| 526 | + |
| 527 | + // Find the object after parentKey |
| 528 | + int objectStart = json.IndexOf("{", parentIndex); |
| 529 | + if (objectStart == -1) return null; |
| 530 | + |
| 531 | + int objectEnd = FindMatchingBrace(json, objectStart); |
| 532 | + if (objectEnd == -1) return null; |
| 533 | + |
| 534 | + string nestedJson = json.Substring(objectStart, objectEnd - objectStart + 1); |
| 535 | + return ExtractJsonString(nestedJson, childKey); |
| 536 | + } |
| 537 | + |
| 538 | + private int FindMatchingBrace(string json, int openBraceIndex) |
| 539 | + { |
| 540 | + int braceCount = 0; |
| 541 | + bool inString = false; |
| 542 | + bool escapeNext = false; |
| 543 | + |
| 544 | + for (int i = openBraceIndex; i < json.Length; i++) |
441 | 545 | { |
442 | | - Name = "ASDF Template", |
443 | | - Description = "A great asdfasdf projects using.", |
444 | | - PreviewImageURL = "https://storage.googleapis.com/live-platform-resources-prd/templates/assets/HDRP_c27702ce66/HDRP_c27702ce66.jpg", |
445 | | - Type = "LEARNING", |
446 | | - RenderPipeline = "HDRP", |
447 | | - TarBallURL = "https://download.packages.unity.com/com.unity.template.platformer/-/com.unity.template.platformer-5.0.5.tgz" |
| 546 | + char c = json[i]; |
| 547 | + |
| 548 | + if (escapeNext) |
| 549 | + { |
| 550 | + escapeNext = false; |
| 551 | + continue; |
| 552 | + } |
| 553 | + |
| 554 | + if (c == '\\') |
| 555 | + { |
| 556 | + escapeNext = true; |
| 557 | + continue; |
| 558 | + } |
| 559 | + |
| 560 | + if (c == '"') |
| 561 | + { |
| 562 | + inString = !inString; |
| 563 | + continue; |
| 564 | + } |
| 565 | + |
| 566 | + if (!inString) |
| 567 | + { |
| 568 | + if (c == '{') braceCount++; |
| 569 | + else if (c == '}') |
| 570 | + { |
| 571 | + braceCount--; |
| 572 | + if (braceCount == 0) return i; |
| 573 | + } |
| 574 | + } |
448 | 575 | } |
449 | | - }; |
450 | 576 |
|
451 | | - // Update UI on dispatcher thread |
452 | | - Dispatcher.Invoke(() => |
| 577 | + return -1; |
| 578 | + } |
| 579 | + |
| 580 | + private void LoadFallbackTemplates() |
| 581 | + { |
| 582 | + var templates = new List<OnlineTemplateItem> |
| 583 | + { |
| 584 | + new OnlineTemplateItem |
453 | 585 | { |
454 | | - listOnlineTemplates.Items.Clear(); |
455 | | - listOnlineTemplates.ItemsSource = templates; |
456 | | - }); |
| 586 | + Name = "3D Template", |
| 587 | + Description = "A great starting point for 3D projects using the Universal Render Pipeline (URP).", |
| 588 | + PreviewImageURL = "pack://application:,,,/Images/icon.png", |
| 589 | + Type = "CORE", |
| 590 | + RenderPipeline = "URP" |
| 591 | + } |
| 592 | + }; |
| 593 | + |
| 594 | + Dispatcher.Invoke(() => |
| 595 | + { |
| 596 | + listOnlineTemplates.Items.Clear(); |
| 597 | + listOnlineTemplates.ItemsSource = templates; |
457 | 598 | }); |
458 | 599 | } |
459 | 600 | } |
|
0 commit comments