@atelierai/uco 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -8
- package/package.json +2 -2
- package/vendor/plugin/com.atelierai.unity.copilot/CHANGELOG.md +4 -4
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetConfig.cs +132 -132
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetDependencyResolver.cs +237 -237
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetDownloader.cs +82 -82
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Resource/MenuItems.cs +247 -247
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Resource/ToolGroups.cs +153 -153
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/SystemTool/Skills.Create.SkillBody.cs +155 -155
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Console.GetLogs.cs +95 -95
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Docs.HttpFetcher.cs +139 -139
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Instance.ListAll.cs +72 -72
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/PathReadHelper.cs +106 -106
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Script.Validate.cs +252 -252
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Tests/TestResultCollector.cs +537 -537
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Tests.cs +400 -400
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/ToolGroups.SetEnabled.cs +92 -92
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Branding/ProductInfo.cs +62 -62
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/CopilotServerManager.cs +887 -1034
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Skills/Skill_InitialSetup.cs +197 -197
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Startup.Editor.cs +201 -201
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Startup.cs +67 -67
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/CopilotListWindowBase.cs +393 -393
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/CopilotWindowBase.cs +113 -113
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.Connection.cs +3 -3
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CopilotFeatures.cs +195 -195
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CopilotServer.cs +22 -22
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CreateGUI.cs +354 -354
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.cs +78 -78
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowInitializer.cs +47 -47
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/SerializationCheckWindow.cs +190 -190
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Build.cs +91 -91
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Config.cs +298 -298
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Static.cs +296 -296
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.cs +69 -69
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/PackageUtils.cs +168 -168
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/PrefsKeyMigration.cs +119 -119
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/SafeDefaultsGuard.cs +180 -180
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ScriptUtils.cs +229 -229
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ToolGroupRegistry.cs +461 -460
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ToolsManifestGenerator.cs +200 -200
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityAuthoringAdapters.cs +1467 -1467
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityAuthoringSafetyReloadGuard.cs +65 -65
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityCopilotUpdateProjectSettings.cs +66 -66
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotPromptsWindow.uss +11 -11
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotResourcesWindow.uss +16 -16
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotToolsWindow.uss +36 -36
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/MainWindow.uss +183 -183
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/{_mcp-list-window.uss → _copilot-list-window.uss} +18 -18
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/_list-view.uss +77 -77
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotPromptsWindow.uxml +18 -18
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotResourcesWindow.uxml +18 -18
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotToolsWindow.uxml +18 -18
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/MainWindow.uxml +115 -115
- package/vendor/plugin/com.atelierai.unity.copilot/Plugins/ReflectorNet.dll +0 -0
- package/vendor/plugin/com.atelierai.unity.copilot/Plugins/Uco.Framework.Common.dll +0 -0
- package/vendor/plugin/com.atelierai.unity.copilot/Plugins/Uco.Framework.dll +0 -0
- package/vendor/plugin/com.atelierai.unity.copilot/README.md +88 -88
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Converter/Json/Structures/EntityIdConverter.cs +120 -120
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Data/GameObjectMetadata.cs +110 -110
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Data/GameObjectMetadata.pre-Unity.6.5.cs +110 -110
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Unity/Logs/FileLogStorage.cs +547 -547
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.Build.cs +243 -243
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.Config.cs +3 -3
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.cs +295 -295
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginBuilder.cs +105 -105
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginRuntime.Static.cs +155 -155
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginRuntime.cs +59 -59
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Utils/EnvironmentUtils.cs +11 -11
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AtomicApi/AtomicApiTestFixtures.cs +99 -99
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AtomicApi/TryModifyAtTests.cs +227 -227
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AuthoringSafetyPilotTests.cs +1050 -1050
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetExtractorDevelopmentDependencyTests.cs +148 -148
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetExtractorFlatLayoutTests.cs +166 -166
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetInstallManifestTests.cs +436 -436
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetLegacyMigrationTests.cs +304 -304
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetPackageInstallerStaleVersionCleanupTests.cs +200 -200
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Environment/EnvironmentUtilsTests.cs +2 -2
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/BlacklistTypeTests.cs +416 -416
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataFieldScriptableObjectPopulationTests.cs +172 -172
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataFieldScriptableObjectPopulationTests.pre-Unity.6.5.cs +169 -169
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPopulationTests.cs +182 -182
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPopulationTests.pre-Unity.6.5.cs +179 -179
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyPopulationTests.cs +175 -175
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyPopulationTests.pre-Unity.6.5.cs +174 -174
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyScriptableObjectPopulationTests.cs +171 -171
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyScriptableObjectPopulationTests.pre-Unity.6.5.cs +170 -170
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsCreateFolderTests.cs +243 -243
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsMaterialTests.cs +101 -101
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsPrefabCreateTests.cs +348 -348
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsPrefabCreateTests.pre-Unity.6.5.cs +348 -348
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsShaderTests.cs +194 -194
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/GameObject/TestJsonSchema.cs +199 -199
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/PathBasedToolTests.cs +573 -573
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/PathBasedToolTests.pre-Unity.6.5.cs +513 -513
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotCameraTests.cs +154 -154
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotCameraTests.pre-Unity.6.5.cs +154 -154
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotGameViewTests.cs +164 -164
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotSceneViewTests.cs +155 -155
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolParameterTests.cs +56 -56
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolThreadSafetyTests.cs +651 -651
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolThreadSafetyTests.pre-Unity.6.5.cs +651 -651
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ToolBatchExecutionIntegrationTests.cs +407 -407
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/{McpPluginTests.cs → UcoPluginTests.cs} +105 -105
- package/vendor/plugin/com.atelierai.unity.copilot/package.json +1 -1
- /package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/{_mcp-list-window.uss.meta → _copilot-list-window.uss.meta} +0 -0
- /package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/{McpPluginTests.cs.meta → UcoPluginTests.cs.meta} +0 -0
|
@@ -1,237 +1,237 @@
|
|
|
1
|
-
/*
|
|
2
|
-
+------------------------------------------------------------------+
|
|
3
|
-
| Author: Ivan Murzak (https://github.com/IvanMurzak) |
|
|
4
|
-
| Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) |
|
|
5
|
-
| Copyright (c) 2025 Ivan Murzak |
|
|
6
|
-
| Licensed under the Apache License, Version 2.0. |
|
|
7
|
-
| See the LICENSE file in the project root for more information. |
|
|
8
|
-
+------------------------------------------------------------------+
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
#nullable enable
|
|
12
|
-
using System;
|
|
13
|
-
using System.Collections.Generic;
|
|
14
|
-
using UnityEditor;
|
|
15
|
-
using UnityEditor.PackageManager;
|
|
16
|
-
using UnityEngine;
|
|
17
|
-
using PackageManagerEvents = UnityEditor.PackageManager.Events;
|
|
18
|
-
|
|
19
|
-
namespace com.AtelierAI.Unity.Copilot.Editor.DependencyResolver
|
|
20
|
-
{
|
|
21
|
-
/// <summary>
|
|
22
|
-
/// Entry point for NuGet dependency management. Runs on every domain reload via [InitializeOnLoad]
|
|
23
|
-
/// AND in response to UPM package upgrades via PackageManager.Events.registeredPackages.
|
|
24
|
-
///
|
|
25
|
-
/// This assembly has ZERO external dependencies — it always compiles, even when the main plugin
|
|
26
|
-
/// fails due to missing or conflicting DLLs. It downloads NuGet packages directly from nuget.org,
|
|
27
|
-
/// extracts DLLs, skips assemblies Unity already provides, and sets the UNITY_COPILOT_READY define
|
|
28
|
-
/// so the main plugin assemblies can compile.
|
|
29
|
-
///
|
|
30
|
-
/// Why both triggers are needed:
|
|
31
|
-
/// [InitializeOnLoad] fires after a *successful* project-wide recompile. When a user upgrades
|
|
32
|
-
/// the Unity package and the new code references newer NuGet APIs whose DLL is still on disk
|
|
33
|
-
/// at the old version, the post-import recompile fails, Unity blocks the domain reload, and
|
|
34
|
-
/// the new resolver's static constructor never runs. The previous AppDomain is still alive
|
|
35
|
-
/// though — and so are its event subscriptions. registeredPackages fires from the still-alive
|
|
36
|
-
/// AppDomain after UPM writes new package files but before the failed recompile, giving us a
|
|
37
|
-
/// chance to clean up stale DLLs and unblock the next compile attempt. See Unity-
|
|
38
|
-
///
|
|
39
|
-
/// Flow on domain reload:
|
|
40
|
-
/// 1. [InitializeOnLoad] fires
|
|
41
|
-
/// 2. Deferred via EditorApplication.update (runs without editor focus, unlike delayCall)
|
|
42
|
-
/// 3. NuGetPackageRestorer checks if all packages are installed
|
|
43
|
-
/// 4. Downloads and installs any missing packages, removes stale-version siblings
|
|
44
|
-
/// 5. Sets UNITY_COPILOT_READY scripting define
|
|
45
|
-
/// 6. If packages were installed: triggers AssetDatabase.Refresh() → domain reload
|
|
46
|
-
/// 7. On next reload: everything is in place, main plugin compiles
|
|
47
|
-
///
|
|
48
|
-
/// Flow on UPM package change (no domain reload required to invoke):
|
|
49
|
-
/// 1. registeredPackages fires from the previous AppDomain
|
|
50
|
-
/// 2. NuGetPackageRestorer.Restore() runs the same install + cleanup logic
|
|
51
|
-
/// 3. AssetDatabase.Refresh() prompts Unity to retry compilation with the corrected DLL set
|
|
52
|
-
/// 4. On the resulting successful reload, [InitializeOnLoad] resumes the normal path
|
|
53
|
-
/// </summary>
|
|
54
|
-
[InitializeOnLoad]
|
|
55
|
-
static class NuGetDependencyResolver
|
|
56
|
-
{
|
|
57
|
-
const string Tag = "[Unity-
|
|
58
|
-
|
|
59
|
-
static NuGetDependencyResolver()
|
|
60
|
-
{
|
|
61
|
-
// In CI, skip runtime resolution — DLLs are committed to git
|
|
62
|
-
// and UNITY_COPILOT_READY should already be in ProjectSettings.
|
|
63
|
-
// Setting defines at runtime in batch mode causes "Error building Player
|
|
64
|
-
// because scripts are compiling" when the test runner races the recompilation.
|
|
65
|
-
if (IsCi())
|
|
66
|
-
{
|
|
67
|
-
RecompileGate.EnsureReadyDefine();
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
EditorApplication.update += ResolveOnce;
|
|
72
|
-
|
|
73
|
-
// Subscribe to UPM package-change events so that when the user upgrades a package
|
|
74
|
-
// whose new code references a newer NuGet DLL than the one currently on disk, we
|
|
75
|
-
// can run the cleanup + restore from the still-alive AppDomain. The compile that
|
|
76
|
-
// would otherwise fail (and block [InitializeOnLoad] in the next domain) gets
|
|
77
|
-
// retried by Unity once AssetDatabase.Refresh() picks up the corrected DLL set.
|
|
78
|
-
// -= before += guards against accidental double-subscription if a hot-reload path
|
|
79
|
-
// ever re-runs this constructor without a full domain swap.
|
|
80
|
-
PackageManagerEvents.registeredPackages -= OnRegisteredPackages;
|
|
81
|
-
PackageManagerEvents.registeredPackages += OnRegisteredPackages;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/// <summary>
|
|
85
|
-
/// Tracks whether a UPM-event-triggered restore is currently in flight, so a second
|
|
86
|
-
/// event burst (UPM can fire multiple registeredPackages events for a single user
|
|
87
|
-
/// action) doesn't kick off a parallel restore.
|
|
88
|
-
/// </summary>
|
|
89
|
-
static bool isRestoringFromPackageEvent;
|
|
90
|
-
|
|
91
|
-
static void OnRegisteredPackages(PackageRegistrationEventArgs args)
|
|
92
|
-
{
|
|
93
|
-
if (isRestoringFromPackageEvent)
|
|
94
|
-
return;
|
|
95
|
-
|
|
96
|
-
// Cheap pre-filter: if no packages were added, removed, or upgraded, there is no
|
|
97
|
-
// possibility of a NuGet-dep version change. Skip the heavier AllPackagesInstalled()
|
|
98
|
-
// probe to avoid touching disk on every UPM ping.
|
|
99
|
-
if ((args.added == null || args.added.Count == 0)
|
|
100
|
-
&& (args.removed == null || args.removed.Count == 0)
|
|
101
|
-
&& (args.changedFrom == null || args.changedFrom.Count == 0)
|
|
102
|
-
&& (args.changedTo == null || args.changedTo.Count == 0))
|
|
103
|
-
{
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
isRestoringFromPackageEvent = true;
|
|
108
|
-
try
|
|
109
|
-
{
|
|
110
|
-
Debug.Log($"{Tag} UPM package change detected — running NuGet restore.");
|
|
111
|
-
RunRestoreAndRefresh();
|
|
112
|
-
}
|
|
113
|
-
catch (Exception ex)
|
|
114
|
-
{
|
|
115
|
-
// Same rationale as ResolveOnce: do NOT set UNITY_COPILOT_READY on a failed restore.
|
|
116
|
-
Debug.LogError($"{Tag} Restore from UPM event failed: {ex}");
|
|
117
|
-
}
|
|
118
|
-
finally
|
|
119
|
-
{
|
|
120
|
-
isRestoringFromPackageEvent = false;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/// <summary>
|
|
125
|
-
/// Shared core used by both ResolveOnce (post-domain-reload) and OnRegisteredPackages
|
|
126
|
-
/// (no-domain-reload UPM event path). AllPackagesInstalled() short-circuits the common
|
|
127
|
-
/// no-op case without touching the network.
|
|
128
|
-
/// </summary>
|
|
129
|
-
static void RunRestoreAndRefresh()
|
|
130
|
-
{
|
|
131
|
-
if (NuGetPackageRestorer.AllPackagesInstalled())
|
|
132
|
-
{
|
|
133
|
-
NuGetPluginConfigurator.ConfigureAll();
|
|
134
|
-
RecompileGate.EnsureReadyDefine();
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
Debug.Log($"{Tag} Restoring NuGet packages...");
|
|
139
|
-
var changed = NuGetPackageRestorer.Restore();
|
|
140
|
-
|
|
141
|
-
NuGetPluginConfigurator.ConfigureAll();
|
|
142
|
-
|
|
143
|
-
RecompileGate.EnsureReadyDefine();
|
|
144
|
-
|
|
145
|
-
if (changed)
|
|
146
|
-
{
|
|
147
|
-
Debug.Log($"{Tag} Packages restored. Refreshing AssetDatabase...");
|
|
148
|
-
AssetDatabase.Refresh();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
static void ResolveOnce()
|
|
153
|
-
{
|
|
154
|
-
EditorApplication.update -= ResolveOnce;
|
|
155
|
-
try
|
|
156
|
-
{
|
|
157
|
-
RunRestoreAndRefresh();
|
|
158
|
-
}
|
|
159
|
-
catch (Exception ex)
|
|
160
|
-
{
|
|
161
|
-
// Do NOT set UNITY_COPILOT_READY here: if restore/configuration failed, the DLL
|
|
162
|
-
// layout is unknown/inconsistent, and letting main-plugin assemblies compile
|
|
163
|
-
// against a partial/mismatched set (via defineConstraints) produces hard-to-
|
|
164
|
-
// diagnose MissingMethodException / TypeLoadException at runtime. Surface the
|
|
165
|
-
// failure loud and clear instead, so the user fixes the underlying problem
|
|
166
|
-
// and retries (the next domain reload will run Restore again).
|
|
167
|
-
Debug.LogError($"{Tag} Failed: {ex}");
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/// <summary>
|
|
172
|
-
/// Checks if the current environment is a CI environment.
|
|
173
|
-
/// Mirrors EnvironmentUtils.IsCi() but without external dependencies,
|
|
174
|
-
/// since this assembly must compile standalone.
|
|
175
|
-
/// Checks both command-line arguments and environment variables for
|
|
176
|
-
/// CI, GITHUB_ACTIONS, and TF_BUILD (Azure Pipelines).
|
|
177
|
-
/// </summary>
|
|
178
|
-
static bool IsCi()
|
|
179
|
-
{
|
|
180
|
-
var args = ParseCommandLineArguments();
|
|
181
|
-
|
|
182
|
-
var ci = GetArgOrEnv(args, "CI");
|
|
183
|
-
var gha = GetArgOrEnv(args, "GITHUB_ACTIONS");
|
|
184
|
-
var az = GetArgOrEnv(args, "TF_BUILD");
|
|
185
|
-
|
|
186
|
-
return IsTrue(ci) || IsTrue(gha) || IsTrue(az);
|
|
187
|
-
|
|
188
|
-
static string? GetArgOrEnv(Dictionary<string, string?> args, string key)
|
|
189
|
-
=> args.TryGetValue(key, out var v) ? v : Environment.GetEnvironmentVariable(key);
|
|
190
|
-
|
|
191
|
-
static bool IsTrue(string? value)
|
|
192
|
-
=> string.Equals(value?.Trim()?.Trim('"'), "true", StringComparison.OrdinalIgnoreCase);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/// <summary>
|
|
196
|
-
/// Parses Unity command-line arguments into a dictionary.
|
|
197
|
-
/// Handles both "-key value" and "-key=value" forms, plus bare flags like "-batchmode".
|
|
198
|
-
/// Keys are stored WITHOUT the leading dash.
|
|
199
|
-
/// </summary>
|
|
200
|
-
static Dictionary<string, string?> ParseCommandLineArguments()
|
|
201
|
-
{
|
|
202
|
-
var result = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
|
|
203
|
-
var rawArgs = Environment.GetCommandLineArgs();
|
|
204
|
-
|
|
205
|
-
for (var i = 0; i < rawArgs.Length; i++)
|
|
206
|
-
{
|
|
207
|
-
var arg = rawArgs[i];
|
|
208
|
-
if (!arg.StartsWith("-"))
|
|
209
|
-
continue;
|
|
210
|
-
|
|
211
|
-
var key = arg.TrimStart('-');
|
|
212
|
-
|
|
213
|
-
// Handle -key=value form
|
|
214
|
-
var eqIndex = key.IndexOf('=');
|
|
215
|
-
if (eqIndex >= 0)
|
|
216
|
-
{
|
|
217
|
-
result[key.Substring(0, eqIndex)] = key.Substring(eqIndex + 1);
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Handle -key value form (next arg is value if it doesn't start with -)
|
|
222
|
-
if (i + 1 < rawArgs.Length && !rawArgs[i + 1].StartsWith("-"))
|
|
223
|
-
{
|
|
224
|
-
result[key] = rawArgs[++i];
|
|
225
|
-
}
|
|
226
|
-
else
|
|
227
|
-
{
|
|
228
|
-
// Bare flag like -batchmode
|
|
229
|
-
result[key] = null;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return result;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
+------------------------------------------------------------------+
|
|
3
|
+
| Author: Ivan Murzak (https://github.com/IvanMurzak) |
|
|
4
|
+
| Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) |
|
|
5
|
+
| Copyright (c) 2025 Ivan Murzak |
|
|
6
|
+
| Licensed under the Apache License, Version 2.0. |
|
|
7
|
+
| See the LICENSE file in the project root for more information. |
|
|
8
|
+
+------------------------------------------------------------------+
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#nullable enable
|
|
12
|
+
using System;
|
|
13
|
+
using System.Collections.Generic;
|
|
14
|
+
using UnityEditor;
|
|
15
|
+
using UnityEditor.PackageManager;
|
|
16
|
+
using UnityEngine;
|
|
17
|
+
using PackageManagerEvents = UnityEditor.PackageManager.Events;
|
|
18
|
+
|
|
19
|
+
namespace com.AtelierAI.Unity.Copilot.Editor.DependencyResolver
|
|
20
|
+
{
|
|
21
|
+
/// <summary>
|
|
22
|
+
/// Entry point for NuGet dependency management. Runs on every domain reload via [InitializeOnLoad]
|
|
23
|
+
/// AND in response to UPM package upgrades via PackageManager.Events.registeredPackages.
|
|
24
|
+
///
|
|
25
|
+
/// This assembly has ZERO external dependencies — it always compiles, even when the main plugin
|
|
26
|
+
/// fails due to missing or conflicting DLLs. It downloads NuGet packages directly from nuget.org,
|
|
27
|
+
/// extracts DLLs, skips assemblies Unity already provides, and sets the UNITY_COPILOT_READY define
|
|
28
|
+
/// so the main plugin assemblies can compile.
|
|
29
|
+
///
|
|
30
|
+
/// Why both triggers are needed:
|
|
31
|
+
/// [InitializeOnLoad] fires after a *successful* project-wide recompile. When a user upgrades
|
|
32
|
+
/// the Unity package and the new code references newer NuGet APIs whose DLL is still on disk
|
|
33
|
+
/// at the old version, the post-import recompile fails, Unity blocks the domain reload, and
|
|
34
|
+
/// the new resolver's static constructor never runs. The previous AppDomain is still alive
|
|
35
|
+
/// though — and so are its event subscriptions. registeredPackages fires from the still-alive
|
|
36
|
+
/// AppDomain after UPM writes new package files but before the failed recompile, giving us a
|
|
37
|
+
/// chance to clean up stale DLLs and unblock the next compile attempt. See Unity-Uco#707.
|
|
38
|
+
///
|
|
39
|
+
/// Flow on domain reload:
|
|
40
|
+
/// 1. [InitializeOnLoad] fires
|
|
41
|
+
/// 2. Deferred via EditorApplication.update (runs without editor focus, unlike delayCall)
|
|
42
|
+
/// 3. NuGetPackageRestorer checks if all packages are installed
|
|
43
|
+
/// 4. Downloads and installs any missing packages, removes stale-version siblings
|
|
44
|
+
/// 5. Sets UNITY_COPILOT_READY scripting define
|
|
45
|
+
/// 6. If packages were installed: triggers AssetDatabase.Refresh() → domain reload
|
|
46
|
+
/// 7. On next reload: everything is in place, main plugin compiles
|
|
47
|
+
///
|
|
48
|
+
/// Flow on UPM package change (no domain reload required to invoke):
|
|
49
|
+
/// 1. registeredPackages fires from the previous AppDomain
|
|
50
|
+
/// 2. NuGetPackageRestorer.Restore() runs the same install + cleanup logic
|
|
51
|
+
/// 3. AssetDatabase.Refresh() prompts Unity to retry compilation with the corrected DLL set
|
|
52
|
+
/// 4. On the resulting successful reload, [InitializeOnLoad] resumes the normal path
|
|
53
|
+
/// </summary>
|
|
54
|
+
[InitializeOnLoad]
|
|
55
|
+
static class NuGetDependencyResolver
|
|
56
|
+
{
|
|
57
|
+
const string Tag = "[Unity-Uco DependencyResolver]";
|
|
58
|
+
|
|
59
|
+
static NuGetDependencyResolver()
|
|
60
|
+
{
|
|
61
|
+
// In CI, skip runtime resolution — DLLs are committed to git
|
|
62
|
+
// and UNITY_COPILOT_READY should already be in ProjectSettings.
|
|
63
|
+
// Setting defines at runtime in batch mode causes "Error building Player
|
|
64
|
+
// because scripts are compiling" when the test runner races the recompilation.
|
|
65
|
+
if (IsCi())
|
|
66
|
+
{
|
|
67
|
+
RecompileGate.EnsureReadyDefine();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
EditorApplication.update += ResolveOnce;
|
|
72
|
+
|
|
73
|
+
// Subscribe to UPM package-change events so that when the user upgrades a package
|
|
74
|
+
// whose new code references a newer NuGet DLL than the one currently on disk, we
|
|
75
|
+
// can run the cleanup + restore from the still-alive AppDomain. The compile that
|
|
76
|
+
// would otherwise fail (and block [InitializeOnLoad] in the next domain) gets
|
|
77
|
+
// retried by Unity once AssetDatabase.Refresh() picks up the corrected DLL set.
|
|
78
|
+
// -= before += guards against accidental double-subscription if a hot-reload path
|
|
79
|
+
// ever re-runs this constructor without a full domain swap.
|
|
80
|
+
PackageManagerEvents.registeredPackages -= OnRegisteredPackages;
|
|
81
|
+
PackageManagerEvents.registeredPackages += OnRegisteredPackages;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// <summary>
|
|
85
|
+
/// Tracks whether a UPM-event-triggered restore is currently in flight, so a second
|
|
86
|
+
/// event burst (UPM can fire multiple registeredPackages events for a single user
|
|
87
|
+
/// action) doesn't kick off a parallel restore.
|
|
88
|
+
/// </summary>
|
|
89
|
+
static bool isRestoringFromPackageEvent;
|
|
90
|
+
|
|
91
|
+
static void OnRegisteredPackages(PackageRegistrationEventArgs args)
|
|
92
|
+
{
|
|
93
|
+
if (isRestoringFromPackageEvent)
|
|
94
|
+
return;
|
|
95
|
+
|
|
96
|
+
// Cheap pre-filter: if no packages were added, removed, or upgraded, there is no
|
|
97
|
+
// possibility of a NuGet-dep version change. Skip the heavier AllPackagesInstalled()
|
|
98
|
+
// probe to avoid touching disk on every UPM ping.
|
|
99
|
+
if ((args.added == null || args.added.Count == 0)
|
|
100
|
+
&& (args.removed == null || args.removed.Count == 0)
|
|
101
|
+
&& (args.changedFrom == null || args.changedFrom.Count == 0)
|
|
102
|
+
&& (args.changedTo == null || args.changedTo.Count == 0))
|
|
103
|
+
{
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
isRestoringFromPackageEvent = true;
|
|
108
|
+
try
|
|
109
|
+
{
|
|
110
|
+
Debug.Log($"{Tag} UPM package change detected — running NuGet restore.");
|
|
111
|
+
RunRestoreAndRefresh();
|
|
112
|
+
}
|
|
113
|
+
catch (Exception ex)
|
|
114
|
+
{
|
|
115
|
+
// Same rationale as ResolveOnce: do NOT set UNITY_COPILOT_READY on a failed restore.
|
|
116
|
+
Debug.LogError($"{Tag} Restore from UPM event failed: {ex}");
|
|
117
|
+
}
|
|
118
|
+
finally
|
|
119
|
+
{
|
|
120
|
+
isRestoringFromPackageEvent = false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/// <summary>
|
|
125
|
+
/// Shared core used by both ResolveOnce (post-domain-reload) and OnRegisteredPackages
|
|
126
|
+
/// (no-domain-reload UPM event path). AllPackagesInstalled() short-circuits the common
|
|
127
|
+
/// no-op case without touching the network.
|
|
128
|
+
/// </summary>
|
|
129
|
+
static void RunRestoreAndRefresh()
|
|
130
|
+
{
|
|
131
|
+
if (NuGetPackageRestorer.AllPackagesInstalled())
|
|
132
|
+
{
|
|
133
|
+
NuGetPluginConfigurator.ConfigureAll();
|
|
134
|
+
RecompileGate.EnsureReadyDefine();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
Debug.Log($"{Tag} Restoring NuGet packages...");
|
|
139
|
+
var changed = NuGetPackageRestorer.Restore();
|
|
140
|
+
|
|
141
|
+
NuGetPluginConfigurator.ConfigureAll();
|
|
142
|
+
|
|
143
|
+
RecompileGate.EnsureReadyDefine();
|
|
144
|
+
|
|
145
|
+
if (changed)
|
|
146
|
+
{
|
|
147
|
+
Debug.Log($"{Tag} Packages restored. Refreshing AssetDatabase...");
|
|
148
|
+
AssetDatabase.Refresh();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static void ResolveOnce()
|
|
153
|
+
{
|
|
154
|
+
EditorApplication.update -= ResolveOnce;
|
|
155
|
+
try
|
|
156
|
+
{
|
|
157
|
+
RunRestoreAndRefresh();
|
|
158
|
+
}
|
|
159
|
+
catch (Exception ex)
|
|
160
|
+
{
|
|
161
|
+
// Do NOT set UNITY_COPILOT_READY here: if restore/configuration failed, the DLL
|
|
162
|
+
// layout is unknown/inconsistent, and letting main-plugin assemblies compile
|
|
163
|
+
// against a partial/mismatched set (via defineConstraints) produces hard-to-
|
|
164
|
+
// diagnose MissingMethodException / TypeLoadException at runtime. Surface the
|
|
165
|
+
// failure loud and clear instead, so the user fixes the underlying problem
|
|
166
|
+
// and retries (the next domain reload will run Restore again).
|
|
167
|
+
Debug.LogError($"{Tag} Failed: {ex}");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/// <summary>
|
|
172
|
+
/// Checks if the current environment is a CI environment.
|
|
173
|
+
/// Mirrors EnvironmentUtils.IsCi() but without external dependencies,
|
|
174
|
+
/// since this assembly must compile standalone.
|
|
175
|
+
/// Checks both command-line arguments and environment variables for
|
|
176
|
+
/// CI, GITHUB_ACTIONS, and TF_BUILD (Azure Pipelines).
|
|
177
|
+
/// </summary>
|
|
178
|
+
static bool IsCi()
|
|
179
|
+
{
|
|
180
|
+
var args = ParseCommandLineArguments();
|
|
181
|
+
|
|
182
|
+
var ci = GetArgOrEnv(args, "CI");
|
|
183
|
+
var gha = GetArgOrEnv(args, "GITHUB_ACTIONS");
|
|
184
|
+
var az = GetArgOrEnv(args, "TF_BUILD");
|
|
185
|
+
|
|
186
|
+
return IsTrue(ci) || IsTrue(gha) || IsTrue(az);
|
|
187
|
+
|
|
188
|
+
static string? GetArgOrEnv(Dictionary<string, string?> args, string key)
|
|
189
|
+
=> args.TryGetValue(key, out var v) ? v : Environment.GetEnvironmentVariable(key);
|
|
190
|
+
|
|
191
|
+
static bool IsTrue(string? value)
|
|
192
|
+
=> string.Equals(value?.Trim()?.Trim('"'), "true", StringComparison.OrdinalIgnoreCase);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/// <summary>
|
|
196
|
+
/// Parses Unity command-line arguments into a dictionary.
|
|
197
|
+
/// Handles both "-key value" and "-key=value" forms, plus bare flags like "-batchmode".
|
|
198
|
+
/// Keys are stored WITHOUT the leading dash.
|
|
199
|
+
/// </summary>
|
|
200
|
+
static Dictionary<string, string?> ParseCommandLineArguments()
|
|
201
|
+
{
|
|
202
|
+
var result = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
|
|
203
|
+
var rawArgs = Environment.GetCommandLineArgs();
|
|
204
|
+
|
|
205
|
+
for (var i = 0; i < rawArgs.Length; i++)
|
|
206
|
+
{
|
|
207
|
+
var arg = rawArgs[i];
|
|
208
|
+
if (!arg.StartsWith("-"))
|
|
209
|
+
continue;
|
|
210
|
+
|
|
211
|
+
var key = arg.TrimStart('-');
|
|
212
|
+
|
|
213
|
+
// Handle -key=value form
|
|
214
|
+
var eqIndex = key.IndexOf('=');
|
|
215
|
+
if (eqIndex >= 0)
|
|
216
|
+
{
|
|
217
|
+
result[key.Substring(0, eqIndex)] = key.Substring(eqIndex + 1);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Handle -key value form (next arg is value if it doesn't start with -)
|
|
222
|
+
if (i + 1 < rawArgs.Length && !rawArgs[i + 1].StartsWith("-"))
|
|
223
|
+
{
|
|
224
|
+
result[key] = rawArgs[++i];
|
|
225
|
+
}
|
|
226
|
+
else
|
|
227
|
+
{
|
|
228
|
+
// Bare flag like -batchmode
|
|
229
|
+
result[key] = null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
}
|
|
237
|
+
}
|
package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetDownloader.cs
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
/*
|
|
2
|
-
+------------------------------------------------------------------+
|
|
3
|
-
| Author: Ivan Murzak (https://github.com/IvanMurzak) |
|
|
4
|
-
| Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) |
|
|
5
|
-
| Copyright (c) 2025 Ivan Murzak |
|
|
6
|
-
| Licensed under the Apache License, Version 2.0. |
|
|
7
|
-
| See the LICENSE file in the project root for more information. |
|
|
8
|
-
+------------------------------------------------------------------+
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
#nullable enable
|
|
12
|
-
using System;
|
|
13
|
-
using System.IO;
|
|
14
|
-
using System.Net.Http;
|
|
15
|
-
using UnityEngine;
|
|
16
|
-
|
|
17
|
-
namespace com.AtelierAI.Unity.Copilot.Editor.DependencyResolver
|
|
18
|
-
{
|
|
19
|
-
/// <summary>
|
|
20
|
-
/// Downloads .nupkg files from the NuGet v3 flat container API.
|
|
21
|
-
/// Uses the flat container URL pattern:
|
|
22
|
-
/// https://api.nuget.org/v3-flatcontainer/{id}/{version}/{id}.{version}.nupkg
|
|
23
|
-
/// </summary>
|
|
24
|
-
static class NuGetDownloader
|
|
25
|
-
{
|
|
26
|
-
const string Tag = NuGetConfig.LogTag;
|
|
27
|
-
|
|
28
|
-
static readonly HttpClient httpClient = CreateHttpClient();
|
|
29
|
-
|
|
30
|
-
static HttpClient CreateHttpClient()
|
|
31
|
-
{
|
|
32
|
-
var handler = new HttpClientHandler
|
|
33
|
-
{
|
|
34
|
-
AutomaticDecompression = System.Net.DecompressionMethods.GZip
|
|
35
|
-
| System.Net.DecompressionMethods.Deflate
|
|
36
|
-
};
|
|
37
|
-
var client = new HttpClient(handler);
|
|
38
|
-
client.DefaultRequestHeaders.Add("User-Agent", "Unity-
|
|
39
|
-
client.Timeout = TimeSpan.FromMinutes(5);
|
|
40
|
-
return client;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/// <summary>
|
|
44
|
-
/// Downloads a .nupkg file to the cache. Returns the cached file path.
|
|
45
|
-
/// If the file is already cached, returns immediately without downloading.
|
|
46
|
-
/// </summary>
|
|
47
|
-
public static string Download(NuGetPackage package)
|
|
48
|
-
{
|
|
49
|
-
NuGetCache.EnsureCacheDirectory();
|
|
50
|
-
var cachedPath = NuGetCache.GetCachedPath(package);
|
|
51
|
-
|
|
52
|
-
if (File.Exists(cachedPath))
|
|
53
|
-
return cachedPath;
|
|
54
|
-
|
|
55
|
-
var url = package.DownloadUrl;
|
|
56
|
-
Debug.Log($"{Tag} Downloading {package.Id} {package.Version} from {url}");
|
|
57
|
-
|
|
58
|
-
try
|
|
59
|
-
{
|
|
60
|
-
using (var response = httpClient.GetAsync(url).GetAwaiter().GetResult())
|
|
61
|
-
{
|
|
62
|
-
response.EnsureSuccessStatusCode();
|
|
63
|
-
using (var stream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
|
|
64
|
-
using (var fileStream = File.Create(cachedPath))
|
|
65
|
-
{
|
|
66
|
-
stream.CopyTo(fileStream);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
Debug.Log($"{Tag} Downloaded {package.Id} {package.Version} ({new FileInfo(cachedPath).Length / 1024} KB)");
|
|
70
|
-
}
|
|
71
|
-
catch (Exception ex)
|
|
72
|
-
{
|
|
73
|
-
Debug.LogError($"{Tag} Failed to download {package}: {ex.Message}");
|
|
74
|
-
if (File.Exists(cachedPath))
|
|
75
|
-
File.Delete(cachedPath);
|
|
76
|
-
throw;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return cachedPath;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
+------------------------------------------------------------------+
|
|
3
|
+
| Author: Ivan Murzak (https://github.com/IvanMurzak) |
|
|
4
|
+
| Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) |
|
|
5
|
+
| Copyright (c) 2025 Ivan Murzak |
|
|
6
|
+
| Licensed under the Apache License, Version 2.0. |
|
|
7
|
+
| See the LICENSE file in the project root for more information. |
|
|
8
|
+
+------------------------------------------------------------------+
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#nullable enable
|
|
12
|
+
using System;
|
|
13
|
+
using System.IO;
|
|
14
|
+
using System.Net.Http;
|
|
15
|
+
using UnityEngine;
|
|
16
|
+
|
|
17
|
+
namespace com.AtelierAI.Unity.Copilot.Editor.DependencyResolver
|
|
18
|
+
{
|
|
19
|
+
/// <summary>
|
|
20
|
+
/// Downloads .nupkg files from the NuGet v3 flat container API.
|
|
21
|
+
/// Uses the flat container URL pattern:
|
|
22
|
+
/// https://api.nuget.org/v3-flatcontainer/{id}/{version}/{id}.{version}.nupkg
|
|
23
|
+
/// </summary>
|
|
24
|
+
static class NuGetDownloader
|
|
25
|
+
{
|
|
26
|
+
const string Tag = NuGetConfig.LogTag;
|
|
27
|
+
|
|
28
|
+
static readonly HttpClient httpClient = CreateHttpClient();
|
|
29
|
+
|
|
30
|
+
static HttpClient CreateHttpClient()
|
|
31
|
+
{
|
|
32
|
+
var handler = new HttpClientHandler
|
|
33
|
+
{
|
|
34
|
+
AutomaticDecompression = System.Net.DecompressionMethods.GZip
|
|
35
|
+
| System.Net.DecompressionMethods.Deflate
|
|
36
|
+
};
|
|
37
|
+
var client = new HttpClient(handler);
|
|
38
|
+
client.DefaultRequestHeaders.Add("User-Agent", "Unity-Uco-NuGetResolver");
|
|
39
|
+
client.Timeout = TimeSpan.FromMinutes(5);
|
|
40
|
+
return client;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// <summary>
|
|
44
|
+
/// Downloads a .nupkg file to the cache. Returns the cached file path.
|
|
45
|
+
/// If the file is already cached, returns immediately without downloading.
|
|
46
|
+
/// </summary>
|
|
47
|
+
public static string Download(NuGetPackage package)
|
|
48
|
+
{
|
|
49
|
+
NuGetCache.EnsureCacheDirectory();
|
|
50
|
+
var cachedPath = NuGetCache.GetCachedPath(package);
|
|
51
|
+
|
|
52
|
+
if (File.Exists(cachedPath))
|
|
53
|
+
return cachedPath;
|
|
54
|
+
|
|
55
|
+
var url = package.DownloadUrl;
|
|
56
|
+
Debug.Log($"{Tag} Downloading {package.Id} {package.Version} from {url}");
|
|
57
|
+
|
|
58
|
+
try
|
|
59
|
+
{
|
|
60
|
+
using (var response = httpClient.GetAsync(url).GetAwaiter().GetResult())
|
|
61
|
+
{
|
|
62
|
+
response.EnsureSuccessStatusCode();
|
|
63
|
+
using (var stream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
|
|
64
|
+
using (var fileStream = File.Create(cachedPath))
|
|
65
|
+
{
|
|
66
|
+
stream.CopyTo(fileStream);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
Debug.Log($"{Tag} Downloaded {package.Id} {package.Version} ({new FileInfo(cachedPath).Length / 1024} KB)");
|
|
70
|
+
}
|
|
71
|
+
catch (Exception ex)
|
|
72
|
+
{
|
|
73
|
+
Debug.LogError($"{Tag} Failed to download {package}: {ex.Message}");
|
|
74
|
+
if (File.Exists(cachedPath))
|
|
75
|
+
File.Delete(cachedPath);
|
|
76
|
+
throw;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return cachedPath;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|