@@ -11,45 +11,122 @@ namespace Microsoft.MixedReality.Toolkit.Utilities.Editor
1111 [ InitializeOnLoad ]
1212 static class OnLoadUtilities
1313 {
14- private const string SessionStateKey = "StandardAssetsOnLoadUtilitiesSessionStateKey" ;
15-
1614 private const string ShaderSentinelGuid = "05852dd420bb9ec4cb7318bfa529d37c" ;
1715 private const string ShaderSentinelFile = "MRTK.Shaders.sentinel" ;
1816
1917 private const string ShaderImportDestination = "MRTK/Shaders" ;
2018
19+ private const string IgnoreFileName = "IgnoreUpdateCheck.sentinel" ;
20+
2121 static OnLoadUtilities ( )
2222 {
23- // This InitializeOnLoad handler only runs once at editor launch in order to adjust for Unity version
24- // differences. These don't need to (and should not be) run on an ongoing basis. This uses the
25- // volatile SessionState which is clear when Unity launches to ensure that this only runs the
26- // expensive work (file system i/o) once.
27- if ( ! SessionState . GetBool ( SessionStateKey , false ) )
28- {
29- SessionState . SetBool ( SessionStateKey , true ) ;
30- EnsureShaders ( ) ;
31- }
23+ EnsureShaders ( false ) ;
24+ }
25+
26+ /// <summary>
27+ /// Checks for updated shaders and bypasses the ignore update check.
28+ /// </summary>
29+ [ MenuItem ( "Mixed Reality Toolkit/Utilities/Check for Shader Updates" ) ]
30+ private static void CheckForShaderUpdates ( )
31+ {
32+ EnsureShaders ( true ) ;
3233 }
3334
3435 /// <summary>
3536 /// Ensures that MRTK shader files are present in a writable location. To support the
3637 /// Universal Render Pipeline, shader modifications must be persisted.
3738 /// </summary>
38- private static void EnsureShaders ( )
39+ /// <param name="bypassIgnore">Causes the shader update code to disregard the ignore file.</param>
40+ private static void EnsureShaders ( bool bypassIgnore )
3941 {
40- if ( ! AssetsContainsShaders ( ) )
42+ DirectoryInfo packageShaderFolder = FindShaderFolderInPackage ( ) ;
43+
44+ if ( bypassIgnore )
45+ {
46+ // The customer is manually checking for updates, delete the ignore file
47+ string sentinelPath = AssetDatabase . GUIDToAssetPath ( ShaderSentinelGuid ) ;
48+ if ( ! string . IsNullOrWhiteSpace ( sentinelPath ) )
49+ {
50+ FileInfo ignoreFile = new FileInfo ( Path . Combine ( new FileInfo ( sentinelPath ) . Directory . FullName , IgnoreFileName ) ) ;
51+ if ( ignoreFile . Exists )
52+ {
53+ ignoreFile . Delete ( ) ;
54+ }
55+ ignoreFile . Refresh ( ) ;
56+ }
57+ }
58+
59+ if ( ! AssetsContainsShaders ( packageShaderFolder ) )
4160 {
42- ImportShaderFiles ( ) ;
61+ ImportShaderFiles ( packageShaderFolder ) ;
4362 }
4463 }
4564
4665 /// <summary>
4766 /// Checks to see if the Assets or Packages (if embedded) folder trees contains the MRTK shaders.
4867 /// </summary>
4968 /// <returns>True if the shader sentinel file is found, otherwise false.</returns>
50- private static bool AssetsContainsShaders ( )
69+ private static bool AssetsContainsShaders ( DirectoryInfo packageShaderFolder )
5170 {
52- return ! string . IsNullOrWhiteSpace ( AssetDatabase . GUIDToAssetPath ( ShaderSentinelGuid ) ) ;
71+ string sentinelPath = AssetDatabase . GUIDToAssetPath ( ShaderSentinelGuid ) ;
72+
73+ // If we do not find the sentinel, we need to import the shaders.
74+ if ( string . IsNullOrWhiteSpace ( sentinelPath ) )
75+ {
76+ return false ;
77+ }
78+
79+ // Getting here indicates that the project's Assets folder contains the shader sentinel.
80+
81+ // Check for the "ignore this check" file, if present we do NOT import
82+ FileInfo ignoreFile = new FileInfo ( Path . Combine ( new FileInfo ( sentinelPath ) . Directory . FullName , IgnoreFileName ) ) ;
83+ if ( ignoreFile . Exists )
84+ {
85+ return true ;
86+ }
87+
88+ // If the package shader folder does not exist, there is nothing for us to do.
89+ if ( ( packageShaderFolder == null ) || ! packageShaderFolder . Exists )
90+ {
91+ return true ;
92+ }
93+
94+ // Get the versions of the sentinel files,
95+ int packageVer = ReadSentinelVersion ( Path . Combine ( packageShaderFolder . FullName , ShaderSentinelFile ) ) ;
96+ int assetVer = ReadSentinelVersion ( sentinelPath ) ;
97+
98+ // No need to copy if the versions are the same.
99+ if ( packageVer == assetVer )
100+ {
101+ return true ;
102+ }
103+
104+ string message = ( packageVer < assetVer ) ?
105+ "The MRTK shaders older than those in your project, do you wish to overwrite the existing shaders?" :
106+ "Updated MRTK shaders are available, do you wish to overwrite the existing shaders?" ;
107+
108+ int dialogResponse = EditorUtility . DisplayDialogComplex (
109+ "Mixed Reality Toolkit Standard Assets" ,
110+ message +
111+ "\n \n NOTE: Overwriting will lose any customizations and may require reconfiguring the render pipeline." ,
112+ "Yes" , // returns 0
113+ "Ignore" , // returns 1 - placed in the cancel slot to force the button order as Yes, No, Ignore
114+ "No" ) ; // returns 2
115+
116+ if ( dialogResponse == 1 )
117+ {
118+ // Write an "ignore this check" file to prevent future prompting
119+ if ( ! ignoreFile . Directory . Exists )
120+ {
121+ ignoreFile . Directory . Create ( ) ;
122+ }
123+ ignoreFile . Create ( ) ;
124+ }
125+ ignoreFile . Refresh ( ) ;
126+
127+ // Return the inverse of the dialog result. Result of true means we want to overwrite, this method returns false
128+ // to cause an overwrite.
129+ return ( dialogResponse != 0 ) ;
53130 }
54131
55132 /// <summary>
@@ -85,10 +162,9 @@ private static DirectoryInfo FindShaderFolderInPackage()
85162 /// <summary>
86163 /// Copies the shader files from the package cache to the Assets folder tree.
87164 /// </summary>
88- private static void ImportShaderFiles ( )
165+ private static void ImportShaderFiles ( DirectoryInfo packageShaderFolder )
89166 {
90- DirectoryInfo source = FindShaderFolderInPackage ( ) ;
91- if ( source == null )
167+ if ( packageShaderFolder == null )
92168 {
93169 Debug . LogError ( "Unable to locate the shader source folder in the package" ) ;
94170 return ;
@@ -100,11 +176,43 @@ private static void ImportShaderFiles()
100176 destination . Create ( ) ;
101177 }
102178
103- FileInfo [ ] sourceFiles = source . GetFiles ( ) ;
179+ FileInfo [ ] sourceFiles = packageShaderFolder . GetFiles ( ) ;
104180 foreach ( FileInfo fi in sourceFiles )
105181 {
106- fi . CopyTo ( Path . Combine ( destination . FullName , fi . Name ) ) ;
182+ fi . CopyTo ( Path . Combine ( destination . FullName , fi . Name ) , true ) ;
183+ }
184+ }
185+
186+ /// <summary>
187+ /// Reads the version number out of the shader
188+ /// </summary>
189+ /// <param name="sentinelPath">The path to the sentinel file.</param>
190+ /// <returns>The version number found in the file, or -1.</returns>
191+ private static int ReadSentinelVersion ( string sentinelPath )
192+ {
193+ using ( FileStream fs = new FileStream ( sentinelPath , FileMode . Open , FileAccess . Read ) )
194+ {
195+ using ( StreamReader reader = new StreamReader ( fs ) )
196+ {
197+ const string token = "ver:" ;
198+
199+ while ( ! reader . EndOfStream )
200+ {
201+ string line = reader . ReadLine ( ) ;
202+ if ( line . StartsWith ( token ) )
203+ {
204+ line = line . Substring ( token . Length ) . Trim ( ) ;
205+ if ( ! int . TryParse ( line , out int ver ) )
206+ {
207+ break ;
208+ }
209+ return ver ;
210+ }
211+ }
212+ }
107213 }
214+
215+ return - 1 ;
108216 }
109217 }
110218}
0 commit comments