| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 | #if UNITY_2019_4_OR_NEWERusing System;using System.Collections.Generic;using UnityEditor;using UnityEngine;using UnityEngine.UIElements;using UnityEditor.UIElements;using UnityEditor.Networking.PlayerConnection;using UnityEngine.Networking.PlayerConnection;namespace YooAsset.Editor{	public class AssetBundleDebuggerWindow : EditorWindow	{		[MenuItem("YooAsset/AssetBundle Debugger", false, 104)]		public static void OpenWindow()		{			AssetBundleDebuggerWindow wnd = GetWindow<AssetBundleDebuggerWindow>("资源包调试工具", true, WindowsDefine.DockedWindowTypes);			wnd.minSize = new Vector2(800, 600);		}		/// <summary>		/// 视图模式		/// </summary>		private enum EViewMode		{			/// <summary>			/// 内存视图			/// </summary>			MemoryView,			/// <summary>			/// 资源对象视图			/// </summary>			AssetView,			/// <summary>			/// 资源包视图			/// </summary>			BundleView,		}		private readonly Dictionary<int, RemotePlayerSession> _playerSessions = new Dictionary<int, RemotePlayerSession>();		private Label _playerName;		private ToolbarMenu _viewModeMenu;		private SliderInt _frameSlider;		private DebuggerAssetListViewer _assetListViewer;		private DebuggerBundleListViewer _bundleListViewer;		private EViewMode _viewMode;		private string _searchKeyWord;		private DebugReport _currentReport;		private RemotePlayerSession _currentPlayerSession;		private int _rangeIndex = 0;		public void CreateGUI()		{			try			{				VisualElement root = rootVisualElement;				// 加载布局文件				var visualAsset = UxmlLoader.LoadWindowUXML<AssetBundleDebuggerWindow>();				if (visualAsset == null)					return;				visualAsset.CloneTree(root);				// 采样按钮				var sampleBtn = root.Q<Button>("SampleButton");				sampleBtn.clicked += SampleBtn_onClick;				// 导出按钮				var exportBtn = root.Q<Button>("ExportButton");				exportBtn.clicked += ExportBtn_clicked;				// 用户列表菜单				_playerName = root.Q<Label>("PlayerName");				_playerName.text = "Editor player";				// 视口模式菜单				_viewModeMenu = root.Q<ToolbarMenu>("ViewModeMenu");				_viewModeMenu.menu.AppendAction(EViewMode.AssetView.ToString(), OnViewModeMenuChange, OnViewModeMenuStatusUpdate, EViewMode.AssetView);				_viewModeMenu.menu.AppendAction(EViewMode.BundleView.ToString(), OnViewModeMenuChange, OnViewModeMenuStatusUpdate, EViewMode.BundleView);				_viewModeMenu.text = EViewMode.AssetView.ToString();				// 搜索栏				var searchField = root.Q<ToolbarSearchField>("SearchField");				searchField.RegisterValueChangedCallback(OnSearchKeyWordChange);				// 帧数相关				{					_frameSlider = root.Q<SliderInt>("FrameSlider");					_frameSlider.label = "Frame:";					_frameSlider.highValue = 0;					_frameSlider.lowValue = 0;					_frameSlider.value = 0;					_frameSlider.RegisterValueChangedCallback(evt =>					{						OnFrameSliderChange(evt.newValue);					});					var frameLast = root.Q<ToolbarButton>("FrameLast");					frameLast.clicked += OnFrameLast_clicked;					var frameNext = root.Q<ToolbarButton>("FrameNext");					frameNext.clicked += OnFrameNext_clicked;					var frameClear = root.Q<ToolbarButton>("FrameClear");					frameClear.clicked += OnFrameClear_clicked;				}				// 加载视图				_assetListViewer = new DebuggerAssetListViewer();				_assetListViewer.InitViewer();				// 加载视图				_bundleListViewer = new DebuggerBundleListViewer();				_bundleListViewer.InitViewer();				// 显示视图				_viewMode = EViewMode.AssetView;				_assetListViewer.AttachParent(root);				// 远程调试				EditorConnection.instance.Initialize();				EditorConnection.instance.RegisterConnection(OnHandleConnectionEvent);				EditorConnection.instance.RegisterDisconnection(OnHandleDisconnectionEvent);				EditorConnection.instance.Register(RemoteDebuggerDefine.kMsgSendPlayerToEditor, OnHandlePlayerMessage);				RemoteDebuggerInRuntime.EditorHandleDebugReportCallback = OnHandleDebugReport;			}			catch (Exception e)			{				Debug.LogError(e.ToString());			}		}		public void OnDestroy()		{			// 远程调试			EditorConnection.instance.UnregisterConnection(OnHandleConnectionEvent);			EditorConnection.instance.UnregisterDisconnection(OnHandleDisconnectionEvent);			EditorConnection.instance.Unregister(RemoteDebuggerDefine.kMsgSendPlayerToEditor, OnHandlePlayerMessage);			_playerSessions.Clear();		}		private void OnHandleConnectionEvent(int playerId)		{			Debug.Log($"Game player connection : {playerId}");			_playerName.text = $"Connected player : {playerId}";		}		private void OnHandleDisconnectionEvent(int playerId)		{			Debug.Log($"Game player disconnection : {playerId}");			_playerName.text = $"Disconneced player : {playerId}";		}		private void OnHandlePlayerMessage(MessageEventArgs args)		{			var debugReport = DebugReport.Deserialize(args.data);			OnHandleDebugReport(args.playerId, debugReport);		}		private void OnHandleDebugReport(int playerId, DebugReport debugReport)		{			Debug.Log($"Handle player {playerId} debug report !");			_currentPlayerSession = GetOrCreatePlayerSession(playerId);			_currentPlayerSession.AddDebugReport(debugReport);			_frameSlider.highValue = _currentPlayerSession.MaxRangeValue;			_frameSlider.value = _currentPlayerSession.MaxRangeValue;			UpdateFrameView(_currentPlayerSession);		}		private void OnFrameSliderChange(int sliderValue)		{			if (_currentPlayerSession != null)			{				_rangeIndex = _currentPlayerSession.ClampRangeIndex(sliderValue); ;				UpdateFrameView(_currentPlayerSession, _rangeIndex);			}		}		private void OnFrameLast_clicked()		{			if (_currentPlayerSession != null)			{				_rangeIndex = _currentPlayerSession.ClampRangeIndex(_rangeIndex - 1);				_frameSlider.value = _rangeIndex;				UpdateFrameView(_currentPlayerSession, _rangeIndex);			}		}		private void OnFrameNext_clicked()		{			if (_currentPlayerSession != null)			{				_rangeIndex = _currentPlayerSession.ClampRangeIndex(_rangeIndex + 1);				_frameSlider.value = _rangeIndex;				UpdateFrameView(_currentPlayerSession, _rangeIndex);			}		}		private void OnFrameClear_clicked()		{			if (_currentPlayerSession != null)			{				_frameSlider.label = $"Frame:";				_frameSlider.value = 0;				_frameSlider.lowValue = 0;				_frameSlider.highValue = 0;				_currentPlayerSession.ClearDebugReport();				_assetListViewer.ClearView();				_bundleListViewer.ClearView();			}		}		private RemotePlayerSession GetOrCreatePlayerSession(int playerId)		{			if (_playerSessions.TryGetValue(playerId, out RemotePlayerSession session))			{				return session;			}			else			{				RemotePlayerSession newSession = new RemotePlayerSession(playerId);				_playerSessions.Add(playerId, newSession);				return newSession;			}		}		private void UpdateFrameView(RemotePlayerSession playerSession)		{			if (playerSession != null)			{				UpdateFrameView(playerSession, playerSession.MaxRangeValue);			}		}		private void UpdateFrameView(RemotePlayerSession playerSession, int rangeIndex)		{			if (playerSession == null)				return;			var debugReport = playerSession.GetDebugReport(rangeIndex);			if (debugReport != null)			{				_currentReport = debugReport;				_frameSlider.label = $"Frame: {debugReport.FrameCount}";				_assetListViewer.FillViewData(debugReport, _searchKeyWord);				_bundleListViewer.FillViewData(debugReport, _searchKeyWord);			}		}		private void SampleBtn_onClick()		{			// 发送采集数据的命令			RemoteCommand command = new RemoteCommand();			command.CommandType = (int)ERemoteCommand.SampleOnce;			command.CommandParam = string.Empty;			byte[] data = RemoteCommand.Serialize(command);			EditorConnection.instance.Send(RemoteDebuggerDefine.kMsgSendEditorToPlayer, data);			RemoteDebuggerInRuntime.EditorRequestDebugReport();		}		private void ExportBtn_clicked()		{			if (_currentReport == null)			{				Debug.LogWarning("Debug report is null.");				return;			}			string resultPath = EditorTools.OpenFolderPanel("Export JSON", "Assets/");			if (resultPath != null)			{				// 注意:排序保证生成配置的稳定性				foreach (var packageData in _currentReport.PackageDatas)				{					packageData.ProviderInfos.Sort();					foreach (var providerInfo in packageData.ProviderInfos)					{						providerInfo.DependBundleInfos.Sort();					}				}				string filePath = $"{resultPath}/{nameof(DebugReport)}_{_currentReport.FrameCount}.json";				string fileContent = JsonUtility.ToJson(_currentReport, true);				FileUtility.WriteAllText(filePath, fileContent);			}		}		private void OnSearchKeyWordChange(ChangeEvent<string> e)		{			_searchKeyWord = e.newValue;			if (_currentReport != null)			{				_assetListViewer.FillViewData(_currentReport, _searchKeyWord);				_bundleListViewer.FillViewData(_currentReport, _searchKeyWord);			}		}		private void OnViewModeMenuChange(DropdownMenuAction action)		{			var viewMode = (EViewMode)action.userData;			if (_viewMode != viewMode)			{				_viewMode = viewMode;				VisualElement root = this.rootVisualElement;				_viewModeMenu.text = viewMode.ToString();				if (viewMode == EViewMode.AssetView)				{					_assetListViewer.AttachParent(root);					_bundleListViewer.DetachParent();				}				else if (viewMode == EViewMode.BundleView)				{					_assetListViewer.DetachParent();					_bundleListViewer.AttachParent(root);				}				else				{					throw new NotImplementedException(viewMode.ToString());				}			}		}		private DropdownMenuAction.Status OnViewModeMenuStatusUpdate(DropdownMenuAction action)		{			var viewMode = (EViewMode)action.userData;			if (_viewMode == viewMode)				return DropdownMenuAction.Status.Checked;			else				return DropdownMenuAction.Status.Normal;		}	}}#endif
 |