FSequenceWindowHeader.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System.Collections.Generic;
  4. using System.Security;
  5. using Mono.Xml;
  6. using Flux;
  7. namespace FluxEditor
  8. {
  9. public class FSequenceWindowHeader
  10. {
  11. // padding on top, bottom, left and right
  12. public const float PADDING = 5;
  13. // space between labels and the fields
  14. public const float LABEL_SPACE = 5;
  15. // space between elements (i.e. label+field pairs)
  16. public const float ELEMENT_SPACE = 20;
  17. // height of the header
  18. public const float HEIGHT = 20 + PADDING + PADDING;
  19. private const float MAX_SEQUENCE_POPUP_WIDTH = 250;
  20. private const float UPDATE_MODE_FIELD_WIDTH = 100;
  21. private const float FRAMERATE_FIELD_WIDTH = 40;
  22. private const float LENGTH_FIELD_WIDTH = 100;
  23. // window this header belongs to
  24. private FSequenceEditorWindow _sequenceWindow;
  25. private SerializedObject _sequenceSO;
  26. private SerializedProperty _sequenceUpdateMode;
  27. private SerializedProperty _sequenceLength;
  28. // sequence selection popup variables
  29. private GUIContent _sequenceLabel = new GUIContent( "FrameEvents", "Select FrameEvent..." );
  30. // rect of the sequence label
  31. private Rect _sequenceLabelRect;
  32. // rect of the sequence name
  33. private Rect _sequencePopupRect;
  34. // rect for the button to create a new sequence
  35. private Rect _sequenceAddButtonRect;
  36. private FSequence[] _sequences;
  37. private GUIContent[] _sequenceNames;
  38. private int _selectedSequenceIndex;
  39. private GUIContent _fileLabel = new GUIContent("文件列表", "请选择编辑的buff文件");
  40. private Rect _fileLabelRect;
  41. private Rect _fileSearchRect;
  42. private Rect _fileListPopupRect;
  43. private List<string> mFrameEventFiles = new List<string>();
  44. private List<string> mFileNames = new List<string>();
  45. private List<string> mSearchFiles = new List<string>();
  46. private int _selectedFileIndex;
  47. private Dictionary<string, FSequence> mEventFileMapping = new Dictionary<string, FSequence>();
  48. // update mode UI variables
  49. private GUIContent _updateModeLabel = new GUIContent( "Update Mode", "How does the sequence update:\n\tNormal: uses Time.time in Update()\n\tAnimatePhysics: uses Time.fixedTime in FixedUpdate()\n\tUnscaledTime: uses Time.unscaledTime in Update()" );
  50. private Rect _updateModeLabelRect;
  51. private Rect _updateModeFieldRect;
  52. private bool _showUpdadeMode;
  53. // framerate UI variables
  54. private GUIContent _framerateLabel = new GUIContent( "Frame Rate", "How many frames does the sequence have per second" );
  55. private Rect _framerateLabelRect;
  56. private Rect _framerateFieldRect;
  57. private bool _showFramerate;
  58. // length UI variables
  59. private GUIContent _lengthLabel = new GUIContent( "Length", "What's the length of the sequence" );
  60. private Rect _lengthLabelRect;
  61. private Rect _lengthFieldRect;
  62. private bool _showLength;
  63. private GUIContent _addContainerLabel = new GUIContent( string.Empty, "新增新的FrameEvent" );
  64. private Rect _addContainerRect;
  65. private bool _showAddContainer;
  66. private GUIContent _openInspectorLabel = new GUIContent( string.Empty, "打开内容编辑" );
  67. private Rect _openInspectorRect;
  68. private GUIContent _saveEventLabel = new GUIContent(string.Empty, "保存内容");
  69. private Rect _saveEventRect;
  70. private GUIContent _refreshLabel = new GUIContent("刷新", "重新刷新技能编辑器");
  71. private Rect _refreshRect;
  72. // cached number field style, since we want numbers centered
  73. private GUIStyle _numberFieldStyle;
  74. private string searchContent = "";
  75. public FSequenceWindowHeader( FSequenceEditorWindow sequenceWindow )
  76. {
  77. _sequenceWindow = sequenceWindow;
  78. LoadFrameEventFromXml();
  79. RebuildSequenceList();
  80. EditorApplication.hierarchyWindowChanged += OnHierarchyChanged;
  81. _addContainerLabel.image = FUtility.GetFluxTexture("AddFolder.png");
  82. _openInspectorLabel.image = FUtility.GetFluxTexture("Inspector.png");
  83. _saveEventLabel.image = FUtility.GetFluxTexture("SkinSave.png");
  84. }
  85. private void OnHierarchyChanged()
  86. {
  87. RebuildSequenceList();
  88. }
  89. private void LoadFrameEventFromXml()
  90. {
  91. _selectedFileIndex = -1;
  92. mEventFileMapping.Clear();
  93. mFrameEventFiles.Clear();
  94. mFileNames.Clear();
  95. mSearchFiles.Clear();
  96. string[] fileList = FileUtils.TraverseAllFiles("Assets/Content/Xml/Skill", "*.xml");
  97. for (int idx = 0; idx < fileList.Length; idx++)
  98. {
  99. if (!fileList[idx].Contains("buff_")) continue;
  100. mFrameEventFiles.Add(fileList[idx]);
  101. }
  102. for (int idx = 0; idx < mFrameEventFiles.Count; idx++)
  103. {
  104. mFileNames.Add(FileUtils.RemoveExtension(FileUtils.ExtractPureName(mFrameEventFiles[idx])));
  105. }
  106. mSearchFiles.AddRange(mFileNames);
  107. }
  108. private void RebuildSequenceList()
  109. {
  110. _sequences = GameObject.FindObjectsOfType<FSequence>();
  111. System.Array.Sort<FSequence>( _sequences, delegate(FSequence x, FSequence y) { return x.name.CompareTo(y.name); } );
  112. _sequenceNames = new GUIContent[_sequences.Length+1];
  113. for( int i = 0; i != _sequences.Length; ++i )
  114. {
  115. _sequenceNames[i] = new GUIContent(_sequences[i].name);
  116. }
  117. _sequenceNames[_sequenceNames.Length-1] = new GUIContent("[Create New FrameEvent]");
  118. _selectedSequenceIndex = -1;
  119. }
  120. public void RebuildLayout( Rect rect )
  121. {
  122. rect.xMin += PADDING;
  123. rect.yMin += PADDING;
  124. rect.xMax -= PADDING;
  125. rect.yMax -= PADDING;
  126. float width = rect.width;
  127. _openInspectorRect = rect;
  128. _saveEventRect = rect;
  129. _updateModeLabelRect = _updateModeFieldRect = rect;
  130. _framerateLabelRect = _framerateFieldRect = rect;
  131. _lengthLabelRect = _lengthFieldRect = rect;
  132. _updateModeLabelRect.width = EditorStyles.label.CalcSize( _updateModeLabel ).x + LABEL_SPACE;
  133. _updateModeFieldRect.width = UPDATE_MODE_FIELD_WIDTH;
  134. _framerateLabelRect.width = EditorStyles.label.CalcSize( _framerateLabel ).x + LABEL_SPACE;
  135. _framerateFieldRect.width = FRAMERATE_FIELD_WIDTH;
  136. _lengthLabelRect.width = EditorStyles.label.CalcSize( _lengthLabel ).x + LABEL_SPACE;
  137. _lengthFieldRect.width = LENGTH_FIELD_WIDTH;
  138. _fileLabelRect = rect;
  139. _fileLabelRect.width = EditorStyles.label.CalcSize(_fileLabel).x + LABEL_SPACE;
  140. _fileSearchRect = rect;
  141. _fileSearchRect.xMin = _fileLabelRect.xMax;
  142. _fileSearchRect.width = 200;
  143. _fileListPopupRect = rect;
  144. _fileListPopupRect.xMin = _fileSearchRect.xMax;
  145. _fileListPopupRect.width = 200;
  146. _sequenceLabelRect = rect;
  147. _sequenceLabelRect.xMin = _fileListPopupRect.xMax + ELEMENT_SPACE;
  148. _sequenceLabelRect.width = EditorStyles.label.CalcSize( _sequenceLabel ).x + LABEL_SPACE;
  149. _sequencePopupRect = rect;
  150. _sequencePopupRect.xMin = _sequenceLabelRect.xMax;
  151. _sequencePopupRect.width = Mathf.Min( width - _sequenceLabelRect.width, MAX_SEQUENCE_POPUP_WIDTH );
  152. _sequenceAddButtonRect = rect;
  153. _sequenceAddButtonRect.xMin = _sequencePopupRect.xMax + LABEL_SPACE;
  154. _sequenceAddButtonRect.width = 16;
  155. float reminderWidth = width - _sequenceAddButtonRect.xMax;
  156. _addContainerRect = new Rect(0, 3, 22, 22);
  157. _addContainerRect.x = _sequencePopupRect.xMax + LABEL_SPACE;
  158. reminderWidth -= (ELEMENT_SPACE + _addContainerRect.width);
  159. _showAddContainer = reminderWidth >= 0;
  160. _saveEventRect.x = _addContainerRect.x + _addContainerRect.width + LABEL_SPACE + 20;
  161. _saveEventRect.width = 60;
  162. _refreshRect = rect;
  163. _refreshRect.xMin = _saveEventRect.xMax;
  164. _refreshRect.width = 100;
  165. _openInspectorRect.xMin = _openInspectorRect.xMax - 22;
  166. reminderWidth -= 22 + PADDING;
  167. _lengthFieldRect.x = rect.xMax - 22 - PADDING - _lengthFieldRect.width;
  168. _lengthLabelRect.x = _lengthFieldRect.xMin - _lengthLabelRect.width;
  169. reminderWidth -= (ELEMENT_SPACE + _lengthLabelRect.width + _lengthFieldRect.width);
  170. _showLength = reminderWidth >= 0;
  171. _framerateFieldRect.x = _lengthLabelRect.xMin - ELEMENT_SPACE - _framerateFieldRect.width;
  172. _framerateLabelRect.x = _framerateFieldRect.xMin - _framerateLabelRect.width;
  173. reminderWidth -= (_framerateLabelRect.width + _framerateFieldRect.width + ELEMENT_SPACE);
  174. _showFramerate = reminderWidth >= 0;
  175. _updateModeFieldRect.x = _framerateLabelRect.xMin - ELEMENT_SPACE - _updateModeFieldRect.width;
  176. _updateModeLabelRect.x = _updateModeFieldRect.xMin - _updateModeLabelRect.width;
  177. reminderWidth -= (_updateModeLabelRect.width + _updateModeFieldRect.width + ELEMENT_SPACE);
  178. _showUpdadeMode = reminderWidth >= 0;
  179. _numberFieldStyle = new GUIStyle( EditorStyles.numberField );
  180. _numberFieldStyle.alignment = TextAnchor.MiddleCenter;
  181. }
  182. public void OnGUI()
  183. {
  184. FSequence sequence = _sequenceWindow.GetSequenceEditor().Sequence;
  185. if( (_selectedSequenceIndex < 0 && sequence != null) || (_selectedSequenceIndex >= 0 && _sequences[_selectedSequenceIndex] != sequence) )
  186. {
  187. for( int i = 0; i != _sequences.Length; ++i )
  188. {
  189. if( _sequences[i] == sequence )
  190. {
  191. _selectedSequenceIndex = i;
  192. break;
  193. }
  194. }
  195. }
  196. if( Event.current.type == EventType.MouseDown && Event.current.alt && _sequencePopupRect.Contains(Event.current.mousePosition) )
  197. {
  198. Selection.activeObject = sequence;
  199. Event.current.Use();
  200. }
  201. EditorGUI.BeginChangeCheck();
  202. EditorGUI.PrefixLabel(_fileLabelRect, _fileLabel);
  203. searchContent = EditorGUI.TextField(_fileSearchRect, searchContent);
  204. if(EditorGUI.EndChangeCheck())
  205. {
  206. SearchFile(searchContent);
  207. }
  208. EditorGUI.BeginChangeCheck();
  209. int fileIdx = EditorGUI.Popup(_fileListPopupRect, _selectedFileIndex, mSearchFiles.ToArray());
  210. if (EditorGUI.EndChangeCheck())
  211. {
  212. _selectedFileIndex = fileIdx;
  213. string fileName = mSearchFiles[_selectedFileIndex];
  214. ReadFrameEvent(fileName);
  215. }
  216. EditorGUI.BeginChangeCheck();
  217. EditorGUI.PrefixLabel( _sequenceLabelRect, _sequenceLabel );
  218. int newSequenceIndex = EditorGUI.Popup( _sequencePopupRect, _selectedSequenceIndex, _sequenceNames );
  219. if( EditorGUI.EndChangeCheck() )
  220. {
  221. if( newSequenceIndex == _sequenceNames.Length-1 )
  222. {
  223. FSequence newSequence = FSequenceEditorWindow.CreateSequence();
  224. Selection.activeTransform = newSequence.transform;
  225. _sequenceWindow.GetSequenceEditor().OpenSequence( newSequence );
  226. }
  227. else
  228. {
  229. _selectedSequenceIndex = newSequenceIndex;
  230. _sequenceWindow.GetSequenceEditor().OpenSequence( _sequences[_selectedSequenceIndex] );
  231. _sequenceWindow.RemoveNotification();
  232. }
  233. EditorGUIUtility.keyboardControl = 0; // deselect it
  234. EditorGUIUtility.ExitGUI();
  235. }
  236. // if we're in play mode, can't change anything
  237. if( Application.isPlaying )
  238. GUI.enabled = false;
  239. if( sequence == null )
  240. return;
  241. if( _sequenceSO == null || _sequenceSO.targetObject != sequence )
  242. {
  243. _sequenceSO = new SerializedObject( sequence );
  244. _sequenceUpdateMode = _sequenceSO.FindProperty( "_updateMode" );
  245. _sequenceLength = _sequenceSO.FindProperty( "_length" );
  246. }
  247. _sequenceSO.Update();
  248. if( _showUpdadeMode )
  249. {
  250. EditorGUI.PrefixLabel( _updateModeLabelRect, _updateModeLabel );
  251. EditorGUI.PropertyField( _updateModeFieldRect, _sequenceUpdateMode, GUIContent.none );
  252. }
  253. if( _showFramerate )
  254. {
  255. EditorGUI.PrefixLabel( _framerateLabelRect, _framerateLabel );
  256. EditorGUI.BeginChangeCheck();
  257. int newFrameRate = FGUI.FrameRatePopup( _framerateFieldRect, sequence.FrameRate );
  258. if( EditorGUI.EndChangeCheck() )
  259. {
  260. if( newFrameRate == -1 )
  261. {
  262. FChangeFrameRateWindow.Show( new Vector2(_framerateLabelRect.xMin, _framerateLabelRect.yMax), sequence, FSequenceInspector.Rescale );
  263. }
  264. else
  265. {
  266. FSequenceInspector.Rescale( sequence, newFrameRate, true );
  267. }
  268. }
  269. }
  270. if( _showLength )
  271. {
  272. EditorGUI.PrefixLabel( _lengthLabelRect, _lengthLabel );
  273. _sequenceLength.intValue = Mathf.Clamp( EditorGUI.IntField( _lengthFieldRect, _sequenceLength.intValue, _numberFieldStyle ), 1, int.MaxValue );
  274. }
  275. GUIStyle s = new GUIStyle(EditorStyles.miniButton);
  276. s.padding = new RectOffset(1, 1, 1, 1);
  277. if( _showAddContainer )
  278. {
  279. if( FGUI.Button( _addContainerRect, _addContainerLabel ) )
  280. {
  281. AddContainer();
  282. }
  283. }
  284. if (FGUI.Button(_openInspectorRect, _openInspectorLabel))
  285. {
  286. FInspectorWindow.Open();
  287. }
  288. if (FGUI.Button(_saveEventRect, _saveEventLabel))
  289. {
  290. SaveContainer();
  291. }
  292. _sequenceSO.ApplyModifiedProperties();
  293. if (FGUI.Button(_refreshRect, _refreshLabel))
  294. {
  295. Refresh();
  296. }
  297. GUI.enabled = true;
  298. }
  299. private void Refresh()
  300. {
  301. if (_sequences == null) return;
  302. for (int idx = 0; idx < _sequences.Length; idx++)
  303. {
  304. _sequences[idx].ResetDefaultVal();
  305. }
  306. }
  307. private void AddContainer()
  308. {
  309. GenericMenu menu = new GenericMenu();
  310. bool hasDefaultContainers = false;
  311. List<FColorSetting> defaultContainers = FUtility.GetSettings().DefaultContainers;
  312. foreach( FColorSetting colorSetting in defaultContainers )
  313. {
  314. if( string.IsNullOrEmpty(colorSetting._str) )
  315. continue;
  316. menu.AddItem( new GUIContent( colorSetting._str ), false, CreateContainer, colorSetting );
  317. hasDefaultContainers = true;
  318. }
  319. if( !hasDefaultContainers )
  320. {
  321. _sequenceWindow.GetSequenceEditor().CreateContainer( new FColorSetting("Default", FGUI.DefaultContainerColor()) );
  322. return;
  323. }
  324. menu.AddSeparator(null);
  325. menu.AddItem( new GUIContent( "[Default New Container]" ), false, CreateContainer, new FColorSetting("Default", FGUI.DefaultContainerColor()) );
  326. menu.ShowAsContext();
  327. }
  328. private void CreateContainer( object data )
  329. {
  330. _sequenceWindow.GetSequenceEditor().CreateContainer( (FColorSetting)data );
  331. }
  332. private void SaveContainer()
  333. {
  334. _sequenceWindow.GetSequenceEditor().SaveToXml();
  335. }
  336. private void ReadFrameEvent(string fileName)
  337. {
  338. if (mEventFileMapping.ContainsKey(fileName))
  339. {
  340. Debug.LogError("文件 " + fileName + " 已经打开过");
  341. return;
  342. }
  343. string filePath = Constants.XmlConfig + "/Skill/" + fileName + ".xml";
  344. TextAsset ta = AssetDatabase.LoadAssetAtPath(filePath, typeof(TextAsset)) as TextAsset;
  345. if(ta == null)
  346. {
  347. Debug.LogError("加载文件:" + fileName + "失败!!");
  348. return;
  349. }
  350. SecurityParser doc = new SecurityParser();
  351. try
  352. {
  353. doc.LoadXml(ta.text);
  354. }
  355. catch (System.Exception e)
  356. {
  357. DebugHelper.LogError(string.Format("Load Frame Event, exception = {0}", e.Message));
  358. return;
  359. }
  360. SecurityElement root = doc.SelectSingleNode("FrameEvent");
  361. if (root == null || root.Children == null) return;
  362. for (int idx = 0; idx < root.Children.Count; idx++)
  363. {
  364. var buffNode = root.Children[idx] as SecurityElement;
  365. if (buffNode.Tag.CompareTo("buff") != 0) continue;
  366. int endFrame = 0;
  367. int.TryParse(buffNode.Attribute("endFrame"), out endFrame);
  368. string casterName = buffNode.Attribute("caster");
  369. string targetName = buffNode.Attribute("target");
  370. FSequence sequence = FSequence.CreateSequence();
  371. sequence.FrameRate = 30;
  372. sequence.Length = endFrame;
  373. if(!string.IsNullOrEmpty(casterName))
  374. sequence.CasterActor = GameObject.Find(casterName);
  375. if(!string.IsNullOrEmpty(targetName))
  376. sequence.TargetActor = GameObject.Find(targetName);
  377. sequence.CameraGo = Camera.main.gameObject;
  378. FTimeline timeline = FTimeline.Create(sequence.transform);
  379. sequence.Containers[0].Add(timeline);
  380. timeline.LoadFromXml(buffNode);
  381. Selection.activeTransform = sequence.transform;
  382. _sequenceWindow.GetSequenceEditor().OpenSequence(sequence);
  383. if(!mEventFileMapping.ContainsKey(fileName))
  384. {
  385. mEventFileMapping.Add(fileName, sequence);
  386. }
  387. else
  388. {
  389. string newFileName = fileName + "_" + timeline.Gender;
  390. mEventFileMapping.Add(newFileName, sequence);
  391. }
  392. }
  393. }
  394. public void Destroy()
  395. {
  396. foreach(var pair in mEventFileMapping)
  397. {
  398. GameObject.DestroyImmediate(pair.Value.gameObject);
  399. }
  400. mEventFileMapping.Clear();
  401. }
  402. private void SearchFile(string content)
  403. {
  404. mSearchFiles.Clear();
  405. for(int idx =0; idx < mFileNames.Count;idx++)
  406. {
  407. string name = mFileNames[idx];
  408. if(name.StartsWith(content))
  409. {
  410. mSearchFiles.Add(name);
  411. }
  412. }
  413. }
  414. }
  415. }