ASEPackageManagerHelper.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. using System;
  4. using UnityEngine;
  5. using UnityEngine.Rendering;
  6. using UnityEditor;
  7. using UnityEditor.PackageManager.Requests;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Reflection;
  11. using System.Text.RegularExpressions;
  12. namespace AmplifyShaderEditor
  13. {
  14. public enum ASEImportFlags
  15. {
  16. None = 0,
  17. URP = 1 << 0,
  18. HDRP = 1 << 1,
  19. Both = URP | HDRP
  20. }
  21. public static class AssetDatabaseEX
  22. {
  23. private static System.Type type = null;
  24. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEditor.AssetDatabase, UnityEditor" ) : type; } }
  25. public static void ImportPackageImmediately( string packagePath )
  26. {
  27. AssetDatabaseEX.Type.InvokeMember( "ImportPackageImmediately", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { packagePath } );
  28. }
  29. }
  30. public enum ASESRPBaseline
  31. {
  32. ASE_SRP_INVALID = 0,
  33. ASE_SRP_10 = 100000,
  34. ASE_SRP_11 = 110000,
  35. ASE_SRP_12 = 120000,
  36. ASE_SRP_13 = 130000,
  37. ASE_SRP_14 = 140000,
  38. ASE_SRP_15 = 150000,
  39. ASE_SRP_16 = 160000,
  40. ASE_SRP_17 = 170000
  41. }
  42. public class ASESRPPackageDesc
  43. {
  44. public ASESRPBaseline baseline = ASESRPBaseline.ASE_SRP_INVALID;
  45. public string guidURP = string.Empty;
  46. public string guidHDRP = string.Empty;
  47. public ASESRPPackageDesc( ASESRPBaseline baseline, string guidURP, string guidHDRP )
  48. {
  49. this.baseline = baseline;
  50. this.guidURP = guidURP;
  51. this.guidHDRP = guidHDRP;
  52. }
  53. }
  54. [Serializable]
  55. [InitializeOnLoad]
  56. public static class ASEPackageManagerHelper
  57. {
  58. private static string URPPackageId = "com.unity.render-pipelines.universal";
  59. private static string HDRPPackageId = "com.unity.render-pipelines.high-definition";
  60. private static string NewVersionDetectedFormat = "A new {0} version {1} was detected and new templates are being imported.\nPlease hit the Update button on your ASE canvas to recompile your shader under the newest version.";
  61. private static string PackageBaseFormat = "ASE_PkgBase_{0}_{1}";
  62. private static string PackageCRCFormat = "ASE_PkgCRC_{0}_{1}";
  63. private static string SRPKeywordFormat = "ASE_SRP_VERSION {0}";
  64. private static string ASEVersionKeywordFormat = "ASE_VERSION {0}";
  65. private static Dictionary<int, ASESRPPackageDesc> m_srpPackageSupport = new Dictionary<int,ASESRPPackageDesc>()
  66. {
  67. { ( int )ASESRPBaseline.ASE_SRP_10, new ASESRPPackageDesc( ASESRPBaseline.ASE_SRP_10, "b460b52e6c1feae45b70b7ddc2c45bd6", "2243c8b4e1ab6914995699133f67ab5a" ) },
  68. { ( int )ASESRPBaseline.ASE_SRP_11, new ASESRPPackageDesc( ASESRPBaseline.ASE_SRP_11, "b460b52e6c1feae45b70b7ddc2c45bd6", "2243c8b4e1ab6914995699133f67ab5a" ) },
  69. { ( int )ASESRPBaseline.ASE_SRP_12, new ASESRPPackageDesc( ASESRPBaseline.ASE_SRP_12, "57fcea0ed8b5eb347923c4c21fa31b57", "9a5e61a8b3421b944863d0946e32da0a" ) },
  70. { ( int )ASESRPBaseline.ASE_SRP_13, new ASESRPPackageDesc( ASESRPBaseline.ASE_SRP_13, "57fcea0ed8b5eb347923c4c21fa31b57", "9a5e61a8b3421b944863d0946e32da0a" ) },
  71. { ( int )ASESRPBaseline.ASE_SRP_14, new ASESRPPackageDesc( ASESRPBaseline.ASE_SRP_14, "2e9da72e7e3196146bf7d27450013734", "89f0b84148d149d4d96b838d7ef60e92" ) },
  72. { ( int )ASESRPBaseline.ASE_SRP_15, new ASESRPPackageDesc( ASESRPBaseline.ASE_SRP_15, "0904cdf24ddcd5042b024326476220d5", "19939ee2cdb76e0489b1b8cd4bed7f3d" ) },
  73. { ( int )ASESRPBaseline.ASE_SRP_16, new ASESRPPackageDesc( ASESRPBaseline.ASE_SRP_16, "929783250050f8a448821b6ca1f2c578", "70777e8ce9f3c8d4a8182ca2f965cdb2" ) },
  74. { ( int )ASESRPBaseline.ASE_SRP_17, new ASESRPPackageDesc( ASESRPBaseline.ASE_SRP_17, "89da50d95d149b744bf10bd27babcf79", "daf511a6dae20e641a9d69d025f023e4" ) },
  75. };
  76. private static Shader m_lateShader;
  77. private static Material m_lateMaterial;
  78. private static AmplifyShaderFunction m_lateShaderFunction;
  79. private static ListRequest m_packageListRequest = null;
  80. private static UnityEditor.PackageManager.PackageInfo m_urpPackageInfo;
  81. private static UnityEditor.PackageManager.PackageInfo m_hdrpPackageInfo;
  82. public static bool FoundURPVersion { get { return m_urpPackageInfo != null; } }
  83. public static bool FoundHDRPVersion { get { return m_hdrpPackageInfo != null; } }
  84. private static bool m_lateImport = false;
  85. private static string m_latePackageToImport;
  86. private static bool m_requireUpdateList = false;
  87. private static ASEImportFlags m_importingPackage = ASEImportFlags.None;
  88. public static bool CheckImporter { get { return m_importingPackage != ASEImportFlags.None; } }
  89. public static bool IsProcessing { get { return m_requireUpdateList && m_importingPackage == ASEImportFlags.None; } }
  90. private static ASESRPBaseline m_currentURPBaseline = ASESRPBaseline.ASE_SRP_INVALID;
  91. private static ASESRPBaseline m_currentHDRPBaseline = ASESRPBaseline.ASE_SRP_INVALID;
  92. public static ASESRPBaseline CurrentURPBaseline { get { return m_currentURPBaseline; } }
  93. public static ASESRPBaseline CurrentHDRPBaseline { get { return m_currentHDRPBaseline; } }
  94. private static int m_packageURPVersion = -1; // @diogo: starts as missing
  95. private static int m_packageHDRPVersion = -1;
  96. public static int PackageSRPVersion { get { return ( m_packageHDRPVersion >= m_packageURPVersion ) ? m_packageHDRPVersion : m_packageURPVersion; } }
  97. public static int CurrentSRPVersion { get { return UIUtils.CurrentWindow.MainGraphInstance.IsSRP ? PackageSRPVersion : -1; } }
  98. private static string m_projectName = null;
  99. private static string ProjectName
  100. {
  101. get
  102. {
  103. if ( string.IsNullOrEmpty( m_projectName ) )
  104. {
  105. string[] s = Application.dataPath.Split( '/' );
  106. m_projectName = s[ s.Length - 2 ];
  107. }
  108. return m_projectName;
  109. }
  110. }
  111. static ASEPackageManagerHelper()
  112. {
  113. RequestInfo( true );
  114. }
  115. static void WaitForPackageListBeforeUpdating()
  116. {
  117. if ( m_packageListRequest.IsCompleted )
  118. {
  119. Update();
  120. EditorApplication.update -= WaitForPackageListBeforeUpdating;
  121. }
  122. }
  123. public static void RequestInfo( bool updateWhileWaiting = false )
  124. {
  125. if ( !m_requireUpdateList && m_importingPackage == ASEImportFlags.None )
  126. {
  127. m_requireUpdateList = true;
  128. m_packageListRequest = UnityEditor.PackageManager.Client.List( true );
  129. if ( updateWhileWaiting )
  130. {
  131. EditorApplication.update += WaitForPackageListBeforeUpdating;
  132. }
  133. }
  134. }
  135. static void FailedPackageImport( string packageName, string errorMessage )
  136. {
  137. FinishImporter();
  138. }
  139. static void CancelledPackageImport( string packageName )
  140. {
  141. FinishImporter();
  142. }
  143. static void CompletedPackageImport( string packageName )
  144. {
  145. FinishImporter();
  146. }
  147. public static void CheckLatePackageImport()
  148. {
  149. if ( !Application.isPlaying && m_lateImport && !string.IsNullOrEmpty( m_latePackageToImport ) )
  150. {
  151. m_lateImport = false;
  152. StartImporting( m_latePackageToImport );
  153. m_latePackageToImport = string.Empty;
  154. }
  155. }
  156. public static void StartImporting( string packagePath )
  157. {
  158. if ( !Preferences.Project.AutoSRP )
  159. {
  160. m_importingPackage = ASEImportFlags.None;
  161. return;
  162. }
  163. if ( Application.isPlaying )
  164. {
  165. if ( !m_lateImport )
  166. {
  167. m_lateImport = true;
  168. m_latePackageToImport = packagePath;
  169. Debug.LogWarning( "Amplify Shader Editor requires the \"" + packagePath + "\" package to be installed in order to continue. Please exit Play mode to proceed." );
  170. }
  171. return;
  172. }
  173. AssetDatabase.importPackageCancelled += CancelledPackageImport;
  174. AssetDatabase.importPackageCompleted += CompletedPackageImport;
  175. AssetDatabase.importPackageFailed += FailedPackageImport;
  176. AssetDatabase.ImportPackage( packagePath, false );
  177. //AssetDatabaseEX.ImportPackageImmediately( packagePath );
  178. }
  179. public static void FinishImporter()
  180. {
  181. m_importingPackage = ASEImportFlags.None;
  182. AssetDatabase.importPackageCancelled -= CancelledPackageImport;
  183. AssetDatabase.importPackageCompleted -= CompletedPackageImport;
  184. AssetDatabase.importPackageFailed -= FailedPackageImport;
  185. }
  186. public static void SetupLateShader( Shader shader )
  187. {
  188. if ( shader == null )
  189. return;
  190. //If a previous delayed object is pending discard it and register the new one
  191. // So the last selection will be the choice of opening
  192. //This can happen when trying to open an ASE canvas while importing templates or in play mode
  193. if ( m_lateShader != null )
  194. {
  195. EditorApplication.delayCall -= LateShaderOpener;
  196. }
  197. RequestInfo();
  198. m_lateShader = shader;
  199. EditorApplication.delayCall += LateShaderOpener;
  200. }
  201. public static void LateShaderOpener()
  202. {
  203. Update();
  204. if ( IsProcessing )
  205. {
  206. EditorApplication.delayCall += LateShaderOpener;
  207. }
  208. else
  209. {
  210. AmplifyShaderEditorWindow.ConvertShaderToASE( m_lateShader );
  211. m_lateShader = null;
  212. }
  213. }
  214. public static void SetupLateMaterial( Material material )
  215. {
  216. if ( material == null )
  217. return;
  218. //If a previous delayed object is pending discard it and register the new one
  219. // So the last selection will be the choice of opening
  220. //This can happen when trying to open an ASE canvas while importing templates or in play mode
  221. if ( m_lateMaterial != null )
  222. {
  223. EditorApplication.delayCall -= LateMaterialOpener;
  224. }
  225. RequestInfo();
  226. m_lateMaterial = material;
  227. EditorApplication.delayCall += LateMaterialOpener;
  228. }
  229. public static void LateMaterialOpener()
  230. {
  231. Update();
  232. if ( IsProcessing )
  233. {
  234. EditorApplication.delayCall += LateMaterialOpener;
  235. }
  236. else
  237. {
  238. AmplifyShaderEditorWindow.LoadMaterialToASE( m_lateMaterial );
  239. m_lateMaterial = null;
  240. }
  241. }
  242. public static void SetupLateShaderFunction( AmplifyShaderFunction shaderFunction )
  243. {
  244. if ( shaderFunction == null )
  245. return;
  246. //If a previous delayed object is pending discard it and register the new one
  247. // So the last selection will be the choice of opening
  248. //This can happen when trying to open an ASE canvas while importing templates or in play mode
  249. if ( m_lateShaderFunction != null )
  250. {
  251. EditorApplication.delayCall -= LateShaderFunctionOpener;
  252. }
  253. RequestInfo();
  254. m_lateShaderFunction = shaderFunction;
  255. EditorApplication.delayCall += LateShaderFunctionOpener;
  256. }
  257. public static void LateShaderFunctionOpener()
  258. {
  259. Update();
  260. if ( IsProcessing )
  261. {
  262. EditorApplication.delayCall += LateShaderFunctionOpener;
  263. }
  264. else
  265. {
  266. AmplifyShaderEditorWindow.LoadShaderFunctionToASE( m_lateShaderFunction, false );
  267. m_lateShaderFunction = null;
  268. }
  269. }
  270. private static readonly string SemVerPattern = @"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$";
  271. private static int PackageVersionStringToCode( string version, out int major, out int minor, out int patch )
  272. {
  273. MatchCollection matches = Regex.Matches( version, SemVerPattern, RegexOptions.Multiline );
  274. bool validMatch = ( matches.Count > 0 && matches[ 0 ].Groups.Count >= 4 );
  275. major = validMatch ? int.Parse( matches[ 0 ].Groups[ 1 ].Value ) : 99;
  276. minor = validMatch ? int.Parse( matches[ 0 ].Groups[ 2 ].Value ) : 99;
  277. patch = validMatch ? int.Parse( matches[ 0 ].Groups[ 3 ].Value ) : 99;
  278. int versionCode;
  279. versionCode = major * 10000;
  280. versionCode += minor * 100;
  281. versionCode += patch;
  282. return versionCode;
  283. }
  284. private static void CodeToPackageVersionElements( int versionCode, out int major, out int minor, out int patch )
  285. {
  286. major = versionCode / 10000;
  287. minor = versionCode / 100 - major * 100;
  288. patch = versionCode - ( versionCode / 100 ) * 100;
  289. }
  290. private static int PackageVersionElementsToCode( int major, int minor, int patch )
  291. {
  292. return major * 10000 + minor * 100 + patch;
  293. }
  294. private static void CheckPackageImport( ASEImportFlags flag, ASESRPBaseline baseline, string guid, string version )
  295. {
  296. Debug.Assert( flag == ASEImportFlags.HDRP || flag == ASEImportFlags.URP );
  297. string path = AssetDatabase.GUIDToAssetPath( guid );
  298. if ( !string.IsNullOrEmpty( path ) && File.Exists( path ) )
  299. {
  300. uint currentCRC = IOUtils.CRC32( File.ReadAllBytes( path ) );
  301. string srpName = flag.ToString();
  302. string packageBaseKey = string.Format( PackageBaseFormat, srpName, ProjectName );
  303. string packageCRCKey = string.Format( PackageCRCFormat, srpName, ProjectName );
  304. ASESRPBaseline savedBaseline = ( ASESRPBaseline )EditorPrefs.GetInt( packageBaseKey );
  305. uint savedCRC = ( uint )EditorPrefs.GetInt( packageCRCKey, 0 );
  306. bool foundNewVersion = ( savedBaseline != baseline ) || ( savedCRC != currentCRC );
  307. EditorPrefs.SetInt( packageBaseKey, ( int )baseline );
  308. EditorPrefs.SetInt( packageCRCKey, ( int )currentCRC );
  309. string testPath0 = string.Empty;
  310. string testPath1 = string.Empty;
  311. switch ( flag )
  312. {
  313. case ASEImportFlags.URP:
  314. {
  315. testPath0 = AssetDatabase.GUIDToAssetPath( TemplatesManager.URPLitGUID );
  316. testPath1 = AssetDatabase.GUIDToAssetPath( TemplatesManager.URPUnlitGUID );
  317. break;
  318. }
  319. case ASEImportFlags.HDRP:
  320. {
  321. testPath0 = AssetDatabase.GUIDToAssetPath( TemplatesManager.HDRPLitGUID );
  322. testPath1 = AssetDatabase.GUIDToAssetPath( TemplatesManager.HDRPUnlitGUID );
  323. break;
  324. }
  325. }
  326. if ( !File.Exists( testPath0 ) || !File.Exists( testPath1 ) || foundNewVersion )
  327. {
  328. if ( foundNewVersion )
  329. {
  330. Debug.Log( string.Format( NewVersionDetectedFormat, srpName, version ) );
  331. }
  332. m_importingPackage |= flag;
  333. StartImporting( path );
  334. }
  335. }
  336. }
  337. public static void Update()
  338. {
  339. CheckLatePackageImport();
  340. if ( m_requireUpdateList && m_importingPackage == ASEImportFlags.None )
  341. {
  342. if ( m_packageListRequest != null && m_packageListRequest.IsCompleted && m_packageListRequest.Result != null )
  343. {
  344. m_requireUpdateList = false;
  345. foreach ( UnityEditor.PackageManager.PackageInfo pi in m_packageListRequest.Result )
  346. {
  347. int version = PackageVersionStringToCode( pi.version, out int major, out int minor, out int patch );
  348. int baseline = PackageVersionElementsToCode( major, 0, 0 );
  349. ASESRPPackageDesc match;
  350. if ( pi.name.Equals( URPPackageId ) && m_srpPackageSupport.TryGetValue( baseline, out match ) )
  351. {
  352. // Universal Rendering Pipeline
  353. m_currentURPBaseline = match.baseline;
  354. m_packageURPVersion = version;
  355. m_urpPackageInfo = pi;
  356. CheckPackageImport( ASEImportFlags.URP, match.baseline, match.guidURP, pi.version );
  357. }
  358. else if ( pi.name.Equals( HDRPPackageId ) && m_srpPackageSupport.TryGetValue( baseline, out match ) )
  359. {
  360. // High-Definition Rendering Pipeline
  361. m_currentHDRPBaseline = match.baseline;
  362. m_packageHDRPVersion = version;
  363. m_hdrpPackageInfo = pi;
  364. CheckPackageImport( ASEImportFlags.HDRP, match.baseline, match.guidHDRP, pi.version );
  365. }
  366. }
  367. }
  368. }
  369. }
  370. public static void SetASEVersionInfoOnDataCollector( ref MasterNodeDataCollector dataCollector )
  371. {
  372. if ( m_requireUpdateList )
  373. {
  374. Update();
  375. }
  376. dataCollector.AddToDirectives( string.Format( ASEVersionKeywordFormat, VersionInfo.FullNumber ), -1, AdditionalLineType.Define );
  377. }
  378. public static void SetSRPInfoOnDataCollector( ref MasterNodeDataCollector dataCollector )
  379. {
  380. if ( m_requireUpdateList )
  381. {
  382. Update();
  383. }
  384. if ( dataCollector.CurrentSRPType == TemplateSRPType.HDRP )
  385. {
  386. dataCollector.AddToDirectives( string.Format( SRPKeywordFormat, m_packageHDRPVersion ), -1, AdditionalLineType.Define );
  387. }
  388. else if ( dataCollector.CurrentSRPType == TemplateSRPType.URP )
  389. {
  390. dataCollector.AddToDirectives( string.Format( SRPKeywordFormat, m_packageURPVersion ), -1, AdditionalLineType.Define );
  391. }
  392. }
  393. }
  394. }