initial upload

This commit is contained in:
tom.hempel
2025-09-21 22:42:26 +02:00
commit d03bcd4ba5
6231 changed files with 351582 additions and 0 deletions

View File

@ -0,0 +1,156 @@
#if !CC_TOOLS
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
using UnityEngine.Rendering;
namespace Convai.Scripts.Editor.CustomPackage
{
[InitializeOnLoad]
public static class CCToolsImporter
{
private const string CC_TOOLS_SYMBOL = "CC_TOOLS";
private const string URP_URL = "https://github.com/soupday/cc_unity_tools_URP.git";
private const string HDRP_URL = "https://github.com/soupday/cc_unity_tools_HDRP.git";
private const string BASE_URL = "https://github.com/soupday/cc_unity_tools_3D.git";
private const int MAX_RETRY_ATTEMPTS = 5;
private static int _retryCount = 0;
static CCToolsImporter()
{
EditorApplication.update += CheckAndInstallCCTools;
}
private static void CheckAndInstallCCTools()
{
// Ensure we only attempt to check/install once
EditorApplication.update -= CheckAndInstallCCTools;
// Check if the package is already installed
var listRequest = Client.List(true);
while (!listRequest.IsCompleted) { }
if (IsPackageAlreadyInstalled(listRequest))
{
Debug.Log("CC Tools package is already installed. Adding define symbol.");
AddCCToolsDefineSymbol();
return;
}
// If not installed, proceed with installation
TryInstallCCTools();
}
private static bool IsPackageAlreadyInstalled(ListRequest listRequest)
{
return listRequest.Status == StatusCode.Success &&
listRequest.Result.Any(package => package.packageId.Contains("cc_unity_tools"));
}
private static void TryInstallCCTools()
{
// Determine appropriate package URL based on render pipeline
string packageUrl = DeterminePackageUrl();
// Start package installation asynchronously
AddRequest addRequest = Client.Add(packageUrl);
// Use a coroutine-friendly approach to handle installation
EditorApplication.update += () => HandlePackageInstallation(addRequest);
}
private static void HandlePackageInstallation(AddRequest addRequest)
{
// Check if the request is not completed
if (!addRequest.IsCompleted)
{
return;
}
// Remove the update method to prevent multiple executions
EditorApplication.update -= () => HandlePackageInstallation(addRequest);
switch (addRequest.Status)
{
case StatusCode.Success:
Debug.Log("CC Tools has been installed successfully.");
AddCCToolsDefineSymbol();
if (DeterminePackageUrl() == URP_URL)
{
ConvaiCustomPackageInstaller convaiCustomPackageInstaller = new ConvaiCustomPackageInstaller();
convaiCustomPackageInstaller.InstallConvaiURPConverter();
}
break;
case StatusCode.Failure:
HandleInstallationFailure(addRequest);
break;
case StatusCode.InProgress:
Debug.Log("CC Tools installation is in progress.");
break;
default:
Debug.LogWarning("Unexpected status during CC Tools installation.");
break;
}
}
private static void HandleInstallationFailure(AddRequest addRequest)
{
Debug.LogError($"CC Tools installation failed: {addRequest.Error.message}");
// Implement a retry mechanism
if (_retryCount < MAX_RETRY_ATTEMPTS)
{
_retryCount++;
Debug.Log($"Retrying CC Tools installation. Attempt {_retryCount} of {MAX_RETRY_ATTEMPTS}");
// Wait a short time before retrying to reduce chances of conflict
EditorApplication.delayCall += () => { TryInstallCCTools(); };
}
else
{
Debug.LogError("Maximum retry attempts reached. CC Tools installation failed.");
}
}
private static string DeterminePackageUrl()
{
if (GraphicsSettings.currentRenderPipeline == null)
return BASE_URL;
string renderPipelineName = GraphicsSettings.currentRenderPipeline.GetType().Name;
return renderPipelineName == "UniversalRenderPipelineAsset"
? URP_URL
: HDRP_URL;
}
private static void AddCCToolsDefineSymbol()
{
foreach (BuildTarget target in Enum.GetValues(typeof(BuildTarget)))
{
BuildTargetGroup group = BuildPipeline.GetBuildTargetGroup(target);
if (group == BuildTargetGroup.Unknown)
continue;
NamedBuildTarget namedTarget = NamedBuildTarget.FromBuildTargetGroup(group);
List<string> symbols = PlayerSettings.GetScriptingDefineSymbols(namedTarget)
.Split(';')
.Select(d => d.Trim())
.ToList();
if (!symbols.Contains(CC_TOOLS_SYMBOL))
symbols.Add(CC_TOOLS_SYMBOL);
PlayerSettings.SetScriptingDefineSymbols(namedTarget, string.Join(";", symbols.ToArray()));
}
}
}
}
#endif

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 38ca92565cfb4bdba6cdb861acd779e4
timeCreated: 1719503566

