ASESaveBundleTool.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. using UnityEngine;
  2. using UnityEditor;
  3. using UnityEditorInternal;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Text.RegularExpressions;
  7. namespace AmplifyShaderEditor
  8. {
  9. public enum ASESaveBundleAssetAction
  10. {
  11. Update,
  12. Export,
  13. UpdateAndExport
  14. }
  15. [CustomEditor( typeof( ASESaveBundleAsset ) )]
  16. public class ASESaveBundleAssetEditor : Editor
  17. {
  18. public ASESaveBundleAsset Instance;
  19. private DragAndDropTool m_dragAndDropTool;
  20. private SerializedObject m_so;
  21. private SerializedProperty m_packageContentsOrigin;
  22. private GUIContent m_packageContentsOriginLabel = new GUIContent("Main Content");
  23. private SerializedProperty m_allExtras;
  24. private SerializedProperty m_packageTargetPath;
  25. private GUIContent m_packageTargetPathLabel = new GUIContent( "Target Path" );
  26. private SerializedProperty m_packageTargetName;
  27. private GUIContent m_packageTargetNameLabel = new GUIContent( "Target Name" );
  28. private SerializedProperty m_allShaders;
  29. [SerializeField]
  30. private ReorderableList m_listShaders = null;
  31. [SerializeField]
  32. private ReorderableList m_listExtras = null;
  33. public void OnEnable()
  34. {
  35. Instance = (ASESaveBundleAsset)target;
  36. m_so = serializedObject;
  37. m_packageContentsOrigin = m_so.FindProperty( "m_packageContentsOrigin" );
  38. m_packageTargetPath = m_so.FindProperty( "m_packageTargetPath" );
  39. m_packageTargetName = m_so.FindProperty( "m_packageTargetName" );
  40. m_allShaders = m_so.FindProperty( "m_allShaders" );
  41. if( m_listShaders == null )
  42. {
  43. m_listShaders = new ReorderableList( m_so , m_allShaders , true , true , true , true );
  44. m_listShaders.elementHeight = 16;
  45. m_listShaders.drawElementCallback = ( Rect rect , int index , bool isActive , bool isFocused ) =>
  46. {
  47. m_allShaders.GetArrayElementAtIndex( index ).objectReferenceValue = (Shader)EditorGUI.ObjectField( rect , "Shader " + index , m_allShaders.GetArrayElementAtIndex( index ).objectReferenceValue , typeof( Shader ) , false );
  48. };
  49. m_listShaders.drawHeaderCallback = ( Rect rect ) =>
  50. {
  51. EditorGUI.LabelField( rect , "Shader List" );
  52. };
  53. m_listShaders.onAddCallback = ( list ) =>
  54. {
  55. m_allShaders.InsertArrayElementAtIndex( m_allShaders.arraySize );
  56. m_allShaders.GetArrayElementAtIndex( m_allShaders.arraySize - 1 ).objectReferenceValue = null;
  57. };
  58. m_listShaders.onRemoveCallback = ( list ) =>
  59. {
  60. m_allShaders.GetArrayElementAtIndex( list.index ).objectReferenceValue = null;
  61. m_allShaders.DeleteArrayElementAtIndex( list.index );
  62. };
  63. }
  64. m_allExtras = m_so.FindProperty( "m_allExtras" );
  65. if( m_listExtras == null )
  66. {
  67. m_listExtras = new ReorderableList( m_so , m_allExtras , true , true , true , true );
  68. m_listExtras.elementHeight = 18;
  69. m_listExtras.drawElementCallback = ( Rect rect , int index , bool isActive , bool isFocused ) =>
  70. {
  71. rect.width -= 55;
  72. m_allExtras.GetArrayElementAtIndex( index ).stringValue = (string)EditorGUI.TextField( rect , "Path " + index , m_allExtras.GetArrayElementAtIndex( index ).stringValue );
  73. rect.x += rect.width;
  74. rect.width = 55;
  75. if( GUI.Button( rect, "Browse" ) )
  76. m_allExtras.GetArrayElementAtIndex( index ).stringValue = ASESaveBundleTool.FetchPath( "Folder Path" , m_allExtras.GetArrayElementAtIndex( index ).stringValue );
  77. };
  78. m_listExtras.drawHeaderCallback = ( Rect rect ) =>
  79. {
  80. EditorGUI.LabelField( rect , "Extra Paths" );
  81. };
  82. m_listExtras.onAddCallback = ( list ) =>
  83. {
  84. m_allExtras.InsertArrayElementAtIndex( m_allExtras.arraySize );
  85. m_allExtras.GetArrayElementAtIndex( m_allExtras.arraySize - 1 ).stringValue = string.Empty;
  86. };
  87. m_listExtras.onRemoveCallback = ( list ) =>
  88. {
  89. m_allExtras.GetArrayElementAtIndex( list.index ).stringValue = string.Empty;
  90. m_allExtras.DeleteArrayElementAtIndex( list.index );
  91. };
  92. }
  93. m_dragAndDropTool = new DragAndDropTool();
  94. m_dragAndDropTool.OnValidDropObjectEvt += OnValidObjectsDropped;
  95. }
  96. void FetchValidShadersFromPath( string path , bool updateProperty )
  97. {
  98. if( !path.StartsWith( "Assets" ) )
  99. {
  100. int idx = path.IndexOf( "Assets" );
  101. if( idx >= 0 )
  102. {
  103. path = path.Substring( idx );
  104. }
  105. }
  106. if( AssetDatabase.IsValidFolder( path ) )
  107. {
  108. if( updateProperty )
  109. m_packageContentsOrigin.stringValue = path;
  110. string[] pathArr = { path };
  111. string[] shaderInDir = AssetDatabase.FindAssets( "t:Shader" , pathArr );
  112. for( int shaderIdx = 0 ; shaderIdx < shaderInDir.Length ; shaderIdx++ )
  113. {
  114. Shader internalShader = AssetDatabase.LoadAssetAtPath<Shader>( AssetDatabase.GUIDToAssetPath( shaderInDir[ shaderIdx ] ) );
  115. if( internalShader != null && IOUtils.IsASEShader( internalShader ) )
  116. {
  117. m_allShaders.InsertArrayElementAtIndex( m_allShaders.arraySize );
  118. m_allShaders.GetArrayElementAtIndex( m_allShaders.arraySize - 1 ).objectReferenceValue = internalShader;
  119. m_so.ApplyModifiedProperties();
  120. }
  121. }
  122. }
  123. }
  124. public void OnValidObjectsDropped( UnityEngine.Object[] droppedObjs )
  125. {
  126. for( int objIdx = 0 ; objIdx < droppedObjs.Length ; objIdx++ )
  127. {
  128. Shader shader = droppedObjs[ objIdx ] as Shader;
  129. if( shader != null )
  130. {
  131. if( IOUtils.IsASEShader( shader ) )
  132. {
  133. m_allShaders.InsertArrayElementAtIndex( m_allShaders.arraySize );
  134. m_allShaders.GetArrayElementAtIndex( m_allShaders.arraySize - 1 ).objectReferenceValue = shader;
  135. m_so.ApplyModifiedProperties();
  136. }
  137. }
  138. else
  139. {
  140. DefaultAsset asset = droppedObjs[ objIdx ] as DefaultAsset;
  141. if( asset != null )
  142. {
  143. string path = AssetDatabase.GetAssetPath( asset );
  144. FetchValidShadersFromPath( path,true );
  145. }
  146. }
  147. }
  148. Instance.AllShaders.Sort( ( x , y ) => string.Compare( x.name , y.name ) );
  149. m_so.Update();
  150. }
  151. private void OnDestroy()
  152. {
  153. m_dragAndDropTool.Destroy();
  154. m_dragAndDropTool = null;
  155. }
  156. public override void OnInspectorGUI()
  157. {
  158. m_so.Update();
  159. EditorGUILayout.Separator();
  160. EditorGUILayout.BeginHorizontal();
  161. {
  162. EditorGUILayout.PropertyField( m_packageContentsOrigin, m_packageContentsOriginLabel );
  163. if( GUILayout.Button( "Browse", GUILayout.MaxWidth( 55 ) ) )
  164. {
  165. m_packageContentsOrigin.stringValue = ASESaveBundleTool.FetchPath( "Folder Path" , m_packageContentsOrigin.stringValue );
  166. }
  167. if( GUILayout.Button( "Fetch" , GUILayout.MaxWidth( 45 ) ) )
  168. {
  169. FetchValidShadersFromPath( m_packageContentsOrigin.stringValue, false );
  170. }
  171. }
  172. EditorGUILayout.EndHorizontal();
  173. if( m_listExtras != null )
  174. m_listExtras.DoLayoutList();
  175. EditorGUILayout.Separator();
  176. EditorGUILayout.BeginHorizontal();
  177. {
  178. EditorGUILayout.PropertyField( m_packageTargetPath , m_packageTargetPathLabel );
  179. if( GUILayout.Button( "Browse",GUILayout.MaxWidth(55) ))
  180. m_packageTargetPath.stringValue = EditorUtility.OpenFolderPanel( "Folder Path" , m_packageTargetPath.stringValue , "" );
  181. }
  182. EditorGUILayout.EndHorizontal();
  183. EditorGUILayout.PropertyField( m_packageTargetName, m_packageTargetNameLabel );
  184. EditorGUILayout.Separator();
  185. if( GUILayout.Button( "Clear" ) )
  186. {
  187. m_allShaders.ClearArray();
  188. }
  189. if( m_listShaders != null )
  190. m_listShaders.DoLayoutList();
  191. EditorGUILayout.Separator();
  192. m_dragAndDropTool.TestDragAndDrop( new Rect( 0 , 0 , Screen.width , Screen.height ) );
  193. m_so.ApplyModifiedProperties();
  194. }
  195. }
  196. public class ASESaveBundleTool : EditorWindow
  197. {
  198. private const string UpdateAllStr = "Update All";
  199. private const string UpdateAllStyle = "prebutton";
  200. [SerializeField]
  201. private ASESaveBundleAsset m_asset;
  202. [SerializeField]
  203. private ASESaveBundleAsset m_dummyAsset;
  204. private GUIStyle m_contentStyle = null;
  205. private Vector2 m_scrollPos;
  206. private GUIContent m_ViewToolIcon;
  207. ASESaveBundleAssetEditor m_editor;
  208. private const string Title = "Batch Save and Pack";
  209. [NonSerialized]
  210. private GUIStyle m_titleStyle;
  211. [MenuItem( "Window/Amplify Shader Editor/"+ Title , false , 1001 )]
  212. static void ShowWindow()
  213. {
  214. ASESaveBundleTool window = EditorWindow.GetWindow<ASESaveBundleTool>();
  215. window.titleContent.text = "Batch Save...";
  216. window.titleContent.tooltip = Title;
  217. window.minSize = new Vector2( 302 , 350 );
  218. window.Show();
  219. }
  220. private void OnEnable()
  221. {
  222. if( m_contentStyle == null )
  223. {
  224. m_contentStyle = new GUIStyle( GUIStyle.none );
  225. m_contentStyle.margin = new RectOffset( 6 , 4 , 5 , 5 );
  226. }
  227. if( m_ViewToolIcon == null )
  228. {
  229. m_ViewToolIcon = EditorGUIUtility.IconContent( "icons/d_ViewToolZoom.png" );
  230. }
  231. }
  232. private void OnDestroy()
  233. {
  234. DestroyImmediate( m_editor );
  235. if( m_dummyAsset != null && m_dummyAsset != m_asset )
  236. DestroyImmediate( m_dummyAsset );
  237. }
  238. public static string FetchPath( string title, string folderpath )
  239. {
  240. folderpath = EditorUtility.OpenFolderPanel( title , folderpath , "" );
  241. folderpath = FileUtil.GetProjectRelativePath( folderpath );
  242. if( string.IsNullOrEmpty( folderpath ) )
  243. folderpath = "Assets";
  244. return folderpath;
  245. }
  246. private bool m_updatingShaders = false;
  247. private void ExportCurrent( ASESaveBundleAsset currentAsset )
  248. {
  249. List<string> pathsList = new List<string>();
  250. pathsList.Add( currentAsset.PackageContentsOrigin );
  251. for( int i = 0 ; i < currentAsset.AllExtras.Count ; i++ )
  252. {
  253. if( currentAsset.AllExtras[ i ].StartsWith( "Assets" ) )
  254. {
  255. pathsList.Add( currentAsset.AllExtras[ i ] );
  256. }
  257. else
  258. {
  259. int idx = currentAsset.AllExtras[ i ].IndexOf( "Assets" );
  260. if( idx >= 0 )
  261. {
  262. pathsList.Add( currentAsset.AllExtras[ i ].Substring( idx ) );
  263. }
  264. }
  265. }
  266. AssetDatabase.ExportPackage( pathsList.ToArray() , currentAsset.PackageTargetPath + "/" + currentAsset.PackageTargetName + ".unitypackage" , ExportPackageOptions.Recurse | ExportPackageOptions.Interactive );
  267. }
  268. private void OnGUI()
  269. {
  270. if( m_updatingShaders )
  271. {
  272. m_updatingShaders = EditorPrefs.HasKey( AmplifyShaderEditorWindow.ASEFileList );
  273. }
  274. if( m_titleStyle == null )
  275. {
  276. m_titleStyle = new GUIStyle( "BoldLabel" );
  277. m_titleStyle.fontSize = 13;
  278. m_titleStyle.alignment = TextAnchor.MiddleCenter;
  279. }
  280. EditorGUILayout.LabelField( Title , m_titleStyle );
  281. EditorGUI.BeginDisabledGroup( m_updatingShaders );
  282. {
  283. ASESaveBundleAsset currentAsset = null;
  284. if( m_asset != null )
  285. {
  286. currentAsset = m_asset;
  287. }
  288. else
  289. {
  290. if( m_dummyAsset == null )
  291. {
  292. m_dummyAsset = ScriptableObject.CreateInstance<ASESaveBundleAsset>();
  293. m_dummyAsset.name = "Dummy";
  294. }
  295. currentAsset = m_dummyAsset;
  296. }
  297. m_scrollPos = EditorGUILayout.BeginScrollView( m_scrollPos , GUILayout.Height( position.height ) );
  298. {
  299. float cachedWidth = EditorGUIUtility.labelWidth;
  300. EditorGUIUtility.labelWidth = 100;
  301. EditorGUILayout.BeginVertical( m_contentStyle );
  302. {
  303. EditorGUI.BeginDisabledGroup( currentAsset.AllShaders.Count <= 0 );
  304. {
  305. // Update all shaders
  306. if( GUILayout.Button( UpdateAllStr/* , UpdateAllStyle , GUILayout.Height( 20 )*/ ) )
  307. {
  308. m_updatingShaders = true;
  309. string[] assetPaths = new string[ currentAsset.AllShaders.Count ];
  310. for( int i = 0 ; i < assetPaths.Length ; i++ )
  311. {
  312. assetPaths[ i ] = AssetDatabase.GetAssetPath( currentAsset.AllShaders[ i ] );
  313. }
  314. AmplifyShaderEditorWindow.LoadAndSaveList( assetPaths );
  315. }
  316. if( GUILayout.Button( "Remove Custom Inspector" ) )
  317. {
  318. int count = currentAsset.AllShaders.Count;
  319. for( int i = 0 ; i < count ; i++ )
  320. {
  321. EditorUtility.DisplayProgressBar( "Removing custom inspector", currentAsset.AllShaders[i].name , i / ( count - 1 ) );
  322. string path = AssetDatabase.GetAssetPath( currentAsset.AllShaders[ i ] );
  323. string shaderBody = IOUtils.LoadTextFileFromDisk( path );
  324. shaderBody = Regex.Replace( shaderBody , TemplateHelperFunctions.CustomInspectorPattern , string.Empty ,RegexOptions.Multiline );
  325. shaderBody = UIUtils.ForceLFLineEnding( shaderBody );
  326. IOUtils.SaveTextfileToDisk( shaderBody , path , false );
  327. }
  328. AssetDatabase.Refresh();
  329. EditorUtility.ClearProgressBar();
  330. }
  331. }
  332. EditorGUI.EndDisabledGroup();
  333. EditorGUI.BeginDisabledGroup( string.IsNullOrEmpty( currentAsset.PackageTargetName ) || string.IsNullOrEmpty( currentAsset.PackageTargetPath ) );
  334. {
  335. if( GUILayout.Button( "Export Unity Package" ) )
  336. {
  337. ExportCurrent( currentAsset );
  338. }
  339. }
  340. EditorGUI.EndDisabledGroup();
  341. EditorGUILayout.Separator();
  342. // Asset creation/load
  343. EditorGUILayout.BeginHorizontal();
  344. m_asset = EditorGUILayout.ObjectField( "Asset Preset" , m_asset , typeof( ASESaveBundleAsset ) , false ) as ASESaveBundleAsset;
  345. if( GUILayout.Button( m_asset != null ? "Save" : "Create" , "minibutton" , GUILayout.Width( 50 ) ) )
  346. {
  347. string defaultName = "ShaderBundlePreset";
  348. string assetPath = string.Empty;
  349. if( m_asset != null )
  350. {
  351. defaultName = m_asset.name;
  352. assetPath = Application.dataPath.Substring(0, Application.dataPath.Length - 6 )+ AssetDatabase.GetAssetPath( m_asset );
  353. }
  354. string path = EditorUtility.SaveFilePanelInProject( "Save as" , defaultName , "asset" , string.Empty , assetPath );
  355. if( !string.IsNullOrEmpty( path ) )
  356. {
  357. ASESaveBundleAsset outfile = AssetDatabase.LoadMainAssetAtPath( path ) as ASESaveBundleAsset;
  358. if( outfile != null )
  359. {
  360. EditorUtility.CopySerialized( currentAsset , outfile );
  361. AssetDatabase.SaveAssets();
  362. Selection.activeObject = outfile;
  363. EditorGUIUtility.PingObject( outfile );
  364. }
  365. else
  366. {
  367. if( m_asset != null )
  368. {
  369. currentAsset = ScriptableObject.CreateInstance<ASESaveBundleAsset>();
  370. EditorUtility.CopySerialized( m_asset , currentAsset );
  371. }
  372. AssetDatabase.CreateAsset( currentAsset , path );
  373. Selection.activeObject = currentAsset;
  374. EditorGUIUtility.PingObject( currentAsset );
  375. m_asset = currentAsset;
  376. }
  377. }
  378. }
  379. EditorGUILayout.EndHorizontal();
  380. if( Event.current.type == EventType.Layout )
  381. {
  382. if( m_editor == null )
  383. {
  384. m_editor = Editor.CreateEditor( currentAsset , typeof( ASESaveBundleAssetEditor ) ) as ASESaveBundleAssetEditor;
  385. }
  386. else
  387. {
  388. if( m_editor.Instance != currentAsset )
  389. {
  390. DestroyImmediate( m_editor );
  391. m_editor = Editor.CreateEditor( currentAsset , typeof( ASESaveBundleAssetEditor ) ) as ASESaveBundleAssetEditor;
  392. }
  393. }
  394. }
  395. if( m_editor != null )
  396. m_editor.OnInspectorGUI();
  397. }
  398. EditorGUILayout.EndVertical();
  399. }
  400. EditorGUILayout.EndScrollView();
  401. }
  402. EditorGUI.EndDisabledGroup();
  403. }
  404. }
  405. }