#if UNITY_EDITOR
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
namespace Convai.Scripts.Editor.Custom_Package
{
///
/// Custom package installer for Convai's Custom Packages in Unity Editor.
///
public class ConvaiCustomPackageInstaller : EditorWindow, IActiveBuildTargetChanged
{
// Enum to represent different setup types
private enum SetupTypes
{
None,
ARAndroid,
ARiOS,
VR,
Uninstaller
}
// Paths to different Convai packages
private const string AR_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiARUpgrader.unitypackage";
private const string IOS_BUILD_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiiOSBuild.unitypackage";
private const string TMP_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiCustomTMP.unitypackage";
private const string URP_CONVERTER_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiURPConverter.unitypackage";
private const string VR_PACKAGE_PATH = "Assets/Convai/Custom Packages/ConvaiVRUpgrader.unitypackage";
// Index to keep track of the current package installation step
private int _currentPackageInstallIndex;
// Current setup type
private SetupTypes _currentSetup;
// Request object for package installations/uninstallations
private Request _request;
///
/// GUI method to display the window and buttons.
///
private void OnGUI()
{
// Loading Convai logo
Texture2D convaiLogo = AssetDatabase.LoadAssetAtPath(ConvaiImagesDirectory.CONVAI_LOGO_PATH);
GUI.DrawTexture(new Rect(115, 0, 256, 80), convaiLogo);
GUILayout.BeginArea(new Rect(165, 100, Screen.width, Screen.height));
GUILayout.BeginVertical();
// Button to install AR package
if (GUILayout.Button("Install AR Package", GUILayout.Width(170), GUILayout.Height(30)))
{
if (EditorUtility.DisplayDialog("Which Platform",
"Which platform do you want to install AR package for?", "Android", "iOS"))
{
// Display confirmation dialog before installation
if (EditorUtility.DisplayDialog("Confirm Android AR Package Installation",
"This step will install AR-related packages and integrate Convai's AR package into your project. " +
"This process will affect your project. Do you want to proceed?\n\n" +
"The following operations will be performed:\n" +
"- Universal Render Pipeline (URP)\n" +
"- ARCore Plugin\n" +
"- Convai Custom AR Package\n" +
"- Convai URP Converter\n\n" +
"* If these packages are not present in your project, they will be installed.\n" +
"* If the target build platform is not Android, it will be switched to Android.", "Yes, Proceed", "No, Cancel"))
{
EditorApplication.LockReloadAssemblies();
StartPackageInstallation(SetupTypes.ARAndroid);
}
}
else
{
// Display confirmation dialog before installation
if (EditorUtility.DisplayDialog("Confirm iOS AR Package Installation",
"This step will install AR-related packages and integrate Convai's AR package into your project. " +
"This process will affect your project. Do you want to proceed?\n\n" +
"The following operations will be performed:\n" +
"- Universal Render Pipeline (URP)\n" +
"- ARKit Plugin\n" +
"- Convai Custom AR Package\n" +
"- Convai URP Converter\n\n" +
"* If these packages are not present in your project, they will be installed.\n" +
"* If the target build platform is not iOS, it will be switched to iOS.", "Yes, Proceed", "No, Cancel"))
{
EditorApplication.LockReloadAssemblies();
StartPackageInstallation(SetupTypes.ARiOS);
}
}
}
GUILayout.Space(10);
// Button to install VR package
if (GUILayout.Button("Install VR Package", GUILayout.Width(170), GUILayout.Height(30)))
// Display confirmation dialog before installation
if (EditorUtility.DisplayDialog("Confirm VR Package Installation",
"This step will install VR-related packages and integrate Convai's VR package into your project. " +
"This process will affect your project. Do you want to proceed?\n\n" +
"The following operations will be performed:\n" +
"- Universal Render Pipeline (URP)\n" +
"- OpenXR Plugin\n" +
"- XR Interaction Toolkit\n" +
"- Convai Custom VR Package\n" +
"- Convai URP Converter\n\n" +
"* If these packages are not present in your project, they will be installed.\n" +
"* If the target build platform is not Android, it will be switched to Android.", "Yes, Proceed", "No, Cancel"))
{
EditorApplication.LockReloadAssemblies();
StartPackageInstallation(SetupTypes.VR);
}
GUILayout.Space(10);
// Button to uninstall XR package
if (GUILayout.Button("Uninstall XR Package", GUILayout.Width(170), GUILayout.Height(30)))
// Display confirmation dialog before uninstallation
if (EditorUtility.DisplayDialog("Confirm Package Uninstallation",
"This process will uninstall the Convai package and revert changes made by AR or VR setups in your project. " +
"It may affect your project. Are you sure you want to proceed?\n\n" +
"The following packages will be uninstalled.\n" +
"- ARCore Plugin or ARKit\n" +
"- OpenXR Plugin\n" +
"- XR Interaction Toolkit\n" +
"- Convai Custom AR or VR Package\n\n" +
"* The Convai Uninstaller Package will be installed. This process will revert scripts modified for XR to their default states.",
"Yes, Uninstall", "No, Cancel"))
{
_currentSetup = SetupTypes.Uninstaller;
EditorApplication.update += Progress;
EditorApplication.LockReloadAssemblies();
HandleUninstallPackage();
}
GUILayout.Space(10);
if (GUILayout.Button("Install iOS Build Package", GUILayout.Width(170), GUILayout.Height(30)))
{
InstallConvaiUnityPackage(IOS_BUILD_PACKAGE_PATH);
TryToDownloadiOSDLL();
}
GUILayout.Space(10);
if (GUILayout.Button("Install URP Converter", GUILayout.Width(170), GUILayout.Height(30))) InstallConvaiUnityPackage(URP_CONVERTER_PACKAGE_PATH);
GUILayout.Space(10);
if (GUILayout.Button("Install TMP Package", GUILayout.Width(170), GUILayout.Height(30))) InstallConvaiUnityPackage(TMP_PACKAGE_PATH);
GUILayout.EndVertical();
GUILayout.EndArea();
}
// IActiveBuildTargetChanged callback
public int callbackOrder { get; }
///
/// Called when the active build target is changed.
///
/// The previous build target.
/// The new build target.
public void OnActiveBuildTargetChanged(BuildTarget previousTarget, BuildTarget newTarget)
{
// Check if the new build target is iOS and trigger the download of iOS DLL.
if (newTarget == BuildTarget.iOS) TryToDownloadiOSDLL();
}
///
/// Shows the Convai Custom Package Installer window.
///
[MenuItem("Convai/Custom Package Installer", false, 10)]
public static void ShowWindow()
{
ConvaiCustomPackageInstaller window = GetWindow("Convai Custom Package Installer", true);
window.minSize = new Vector2(500, 370);
window.maxSize = window.minSize;
window.titleContent.text = "Custom Package Installer";
window.Show();
}
///
/// Progress method to handle the installation/uninstallation progress.
///
private void Progress()
{
Debug.Log("Process in progress... Please wait.");
// Check if the request object is initialized
if (_request == null) return;
if (_request.IsCompleted)
{
switch (_request.Status)
{
case StatusCode.InProgress:
// Do nothing while the request is still in progress
break;
case StatusCode.Success:
// Handle the successful completion of the package request
HandlePackageRequest();
break;
case StatusCode.Failure:
// Log an error message in case of failure
Debug.LogError("Error: " + _request.Error.message);
break;
}
// Remove the Progress method from the update event
EditorApplication.UnlockReloadAssemblies();
EditorApplication.update -= Progress;
}
}
///
/// Method to handle the completion of the package request.
///
private void HandlePackageRequest()
{
switch (_currentSetup)
{
case SetupTypes.None:
// Do nothing for SetupTypes.None
break;
case SetupTypes.ARiOS:
// Handle iOS AR package installation
HandleARPackageInstall();
Debug.Log("The request for package installation from the Package Manager has been successfully completed.");
break;
case SetupTypes.ARAndroid:
// Handle Android AR package installation
HandleARPackageInstall();
Debug.Log("The request for package installation from the Package Manager has been successfully completed.");
break;
case SetupTypes.VR:
// Handle VR package installation
HandleVRPackageInstall();
Debug.Log("The request for package installation from the Package Manager has been successfully completed.");
break;
case SetupTypes.Uninstaller:
// Handle uninstallation package completion
HandleUninstallPackage();
Debug.Log("The request for package uninstallation from the Package Manager has been successfully completed.");
break;
}
// Add the Progress method back to the update event
EditorApplication.update += Progress;
}
///
/// Method to handle the uninstallation of packages.
///
private void HandleUninstallPackage()
{
// Check if the request object is not initialized
if (_request == null)
{
// Define asset paths to delete
string[] deleteAssetPaths =
{
"Assets/Samples",
"Assets/Convai/ConvaiAR",
"Assets/Convai/ConvaiVR",
"Assets/XR",
"Assets/XRI"
};
List outFailedPaths = new();
// Delete specified asset paths
AssetDatabase.DeleteAssets(deleteAssetPaths, outFailedPaths);
// Log errors if any deletion fails
if (outFailedPaths.Count > 0)
foreach (string failedPath in outFailedPaths)
Debug.LogError("Failed to delete : " + failedPath);
}
// Define package names for uninstallation
string ARCorePackageName = "com.unity.xr.arcore";
string ARKitPackageName = "com.unity.xr.arkit";
string OpenXRPackageName = "com.unity.xr.openxr";
string XRInteractionToolkitPackageName = "com.unity.xr.interaction.toolkit";
// Check if ARCore is installed and initiate removal
if (IsPackageInstalled(ARCorePackageName)) _request = Client.Remove(ARCorePackageName);
// Check if ARKit is installed and initiate removal
if (IsPackageInstalled(ARKitPackageName))
{
_request = Client.Remove(ARKitPackageName);
}
// Check if OpenXR is installed and initiate removal
else if (IsPackageInstalled(OpenXRPackageName))
{
_request = Client.Remove(OpenXRPackageName);
}
// Check if XR Interaction Toolkit is installed and initiate removal
else if (IsPackageInstalled(XRInteractionToolkitPackageName))
{
_request = Client.Remove(XRInteractionToolkitPackageName);
}
else
{
// Stop the update event if the request is not initialized
EditorApplication.update -= Progress;
EditorApplication.UnlockReloadAssemblies();
}
// Remove the Progress method from the update event if the request is not initialized
if (_request == null) EditorApplication.update -= Progress;
}
///
/// Method to start the installation of a specific package setup.
///
private void StartPackageInstallation(SetupTypes setupType)
{
// Log a message indicating the start of the package installation
Debug.Log($"Installation of {setupType} package has started... This process may take 3-5 minutes.");
// Warn the user about the possibility of 'Failed to Resolve Packages' error
Debug.LogWarning("If you encounter with 'Failed to Resolve Packages' error, there's no need to be concerned.");
// Reset the package installation index
_currentPackageInstallIndex = 0;
// Set the current setup type
_currentSetup = setupType;
// Initialize the Universal Render Pipeline (URP) setup
InitializeURPSetup();
}
///
/// Method to handle the installation of AR-related packages.
///
private void HandleARPackageInstall()
{
// Check the current package installation index
if (_currentPackageInstallIndex == 0)
{
switch (_currentSetup)
{
case SetupTypes.ARAndroid:
// Initialize the ARCore setup
InitializeARCoreSetup();
break;
case SetupTypes.ARiOS:
// Initialize the ARKit setup
InitializeARKitSetup();
break;
}
}
else
{
// Install AR-related packages and perform necessary setup
InstallConvaiUnityPackage(AR_PACKAGE_PATH);
InstallConvaiUnityPackage(URP_CONVERTER_PACKAGE_PATH);
switch (_currentSetup)
{
case SetupTypes.ARAndroid:
TryToChangeEditorBuildTargetToAndroid();
break;
case SetupTypes.ARiOS:
TryToChangeEditorBuildTargetToiOS();
break;
}
}
}
///
/// Method to handle the installation of VR-related packages.
///
private void HandleVRPackageInstall()
{
// Check the current package installation index
if (_currentPackageInstallIndex == 0)
{
// Initialize the OpenXR setup
InitializeOpenXRSetup();
}
else if (_currentPackageInstallIndex == 1)
{
// Initialize the XR Interaction Toolkit setup
InitializeXRInteractionToolkitSetup();
}
else
{
// Install VR-related packages and perform necessary setup
InstallConvaiUnityPackage(VR_PACKAGE_PATH);
InstallConvaiUnityPackage(URP_CONVERTER_PACKAGE_PATH);
TryToChangeEditorBuildTargetToAndroid();
}
}
///
/// Method to initialize the URP setup.
///
private void InitializeURPSetup()
{
// Define the URP package name
const string URPPackageName = "com.unity.render-pipelines.universal@14.0.11";
// Check if the URP package is already installed
if (IsPackageInstalled(URPPackageName))
{
// If installed, handle the successful package request
HandlePackageRequest();
return;
}
// If not installed, send a request to the Package Manager to add the URP package
_request = Client.Add(URPPackageName);
Debug.Log($"{URPPackageName} Package Installation Request Sent to Package Manager.");
// Add the Progress method to the update event to monitor the installation progress
EditorApplication.update += Progress;
}
///
/// Method to initialize the ARCore setup.
///
private void InitializeARCoreSetup()
{
// Set the current package installation index for ARCore
_currentPackageInstallIndex = 1;
// Define the ARCore package name
string ARCorePackageName = "com.unity.xr.arcore@5.1.4";
// Check if the ARCore package is already installed
if (IsPackageInstalled(ARCorePackageName))
{
// If installed, handle the AR package installation
HandleARPackageInstall();
return;
}
// If not installed, send a request to the Package Manager to add the ARCore package
_request = Client.Add(ARCorePackageName);
Debug.Log($"{ARCorePackageName} Package Installation Request sent to Package Manager.");
}
///
/// Method to initialize the ARKit setup.
///
private void InitializeARKitSetup()
{
// Set the current package installation index for AR Setup
_currentPackageInstallIndex = 1;
// Define the ARKit package name
string ARKitPackageName = "com.unity.xr.arkit@5.1.4";
// Check if the ARKit package is already installed
if (IsPackageInstalled(ARKitPackageName))
{
// If installed, handle the AR package installation
HandleARPackageInstall();
return;
}
// If not installed, send a request to the Package Manager to add the ARKit package
_request = Client.Add(ARKitPackageName);
Debug.Log($"{ARKitPackageName} Package Installation Request sent to Package Manager.");
}
///
/// Method to initialize the OpenXR setup.
///
private void InitializeOpenXRSetup()
{
// Set the current package installation index for OpenXR
_currentPackageInstallIndex = 1;
// Define the OpenXR package name
string OpenXRPackageName = "com.unity.xr.openxr@1.10.0";
// Check if the OpenXR package is already installed
if (IsPackageInstalled(OpenXRPackageName))
{
// If installed, handle the VR package installation
HandleVRPackageInstall();
return;
}
// If not installed, send a request to the Package Manager to add the OpenXR package
_request = Client.Add(OpenXRPackageName);
Debug.Log($"{OpenXRPackageName} Package Installation Request sent to Package Manager.");
}
///
/// Method to initialize the XR Interaction Toolkit setup.
///
private void InitializeXRInteractionToolkitSetup()
{
// Set the current package installation index for XR Interaction Toolkit
_currentPackageInstallIndex = 2;
// Define the XR Interaction Toolkit package name
string XRInteractionToolkitPackageName = "com.unity.xr.interaction.toolkit@2.5.4";
// Check if the XR Interaction Toolkit package is already installed
if (IsPackageInstalled(XRInteractionToolkitPackageName))
{
// If installed, handle the VR package installation
HandleVRPackageInstall();
return;
}
// If not installed, send a request to the Package Manager to add the XR Interaction Toolkit package
_request = Client.Add(XRInteractionToolkitPackageName);
Debug.Log($"{XRInteractionToolkitPackageName} Package Installation Request sent to Package Manager.");
}
///
/// Method to install a custom Convai Unity package.
///
private void InstallConvaiUnityPackage(string packagePath)
{
// Import the Unity package
AssetDatabase.ImportPackage(packagePath, false);
// Get the package name without extension
string packageName = Path.GetFileNameWithoutExtension(packagePath);
Debug.Log($"{packageName} Custom Unity Package Installation Completed.");
}
///
/// Method to check if a package is already installed.
///
private bool IsPackageInstalled(string packageName)
{
// Iterate through all registered packages
foreach (PackageInfo packageInfo in PackageInfo.GetAllRegisteredPackages())
// Check if the package name matches
if (packageInfo.name == packageName)
// Return true if the package is installed
return true;
// Return false if the package is not installed
return false;
}
///
/// Try changing the editor build target to Android.
///
private void TryToChangeEditorBuildTargetToAndroid()
{
// Check if the current build target is not Android
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android)
{
// Switch the active build target to Android
EditorUserBuildSettings.SwitchActiveBuildTargetAsync(BuildTargetGroup.Android, BuildTarget.Android);
Debug.Log("Build Target Platform is being Changed to Android...");
}
}
///
/// Try changing the editor build target to iOS.
///
private void TryToChangeEditorBuildTargetToiOS()
{
// Check if the current build target is not iOS
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.iOS)
{
// Switch the active build target to iOS
EditorUserBuildSettings.SwitchActiveBuildTargetAsync(BuildTargetGroup.iOS, BuildTarget.iOS);
Debug.Log("Build Target Platform is being Changed to iOS...");
}
}
///
/// Attempts to download the iOS DLL using the IOSDLLDownloader class.
///
private void TryToDownloadiOSDLL()
{
// Call the TryToDownload method from the IOSDLLDownloader class.
iOSDLLDownloader.TryToDownload();
}
}
}
#endif