View File

@ -0,0 +1,554 @@
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Convai.Scripts.Runtime.LoggerSystem;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
using UnityEngine.UIElements;
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
namespace Convai.Scripts.Editor.CustomPackage
{
public class ConvaiCustomPackageInstaller : IActiveBuildTargetChanged
{
#region Constants
// XR Package Paths
private const string AR_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiARUpgrader.unitypackage";
private const string VR_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiVRUpgrader.unitypackage";
private const string MR_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiMRUpgrader.unitypackage";
private const string XR_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiXR.unitypackage";
private const string XR_PREFAB_PATH = "Assets/Convai/ConvaiXR/Prefabs/Convai Essentials - XR.prefab";
// Other Package Paths
private const string IOS_BUILD_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiiOSBuild.unitypackage";
private const string URP_CONVERTER_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiURPConverter.unitypackage";
private const string TMP_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiCustomTMP.unitypackage";
#endregion
#region Fields
private SetupTypes _currentSetup;
private List<string> _setupSteps;
private int _totalSetupSteps;
private int _currentStep = 0;
private string _currentStepDescription = "";
private bool _assembliesLocked = false;
private BuildTarget _selectedARPlatform;
private InstallationType _installationType;
public int callbackOrder { get; }
#endregion
#region Enums
private enum SetupTypes
{
AR,
VR,
MR,
iOS,
NormalUnityPackage
}
private enum InstallationType
{
Automatic,
Manual
}
#endregion
#region Constructor
public ConvaiCustomPackageInstaller()
{
}
public ConvaiCustomPackageInstaller(VisualElement root = null)
{
if (root != null)
{
InitializeUI(root);
}
}
#endregion
#region UI Initialization
private void InitializeUI(VisualElement root)
{
root.Q<Button>("install-ar-package").clicked += () => StartPackageInstall(SetupTypes.AR);
root.Q<Button>("install-vr-package").clicked += () => StartPackageInstall(SetupTypes.VR);
root.Q<Button>("install-mr-package").clicked += () => StartPackageInstall(SetupTypes.MR);
root.Q<Button>("install-ios-build-package").clicked += () =>
{
InitializeSetupSteps(SetupTypes.iOS);
InstallConvaiPackage(IOS_BUILD_PACKAGE_PATH);
TryToDownloadiOSDLL();
};
root.Q<Button>("install-urp-converter").clicked += () =>
{
InitializeSetupSteps(SetupTypes.NormalUnityPackage);
InstallConvaiPackage(URP_CONVERTER_PACKAGE_PATH);
EditorUtility.ClearProgressBar();
};
root.Q<Button>("convai-custom-tmp-package").clicked += () =>
{
InitializeSetupSteps(SetupTypes.NormalUnityPackage);
InstallConvaiPackage(TMP_PACKAGE_PATH);
EditorUtility.ClearProgressBar();
};
}
#endregion
#region Build Target Change Handling
public void OnActiveBuildTargetChanged(BuildTarget previousTarget, BuildTarget newTarget)
{
if (newTarget == BuildTarget.iOS) TryToDownloadiOSDLL();
}
#endregion
#region Package Installation
private async void StartPackageInstall(SetupTypes setupType)
{
_currentSetup = setupType;
InitializeSetupSteps(setupType);
if (setupType == SetupTypes.AR)
{
if (!await ConfirmARPlatform()) return;
if (!await ConfirmAutomaticInstallation(SetupTypes.AR)) return;
}
else
{
if (!await ConfirmInstallationType(setupType)) return;
}
InitializeSetupSteps(setupType);
_currentStep = 0;
ConvaiLogger.DebugLog($"Installation of {setupType} package has started... This process may take 3-5 minutes.", ConvaiLogger.LogCategory.Editor);
LockAssemblies();
try
{
await HandlePackageInstall();
}
catch (Exception e)
{
ConvaiLogger.Error($"An error occurred during package installation: {e.Message}", ConvaiLogger.LogCategory.Editor);
}
finally
{
UnlockAssemblies();
EditorUtility.ClearProgressBar();
ConvaiLogger.DebugLog($"Convai {setupType} setup process completed.", ConvaiLogger.LogCategory.Editor);
}
}
private void InitializeSetupSteps(SetupTypes setupType)
{
_setupSteps = new List<string>();
if (setupType == SetupTypes.AR && _selectedARPlatform != EditorUserBuildSettings.activeBuildTarget)
{
_setupSteps.Add($"Change build platform to {_selectedARPlatform}");
}
else if ((setupType == SetupTypes.VR || setupType == SetupTypes.MR) &&
_installationType == InstallationType.Automatic &&
EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android)
{
_setupSteps.Add("Change build platform to Android");
}
switch (setupType)
{
case SetupTypes.AR:
if (_installationType == InstallationType.Automatic)
{
_setupSteps.AddRange(_selectedARPlatform == BuildTarget.Android
? new[] { "Universal Render Pipeline (URP)", "ARCore", "Convai AR Package", "Convai URP Converter" }
: new[] { "Universal Render Pipeline (URP)", "ARKit", "Convai iOS DLL", "Convai iOS Build Package", "Convai AR Package", "Convai URP Converter", });
}
else
{
_setupSteps.Add("Convai AR Package");
}
break;
case SetupTypes.VR:
if (_installationType == InstallationType.Automatic)
{
_setupSteps.AddRange(new[] { "Universal Render Pipeline (URP)", "OpenXR", "XR Interaction Toolkit", "Convai VR Package", "Convai URP Converter" });
}
else
{
_setupSteps.Add("Convai VR Package");
}
break;
case SetupTypes.MR:
if (_installationType == InstallationType.Automatic)
{
_setupSteps.AddRange(new[] { "Universal Render Pipeline (URP)", "XR Management", "Oculus XR Plugin", "Convai URP Converter", "Meta XR SDK All", "Convai MR Package" });
}
else
{
_setupSteps.Add("Convai MR Package");
}
break;
case SetupTypes.iOS:
_setupSteps.AddRange(new[] { "Convai iOS Build Package", "Convai iOS DLL" });
break;
case SetupTypes.NormalUnityPackage:
_setupSteps.Add("Convai Custom Package");
break;
}
_totalSetupSteps = _setupSteps.Count;
}
private async Task HandlePackageInstall()
{
switch (_currentSetup)
{
case SetupTypes.AR:
await HandleARPackageInstall();
break;
case SetupTypes.VR:
await HandleVRPackageInstall();
break;
case SetupTypes.MR:
await HandleMRPackageInstall();
break;
}
}
private async Task HandleARPackageInstall()
{
ChangeBuildTarget(_selectedARPlatform);
await Task.Delay(TimeSpan.FromSeconds(5));
await InitializeURPSetup();
if (_selectedARPlatform == BuildTarget.Android)
{
await InitializeARCoreSetup();
}
else if (_selectedARPlatform == BuildTarget.iOS)
{
await InitializeARKitSetup();
TryToDownloadiOSDLL();
InstallConvaiPackage(IOS_BUILD_PACKAGE_PATH);
}
InstallConvaiPackage(AR_PACKAGE_PATH);
InstallConvaiPackage(URP_CONVERTER_PACKAGE_PATH);
}
private async Task HandleVRPackageInstall()
{
if (_installationType == InstallationType.Automatic)
{
ChangeBuildTarget(BuildTarget.Android);
await Task.Delay(TimeSpan.FromSeconds(5));
await InitializeURPSetup();
await InitializeOpenXRSetup();
await InitializeXRInteractionToolkitSetup();
InstallConvaiPackage(VR_PACKAGE_PATH);
InstallConvaiPackage(URP_CONVERTER_PACKAGE_PATH);
}
else
{
InstallConvaiPackage(XR_PACKAGE_PATH);
await TryToInstantiateXRPrefab();
}
}
private async Task HandleMRPackageInstall()
{
if (_installationType == InstallationType.Automatic)
{
ChangeBuildTarget(BuildTarget.Android);
await InitializeURPSetup();
await InitializeXRManagementSetup();
await InitializeOculusXRSetup();
InstallConvaiPackage(URP_CONVERTER_PACKAGE_PATH);
await InitializeMetaXRSDKAllSetup();
InstallConvaiPackage(MR_PACKAGE_PATH);
await Task.Delay(TimeSpan.FromSeconds(5));
}
else
{
InstallConvaiPackage(XR_PACKAGE_PATH);
await TryToInstantiateXRPrefab();
}
}
#endregion
#region Package Initialization
private async Task InitializePackageSetup(string packageName, string stepDescription)
{
UpdateProgressBar(stepDescription);
if (IsPackageInstalled(packageName))
{
IncrementProgress($"{packageName} is already installed. Skipping...");
return;
}
ConvaiLogger.DebugLog($"{packageName} Package Installation Request sent to Package Manager.", ConvaiLogger.LogCategory.Editor);
AddRequest request = Client.Add(packageName);
while (!request.IsCompleted)
{
await Task.Delay(100);
}
if (request.Status == StatusCode.Success)
{
await Task.Delay(TimeSpan.FromSeconds(5));
IncrementProgress($"Successfully installed: {packageName}");
}
else
{
ConvaiLogger.Error($"Failed to install {packageName}: {request.Error.message}", ConvaiLogger.LogCategory.Editor);
}
}
private Task InitializeURPSetup() => InitializePackageSetup("com.unity.render-pipelines.universal", "Installing Universal Render Pipeline (URP)");
private Task InitializeARCoreSetup() => InitializePackageSetup("com.unity.xr.arcore@5.1.4", "Installing ARCore");
private Task InitializeARKitSetup() => InitializePackageSetup("com.unity.xr.arkit@5.1.4", "Installing ARKit");
private Task InitializeOpenXRSetup() => InitializePackageSetup("com.unity.xr.openxr@1.10.0", "Installing OpenXR");
private Task InitializeOculusXRSetup() => InitializePackageSetup("com.unity.xr.oculus", "Installing Oculus XR Plugin");
private Task InitializeMetaXRSDKAllSetup() => InitializePackageSetup("com.meta.xr.sdk.all", "Installing Meta XR SDK");
private Task InitializeXRManagementSetup() => InitializePackageSetup("com.unity.xr.management", "Installing XR Management");
private Task InitializeXRInteractionToolkitSetup() => InitializePackageSetup("com.unity.xr.interaction.toolkit@2.5.4", "Installing XR Interaction Toolkit");
#endregion
#region Package Installation Methods
private void InstallConvaiPackage(string packagePath)
{
string packageName = Path.GetFileNameWithoutExtension(packagePath);
UpdateProgressBar($"Installing {packageName}");
ConvaiLogger.DebugLog($"Importing: {packageName}", ConvaiLogger.LogCategory.Editor);
AssetDatabase.ImportPackage(packagePath, false);
IncrementProgress($"{packageName} Custom Unity Package Installation Completed.");
}
private async Task TryToInstantiateXRPrefab()
{
if (_installationType != InstallationType.Manual || _currentSetup == SetupTypes.AR) return;
ConvaiLogger.DebugLog("Attempting to instantiate XR Prefab...", ConvaiLogger.LogCategory.Editor);
const int maxAttempts = 30;
const int delayBetweenAttempts = 1000; // 1 second
for (int attempt = 0; attempt < maxAttempts; attempt++)
{
await DelayWithEditorAvailableCheck(delayBetweenAttempts);
if (TryInstantiatePrefab(out GameObject prefab))
{
ConvaiLogger.DebugLog($"Convai XR Prefab Instantiated on attempt {attempt + 1}.", ConvaiLogger.LogCategory.Editor);
return;
}
}
ConvaiLogger.Error($"Failed to load XR Prefab at path: {XR_PREFAB_PATH} after {maxAttempts} attempts.", ConvaiLogger.LogCategory.Editor);
}
private bool TryInstantiatePrefab(out GameObject prefab)
{
AssetDatabase.Refresh();
prefab = AssetDatabase.LoadAssetAtPath<GameObject>(XR_PREFAB_PATH);
if (prefab != null)
{
PrefabUtility.InstantiatePrefab(prefab);
return true;
}
return false;
}
private static void TryToDownloadiOSDLL() => iOSDLLDownloader.TryToDownload();
private async Task<bool> ConfirmARPlatform()
{
string[] options = { "Android", "iOS" };
int choice = await DisplayDialogComplex("Select AR Platform", "Choose the target platform for AR development:", options);
if (choice == -1 || choice == 1) return false; // User cancelled
_selectedARPlatform = choice == 0 ? BuildTarget.Android : BuildTarget.iOS;
return true;
}
private async Task<bool> ConfirmInstallationType(SetupTypes setupType)
{
string[] options = { "Automatic", "Manual" };
string message = $"Choose the installation type for {setupType}:\n\n" +
"Automatic Installation: All necessary packages will be installed, and your project settings will be changed to prepare for building. This option is suitable for new projects. " +
"Using it on existing projects may pose risks and could lead to errors in your current setup.\n\n" +
"Manual Installation: Only the Convai XR package will be installed, and your project settings will remain unchanged. This option is suitable for those who already have an existing XR project.";
int choice = await DisplayDialogComplex($"Select {setupType} Installation Type", message, options);
if (choice == -1 || choice == 1) return false; // User cancelled
_installationType = choice == 0 ? InstallationType.Automatic : InstallationType.Manual;
if (_installationType == InstallationType.Automatic)
{
return await ConfirmAutomaticInstallation(setupType);
}
return true;
}
private async Task<bool> ConfirmAutomaticInstallation(SetupTypes setupType)
{
InitializeSetupSteps(setupType);
string packageList = string.Join("\n", _setupSteps.Select(p => $"- {p}"));
string message = $"Automatic installation for {setupType} will change your project settings, import the following packages, and perform the following steps: \n\n" +
$"{packageList}\n\n" +
"* This process cannot be undone.\n\n" +
"** Recommended for new projects.\n\n" +
"Are you sure you want to proceed with the automatic installation?";
int choice = await DisplayDialogComplex("Confirm Automatic Installation", message, new[] { "Yes, proceed", "No, cancel" });
return choice == 0;
}
private void ChangeBuildTarget(BuildTarget target)
{
UpdateProgressBar($"Changing Build Target to {target}");
if (EditorUserBuildSettings.activeBuildTarget != target)
{
ConvaiLogger.DebugLog($"Build Target Platform is being Changed to {target}...", ConvaiLogger.LogCategory.Editor);
BuildTargetGroup targetGroup = target == BuildTarget.Android ? BuildTargetGroup.Android : BuildTargetGroup.iOS;
bool switched = EditorUserBuildSettings.SwitchActiveBuildTarget(targetGroup, target);
if (switched)
{
IncrementProgress($"Build Target changed to {target}");
}
else
{
IncrementProgress($"Failed to Change Build Target to {target}");
}
}
else
{
IncrementProgress($"Build Target is already set to {target}");
}
}
public void InstallConvaiURPConverter()
{
InitializeSetupSteps(SetupTypes.NormalUnityPackage);
InstallConvaiPackage(URP_CONVERTER_PACKAGE_PATH);
EditorUtility.ClearProgressBar();
}
#endregion
#region Utility Methods
private static bool IsPackageInstalled(string packageName) =>
PackageInfo.GetAllRegisteredPackages().Any(packageInfo => packageInfo.name == packageName);
private void LockAssemblies()
{
if (!_assembliesLocked)
{
EditorApplication.LockReloadAssemblies();
_assembliesLocked = true;
ConvaiLogger.DebugLog("Assemblies locked for package installation.", ConvaiLogger.LogCategory.Editor);
}
}
private void UnlockAssemblies()
{
if (_assembliesLocked)
{
EditorApplication.UnlockReloadAssemblies();
_assembliesLocked = false;
ConvaiLogger.DebugLog("Assemblies unlocked after package installation.", ConvaiLogger.LogCategory.Editor);
}
}
private async Task DelayWithEditorAvailableCheck(int delayBetweenAttempts)
{
await Task.Delay(delayBetweenAttempts);
if (EditorApplication.isCompiling || EditorApplication.isUpdating)
{
ConvaiLogger.DebugLog("Waiting for Unity to finish compiling or updating...", ConvaiLogger.LogCategory.Editor);
await DelayWithEditorAvailableCheck(delayBetweenAttempts); // Recursive call to wait again
}
}
private Task<int> DisplayDialogComplex(string title, string message, string[] options)
{
return Task.FromResult(EditorUtility.DisplayDialogComplex(title, message, options[0], "Cancel", options[1]));
}
#endregion
#region Progress Management
private void UpdateProgressBar(string stepDescription)
{
_currentStepDescription = stepDescription;
float progress = (float)_currentStep / _totalSetupSteps;
int progressPercentage = Mathf.RoundToInt(progress * 100);
string title = $"Convai {_currentSetup} Setup Progress";
string info = $"Step {_currentStep + 1} of {_totalSetupSteps}: {_currentStepDescription} ({progressPercentage}% Complete)";
EditorUtility.DisplayProgressBar(title, info, progress);
}
private void IncrementProgress(string completedStepDescription)
{
_currentStep++;
ConvaiLogger.DebugLog(completedStepDescription, ConvaiLogger.LogCategory.Editor);
if (_currentStep < _totalSetupSteps)
{
UpdateProgressBar(_setupSteps[_currentStep]);
}
}
#endregion
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 53fd043db40ab5b4798e83e7f3204952
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,172 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using Convai.Scripts.Runtime.LoggerSystem;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
namespace Convai.Scripts.Editor.CustomPackage
{
/// <summary>
/// Editor window for downloading and extracting iOS DLL from a specified URL.
/// </summary>
public class iOSDLLDownloader
{
private const string DOWNLOAD_ENDPOINT_URL = "https://api.convai.com/user/downloadAsset";
private const string RELATIVE_PATH = "Convai/Plugins/gRPC/Grpc.Core/runtimes";
private static string _targetDirectory;
/// <summary>
/// Attempts to download the iOS DLL if it doesn't already exist.
/// </summary>
public static void TryToDownload()
{
if (CheckFileExistence()) return;
ConvaiLogger.DebugLog("<color=lime>The iOS DLL download has started...</color>", ConvaiLogger.LogCategory.Editor);
DownloadAndExtract(GetTargetDirectory());
}
/// <summary>
/// Coroutine to download and extract the ZIP file from the specified URL.
/// </summary>
/// <param name="outputPath">Directory to extract the contents to.</param>
/// <returns></returns>
private static void DownloadAndExtract(string outputPath)
{
try
{
string downloadURL = GetDownloadURL();
if (downloadURL == null)
ConvaiLogger.Error("Failed to get download URL. Please check the API key and try again.", ConvaiLogger.LogCategory.Editor);
using UnityWebRequest webRequest = UnityWebRequest.Get(downloadURL);
webRequest.SendWebRequest();
while (!webRequest.isDone)
{
float progress = webRequest.downloadProgress;
EditorUtility.DisplayProgressBar("Downloading required iOS DLL...",
"Please wait for the download to finish and do not close Unity. " + (int)(progress * 100) + "%", progress);
}
EditorUtility.ClearProgressBar();
if (webRequest.result is UnityWebRequest.Result.ConnectionError or UnityWebRequest.Result.ProtocolError)
{
ConvaiLogger.Error($"Error downloading file: {webRequest.error}", ConvaiLogger.LogCategory.Editor);
}
else
{
byte[] results = webRequest.downloadHandler.data;
string zipPath = Path.Combine(Path.GetTempPath(), "downloaded.zip");
File.WriteAllBytes(zipPath, results);
ExtractZipFile(zipPath, outputPath);
File.Delete(zipPath);
ConvaiLogger.Info($"Downloaded and extracted to {outputPath}" + "/ios/libgrpc.a", ConvaiLogger.LogCategory.Editor);
// Refresh the asset database to make sure the new files are recognized
AssetDatabase.Refresh();
}
}
catch (Exception e)
{
ConvaiLogger.Error(e.Message, ConvaiLogger.LogCategory.Editor);
throw;
}
}
/// <summary>
/// Retrieves the download URL from Convai API.
/// </summary>
/// <returns>The download URL or null.</returns>
private static string GetDownloadURL()
{
if (!ConvaiAPIKeySetup.GetAPIKey(out string apiKey)) return null;
string body = @"{""service_name"": ""unity-builds"",""version"":""ios""}";
WebRequest request = WebRequest.Create(DOWNLOAD_ENDPOINT_URL);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("CONVAI-API-KEY", apiKey);
using (StreamWriter streamWriter = new(request.GetRequestStream()))
{
streamWriter.Write(body);
}
using (WebResponse response = request.GetResponse())
using (Stream dataStream = response.GetResponseStream())
using (StreamReader reader = new(dataStream))
{
JObject responseJson = JObject.Parse(reader.ReadToEnd());
return (string)responseJson["download_link"];
}
}
/// <summary>
/// Extracts the contents of a ZIP file to the specified output folder.
/// </summary>
/// <param name="zipFilePath">Path to the ZIP file.</param>
/// <param name="outputFolder">Directory to extract the contents to.</param>
private static void ExtractZipFile(string zipFilePath, string outputFolder)
{
if (!Directory.Exists(outputFolder)) Directory.CreateDirectory(outputFolder);
using (ZipArchive archive = ZipFile.OpenRead(zipFilePath))
{
float totalEntries = archive.Entries.Count;
float currentEntry = 0;
foreach (ZipArchiveEntry entry in archive.Entries)
{
string fullPath = Path.Combine(outputFolder, entry.FullName);
// Ensure the directory exists
string directoryName = Path.GetDirectoryName(fullPath);
if (!Directory.Exists(directoryName))
if (directoryName != null)
Directory.CreateDirectory(directoryName);
// Extract the entry to the output directory
entry.ExtractToFile(fullPath, true);
// Update the progress bar
currentEntry++;
float progress = currentEntry / totalEntries;
EditorUtility.DisplayProgressBar("Extracting", $"Extracting file {entry.Name}...", progress);
}
}
EditorUtility.ClearProgressBar();
}
/// <summary>
/// Gets the target directory for extracting the files.
/// </summary>
/// <returns>Target directory path.</returns>
private static string GetTargetDirectory()
{
_targetDirectory = Path.Combine(Application.dataPath, RELATIVE_PATH);
if (!Directory.Exists(_targetDirectory)) Directory.CreateDirectory(_targetDirectory);
return _targetDirectory;
}
/// <summary>
/// Checks if the iOS DLL file already exists.
/// </summary>
/// <returns>True if the file exists, otherwise false.</returns>
private static bool CheckFileExistence()
{
string fullPath = Path.Combine(Application.dataPath, RELATIVE_PATH + "/ios/libgrpc.a");
bool fileExists = File.Exists(fullPath);
if (fileExists) ConvaiLogger.DebugLog("iOS DLL already exists. No need to download.", ConvaiLogger.LogCategory.Editor);
return fileExists;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 526eafca5259e824591be577e0305054
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: