diff --git a/AGXUnity/IO/Environment.cs b/AGXUnity/IO/Environment.cs index 5afe08a2..e7aaf128 100644 --- a/AGXUnity/IO/Environment.cs +++ b/AGXUnity/IO/Environment.cs @@ -334,6 +334,9 @@ private static void OnPlayerCli() private static void OnCLI() { + if ( LicenseManager.IsAssetImportWorkerProcess ) + return; + if ( CommandLine.HasArg( CommandLine.Arg.GenerateOfflineActivation ) ) { try { var offlineLicenseIdCode = CommandLine.GetValues( CommandLine.Arg.GenerateOfflineActivation ); diff --git a/AGXUnity/LicenseInfo.cs b/AGXUnity/LicenseInfo.cs index e9fdf7c3..8b9bcbb0 100644 --- a/AGXUnity/LicenseInfo.cs +++ b/AGXUnity/LicenseInfo.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using UnityEditor; using Math = System.Math; namespace AGXUnity @@ -88,6 +89,11 @@ public static LicenseInfo Create() { var info = new LicenseInfo(); +#if UNITY_EDITOR + if ( AssetDatabase.IsAssetImportWorkerProcess() ) + return info; +#endif + try { info.Version = agx.agxSWIG.agxGetVersion( false ); if ( info.Version.ToLower().StartsWith( "agx-" ) ) diff --git a/AGXUnity/LicenseManager.cs b/AGXUnity/LicenseManager.cs index cde8ee82..979adb9b 100644 --- a/AGXUnity/LicenseManager.cs +++ b/AGXUnity/LicenseManager.cs @@ -11,6 +11,74 @@ namespace AGXUnity [HelpURL( "https://us.download.algoryx.se/AGXUnity/documentation/current/editor_interface.html#license-manager" )] public static class LicenseManager { +#if UNITY_EDITOR + [UnityEditor.InitializeOnLoadMethod] + private static void CacheEditorProcessState() + { + try { + s_isAssetImportWorkerProcess = UnityEditor.AssetDatabase.IsAssetImportWorkerProcess(); + } + catch ( UnityEngine.UnityException ) { + s_isAssetImportWorkerProcess = LooksLikeAssetImportWorkerProcess(); + } + } +#endif + + public static bool CanAccessRuntime => !IsAssetImportWorkerProcess; + + internal static agx.Runtime Runtime + { + get + { + if ( !CanAccessRuntime ) + throw new AGXUnity.Exception( "Runtime may not be accessed from a Unity asset import worker process." ); + + return agx.Runtime.instance(); + } + } + + public static bool IsAssetImportWorkerProcess + { + get + { +#if UNITY_EDITOR + if ( s_isAssetImportWorkerProcess.HasValue ) + return s_isAssetImportWorkerProcess.Value; + + try { + s_isAssetImportWorkerProcess = UnityEditor.AssetDatabase.IsAssetImportWorkerProcess(); + return s_isAssetImportWorkerProcess.Value; + } + catch ( UnityEngine.UnityException ) { + return LooksLikeAssetImportWorkerProcess(); + } +#else + return false; +#endif + } + } + +#if UNITY_EDITOR + private static bool LooksLikeAssetImportWorkerProcess() + { + try { + var processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName; + if ( processName.IndexOf( "AssetImportWorker", StringComparison.OrdinalIgnoreCase ) >= 0 ) + return true; + + foreach ( var arg in System.Environment.GetCommandLineArgs() ) + if ( arg.IndexOf( "AssetImportWorker", StringComparison.OrdinalIgnoreCase ) >= 0 ) + return true; + } + catch { + } + + return false; + } + + private static bool? s_isAssetImportWorkerProcess = null; +#endif + /// /// Current license information loaded in AGX Dynamics. /// @@ -76,6 +144,9 @@ public static IEnumerable LicenseTypes /// public static bool LoadFile() { + if ( !CanAccessRuntime ) + return false; + // This is potentially a license unlock by a script. It's not // possible to know if it exists scripts that manually unlocks AGX. var potentialScriptLoaded = LicenseInfo.Create(); @@ -110,6 +181,9 @@ public static LicenseInfo QueryInfo( string filename ) TypeDescription = "Unknown", }; + if ( !CanAccessRuntime ) + return info; + if ( !File.Exists( filename ) ) { Debug.LogWarning( $"AGXUnity.LicenseManager: Unable to query license info for license {filename} - file doesn't exist." ); return info; @@ -125,7 +199,7 @@ public static LicenseInfo QueryInfo( string filename ) if ( licenseType == LicenseInfo.LicenseType.Legacy ) return LicenseInfo.FromLegacy( licenseContent ); - return LicenseInfo.FromNative( agx.Runtime.instance().queryLicenseInformation( licenseContent ) ); + return LicenseInfo.FromNative( Runtime.queryLicenseInformation( licenseContent ) ); } /// @@ -146,6 +220,9 @@ public static bool LoadFile( string filename ) /// True if successfully loaded and is a valid license, otherwise false. public static bool Load( string licenseContent ) { + if ( !CanAccessRuntime ) + return false; + var context = "Explicit license content."; // Loading encrypted runtime from script. AGX is writing the generated // file as given in 'context' here, see ActivateEncryptedRuntime. @@ -184,6 +261,9 @@ public static bool GenerateEncryptedRuntime( int runtimeLicenseId, string referenceApplicationFile, Action onSuccess = null ) { + if ( !CanAccessRuntime ) + return false; + if ( !Directory.Exists( applicationRootDirectory ) ) { Debug.LogError( "AGXUnity.LicenseManager: Unable to generate encrypted runtime license - " + $"application root directory \"{applicationRootDirectory}\" doesn't exist." ); @@ -205,7 +285,7 @@ public static bool GenerateEncryptedRuntime( int runtimeLicenseId, try { agxIO.Environment.instance().getFilePath( agxIO.Environment.Type.RESOURCE_PATH ).pushbackPath( applicationRootDirectory ); - var encrypted = agx.Runtime.instance().encryptRuntimeActivation( runtimeLicenseId, + var encrypted = Runtime.encryptRuntimeActivation( runtimeLicenseId, runtimeLicensePassword, referenceApplicationFile ); agxIO.Environment.instance().getFilePath( agxIO.Environment.Type.RESOURCE_PATH ).removeFilePath( applicationRootDirectory ); @@ -229,7 +309,7 @@ public static bool GenerateEncryptedRuntime( int runtimeLicenseId, } Debug.LogError( "AGXUnity.LicenseManager: Unable to generate encrypted runtime license - " + - $"encryption failed with status: {agx.Runtime.instance().getStatus()}" ); + $"encryption failed with status: {Runtime.getStatus()}" ); } catch ( System.Exception e ) { Debug.LogError( "AGXUnity.LicenseManager: Exception occurred during generate of encrypted runtime " + @@ -309,12 +389,15 @@ public static bool GenerateOfflineActivation( int licenseId, string outputFilename, bool throwOnError = true ) { + if ( !CanAccessRuntime ) + return false; + var success = false; try { - var activationText = agx.Runtime.instance().generateOfflineActivationRequest( licenseId, licensePassword ); - if ( !string.IsNullOrEmpty( agx.Runtime.instance().getStatus() ) ) - throw new AGXUnity.Exception( agx.Runtime.instance().getStatus() ); + var activationText = Runtime.generateOfflineActivationRequest( licenseId, licensePassword ); + if ( !string.IsNullOrEmpty( Runtime.getStatus() ) ) + throw new AGXUnity.Exception( Runtime.getStatus() ); File.WriteAllText( outputFilename, activationText ); @@ -348,6 +431,9 @@ public static bool CreateOfflineLicense( string webResponseFilenameOrContent, string licenseFilename, bool throwOnerror = true ) { + if ( !CanAccessRuntime ) + return false; + var success = false; try { @@ -357,10 +443,10 @@ public static bool CreateOfflineLicense( string webResponseFilenameOrContent, if ( File.Exists( webResponseFilenameOrContent ) ) webResponseFilenameOrContent = File.ReadAllText( webResponseFilenameOrContent ); - if ( !agx.Runtime.instance().processOfflineActivationRequest( webResponseFilenameOrContent ) ) - throw new AGXUnity.Exception( agx.Runtime.instance().getStatus() ); + if ( !Runtime.processOfflineActivationRequest( webResponseFilenameOrContent ) ) + throw new AGXUnity.Exception( Runtime.getStatus() ); - File.WriteAllText( licenseFilename, agx.Runtime.instance().readEncryptedLicense() ); + File.WriteAllText( licenseFilename, Runtime.readEncryptedLicense() ); success = File.Exists( licenseFilename ); } @@ -382,6 +468,9 @@ public static bool CreateOfflineLicense( string webResponseFilenameOrContent, /// public static LicenseInfo UpdateLicenseInformation() { + if ( !CanAccessRuntime ) + return ( LicenseInfo = new LicenseInfo() ); + return ( LicenseInfo = LicenseInfo.Create() ); } @@ -397,6 +486,11 @@ public static void ActivateAsync( int licenseId, string targetDirectory, Action onDone ) { + if ( !CanAccessRuntime ) { + onDone?.Invoke( false ); + return; + } + if ( IsBusy ) { Debug.LogWarning( $"AGXUnity.LicenseManager: Unable to activate license with id {licenseId} - activation is still in progress." ); onDone?.Invoke( false ); @@ -407,7 +501,7 @@ public static void ActivateAsync( int licenseId, s_activationTask = Task.Run( () => { var success = false; try { - success = agx.Runtime.instance().activateAgxLicense( licenseId, + success = Runtime.activateAgxLicense( licenseId, licensePassword, licenseFilename ); UpdateLicenseInformation(); @@ -447,6 +541,11 @@ public static bool Activate( int licenseId, public static void RefreshAsync( string filename, Action onDone ) { + if ( !CanAccessRuntime ) { + onDone?.Invoke( false ); + return; + } + var isBusy = IsBusy; var seemsValid = !string.IsNullOrEmpty( filename ) && !isBusy && @@ -472,7 +571,7 @@ public static void RefreshAsync( string filename, s_refreshTask = Task.Run( () => { var success = false; try { - success = agx.Runtime.instance().loadLicenseFile( filename, true ); + success = Runtime.loadLicenseFile( filename, true ); UpdateLicenseInformation(); } catch ( Exception e ) { @@ -539,14 +638,17 @@ public static bool DeactivateAndDelete( string filename ) /// True if successfully deactivated, otherwise false. public static bool DeactivateLoaded() { + if ( !CanAccessRuntime ) + return false; + var success = false; try { - success = agx.Runtime.instance().deactivateAgxLicense(); + success = Runtime.deactivateAgxLicense(); if ( success ) Reset(); else - Debug.LogWarning( $"AGXUnity.LicenseManager: Unable to deactivate loaded license - {agx.Runtime.instance().getStatus()}" ); + Debug.LogWarning( $"AGXUnity.LicenseManager: Unable to deactivate loaded license - {Runtime.getStatus()}" ); } catch ( Exception e ) { Debug.LogException( e ); @@ -559,8 +661,11 @@ public static bool DeactivateLoaded() /// public static void Reset() { + if ( !CanAccessRuntime ) + return; + try { - agx.Runtime.instance().clear(); + Runtime.clear(); } catch ( Exception ) { } @@ -712,6 +817,9 @@ public static bool DeleteFile( string filename ) /// True if successfully loaded, otherwise false. private static bool LoadFile( string filename, string context ) { + if ( !CanAccessRuntime ) + return false; + if ( string.IsNullOrEmpty( filename ) ) { IssueLoadWarning( "Filename is null or empty.", context ); return false; @@ -737,14 +845,14 @@ private static bool LoadFile( string filename, string context ) // If the license has been refreshed we have to write the // new license content to 'filename' independent of 'loadSuccess'. try { - var isRefreshed = agx.Runtime.instance().isLicenseRefreshed(); + var isRefreshed = Runtime.isLicenseRefreshed(); var isRefreshedAndCanWrite = isRefreshed && IO.Environment.CanWriteToExisting( filename ); if ( isRefreshedAndCanWrite ) { LoadInfo( $"The license has been refreshed - rewriting license file {filename}.", context ); using ( var str = new StreamWriter( filename, false ) ) - str.WriteLine( agx.Runtime.instance().readEncryptedLicense() ); + str.WriteLine( Runtime.readEncryptedLicense() ); LoadInfo( $"Successfully updated license file {filename}.", context ); } @@ -773,6 +881,9 @@ private static bool LoadFile( string filename, string context ) /// True if successful, otherwise false. private static bool Load( string licenseContent, string context ) { + if ( !CanAccessRuntime ) + return false; + if ( string.IsNullOrEmpty( licenseContent ) ) { IssueLoadWarning( "License content is null or empty.", context ); return false; @@ -789,8 +900,8 @@ private static bool Load( string licenseContent, string context ) try { // Service type. if ( licenseContentType == LicenseContentType.Service ) { - agx.Runtime.instance().loadLicenseString( licenseContent ); - LoadInfo( $"Loading service license successful: {agx.Runtime.instance().isValid()}.", + Runtime.loadLicenseString( licenseContent ); + LoadInfo( $"Loading service license successful: {Runtime.isValid()}.", context ); } // Runtime license activation. @@ -799,22 +910,22 @@ private static bool Load( string licenseContent, string context ) // to support non-ASCII input paths. var cwd = Directory.GetCurrentDirectory(); agxIO.Environment.instance().getFilePath( agxIO.Environment.Type.RESOURCE_PATH ).pushbackPath( cwd ); - agx.Runtime.instance().activateEncryptedRuntime( licenseContent, context ); + Runtime.activateEncryptedRuntime( licenseContent, context ); agxIO.Environment.instance().getFilePath( agxIO.Environment.Type.RESOURCE_PATH ).removeFilePath( cwd ); - LoadInfo( $"Activating encrypted runtime license \"{context}\" successful: {agx.Runtime.instance().isValid()}.", + LoadInfo( $"Activating encrypted runtime license \"{context}\" successful: {Runtime.isValid()}.", context ); } // Legacy type. else if ( licenseContentType == LicenseContentType.Legacy ) { - agx.Runtime.instance().unlock( licenseContent ); - LoadInfo( $"Loading legacy license successful: {agx.Runtime.instance().isValid()}.", + Runtime.unlock( licenseContent ); + LoadInfo( $"Loading legacy license successful: {Runtime.isValid()}.", context ); } // Assume obfuscated legacy. else { - agx.Runtime.instance().verifyAndUnlock( licenseContent ); - LoadInfo( $"Loading obfuscated legacy license successful: {agx.Runtime.instance().isValid()}.", + Runtime.verifyAndUnlock( licenseContent ); + LoadInfo( $"Loading obfuscated legacy license successful: {Runtime.isValid()}.", context ); } } @@ -831,9 +942,12 @@ private static bool Load( string licenseContent, string context ) private static bool LoadFloating( string file, string context ) { + if ( !CanAccessRuntime ) + return false; + try { - agx.Runtime.instance().openNetworkSession( file ); - LoadInfo( $"Loading floating license successful: {agx.Runtime.instance().isValid()}.", context ); + Runtime.openNetworkSession( file ); + LoadInfo( $"Loading floating license successful: {Runtime.isValid()}.", context ); } catch ( Exception e ) { IssueLoadWarning( "Caught exception calling AGX Dynamics.", context ); @@ -848,9 +962,12 @@ private static bool LoadFloating( string file, string context ) public static bool ReturnFloating( string context ) { + if ( !CanAccessRuntime ) + return false; + bool success; try { - success = agx.Runtime.instance().closeNetworkSession(); + success = Runtime.closeNetworkSession(); LoadInfo( $"Returning floating license successful: {success}.", context ); } catch ( Exception e ) { diff --git a/AGXUnity/NativeHandler.cs b/AGXUnity/NativeHandler.cs index 2d8df39a..5f0130df 100644 --- a/AGXUnity/NativeHandler.cs +++ b/AGXUnity/NativeHandler.cs @@ -149,7 +149,7 @@ public void Unregister( ScriptComponent component ) public void ValidateLicense() { - HasValidLicense = m_isAgx.Initialized && agx.Runtime.instance().isValid(); + HasValidLicense = m_isAgx.Initialized && LicenseManager.Runtime.isValid(); } public void MakeMainThread() @@ -219,6 +219,9 @@ public static NativeHandler Instance { get { + if ( !LicenseManager.CanAccessRuntime ) + throw new AGXUnity.Exception( "NativeHandler.Instance may not be initialized from a Unity asset import worker process." ); + if ( s_instance == null ) s_instance = new NativeHandler(); return s_instance; diff --git a/AGXUnity/Simulation.cs b/AGXUnity/Simulation.cs index 2494715d..c3375acb 100644 --- a/AGXUnity/Simulation.cs +++ b/AGXUnity/Simulation.cs @@ -980,7 +980,7 @@ protected void OnGUI() id => { // Invalid license if initialized. if ( NativeHandler.Instance.Initialized ) { - var status = agx.Runtime.instance().getStatus(); + var status = LicenseManager.Runtime.getStatus(); // Assume no license file was found if status == "" when the // license manager resets any state in agx.Runtime. if ( string.IsNullOrEmpty( status ) ) diff --git a/Editor/AGXUnityEditor/ExternalAGXInitializer.cs b/Editor/AGXUnityEditor/ExternalAGXInitializer.cs index c323b584..b00b315c 100644 --- a/Editor/AGXUnityEditor/ExternalAGXInitializer.cs +++ b/Editor/AGXUnityEditor/ExternalAGXInitializer.cs @@ -35,6 +35,9 @@ public bool HasData public bool ApplyData() { + if ( AGXUnity.LicenseManager.IsAssetImportWorkerProcess ) + return false; + IsApplied = true; Environment.Set( Environment.Variable.AGX_DIR, AGX_DIR ); @@ -139,6 +142,9 @@ public static string IgnoreIncompatibleVersion public static bool Initialize() { + if ( AGXUnity.LicenseManager.IsAssetImportWorkerProcess ) + return false; + #if UNITY_EDITOR_WIN // Dependencies dir set and we're certain setup_env has been executed. if ( Environment.IsSet( Environment.Variable.AGX_DEPENDENCIES_DIR ) ) diff --git a/Editor/AGXUnityEditor/Manager.cs b/Editor/AGXUnityEditor/Manager.cs index a8e3d7c0..16d37599 100644 --- a/Editor/AGXUnityEditor/Manager.cs +++ b/Editor/AGXUnityEditor/Manager.cs @@ -69,6 +69,9 @@ public static class Manager /// static Manager() { + if ( AGXUnity.LicenseManager.IsAssetImportWorkerProcess ) + return; + IO.Utils.VerifyDirectories(); GetRequestScriptReloadData().Float = -1;