Boat Attack使用了Universal RP的许多新图形功能,可以用于探索 Universal RP 的使用方式和技巧。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

547 行
18 KiB

using UnityEditor.IMGUI.Controls;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
#if UNITY_2019_3_OR_NEWER
using UnityEngine.LowLevel;
#else
using UnityEngine.Experimental.LowLevel;
#endif
using UnityEngine.Profiling;
namespace Unity.Entities.Editor
{
internal delegate void SystemSelectionCallback(ComponentSystemBase manager, World world);
internal class SystemListView : TreeView
{
private class AverageRecorder
{
private readonly Recorder recorder;
private int frameCount;
private int totalNanoseconds;
private float lastReading;
public AverageRecorder(Recorder recorder)
{
this.recorder = recorder;
}
public void Update()
{
++frameCount;
totalNanoseconds += (int)recorder.elapsedNanoseconds;
}
public float ReadMilliseconds()
{
if (frameCount > 0)
{
lastReading = (totalNanoseconds/1e6f) / frameCount;
frameCount = totalNanoseconds = 0;
}
return lastReading;
}
}
internal readonly Dictionary<int, ComponentSystemBase> managersById = new Dictionary<int, ComponentSystemBase>();
private readonly Dictionary<int, World> worldsById = new Dictionary<int, World>();
private readonly Dictionary<ComponentSystemBase, AverageRecorder> recordersByManager = new Dictionary<ComponentSystemBase, AverageRecorder>();
private readonly Dictionary<int, HideNode> hideNodesById = new Dictionary<int, HideNode>();
private const float kToggleWidth = 22f;
private const float kTimingWidth = 70f;
private const int kAllEntitiesItemId = 0;
private readonly SystemSelectionCallback systemSelectionCallback;
private readonly WorldSelectionGetter getWorldSelection;
private readonly ShowInactiveSystemsGetter getShowInactiveSystems;
private static GUIStyle RightAlignedLabel
{
get
{
if (rightAlignedText == null)
{
rightAlignedText = new GUIStyle(GUI.skin.label)
{
alignment = TextAnchor.MiddleRight
};
}
return rightAlignedText;
}
}
private static GUIStyle rightAlignedText;
internal static MultiColumnHeaderState GetHeaderState()
{
var columns = new[]
{
new MultiColumnHeaderState.Column
{
headerContent = GUIContent.none,
contextMenuText = "Enabled",
headerTextAlignment = TextAlignment.Left,
canSort = false,
width = kToggleWidth,
minWidth = kToggleWidth,
maxWidth = kToggleWidth,
autoResize = false,
allowToggleVisibility = false
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("System Name"),
headerTextAlignment = TextAlignment.Left,
sortingArrowAlignment = TextAlignment.Right,
canSort = true,
sortedAscending = true,
width = 100,
minWidth = 100,
maxWidth = 2000,
autoResize = true,
allowToggleVisibility = false
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("main (ms)"),
headerTextAlignment = TextAlignment.Right,
canSort = false,
width = kTimingWidth,
minWidth = kTimingWidth,
maxWidth = kTimingWidth,
autoResize = false,
allowToggleVisibility = false
}
};
return new MultiColumnHeaderState(columns);
}
private static TreeViewState GetStateForWorld(World world, List<TreeViewState> states, List<string> stateNames)
{
if (world == null)
return new TreeViewState();
var currentWorldName = world.Name;
var stateForCurrentWorld = states.Where((t, i) => stateNames[i] == currentWorldName).FirstOrDefault();
if (stateForCurrentWorld != null)
return stateForCurrentWorld;
stateForCurrentWorld = new TreeViewState();
states.Add(stateForCurrentWorld);
stateNames.Add(currentWorldName);
return stateForCurrentWorld;
}
public static SystemListView CreateList(List<TreeViewState> states, List<string> stateNames, SystemSelectionCallback systemSelectionCallback, WorldSelectionGetter worldSelectionGetter, ShowInactiveSystemsGetter showInactiveSystemsGetter)
{
var state = GetStateForWorld(worldSelectionGetter(), states, stateNames);
var header = new MultiColumnHeader(GetHeaderState());
return new SystemListView(state, header, systemSelectionCallback, worldSelectionGetter, showInactiveSystemsGetter);
}
internal SystemListView(TreeViewState state, MultiColumnHeader header, SystemSelectionCallback systemSelectionCallback, WorldSelectionGetter worldSelectionGetter, ShowInactiveSystemsGetter showInactiveSystemsGetter) : base(state, header)
{
this.getWorldSelection = worldSelectionGetter;
this.systemSelectionCallback = systemSelectionCallback;
this.getShowInactiveSystems = showInactiveSystemsGetter;
columnIndexForTreeFoldouts = 1;
RebuildNodes();
}
private HideNode CreateNodeForManager(int id, ComponentSystemBase system)
{
var active = true;
if (!(system is ComponentSystemGroup))
{
managersById.Add(id, system);
worldsById.Add(id, system.World);
var recorder = Recorder.Get($"{system.World.Name} {system.GetType().FullName}");
recordersByManager.Add(system, new AverageRecorder(recorder));
recorder.enabled = true;
active = false;
}
var name = getWorldSelection() == null ? $"{system.GetType().Name} ({system.World.Name})" : system.GetType().Name;
var item = new TreeViewItem { id = id, displayName = name };
var hideNode = new HideNode(item) { Active = active };
hideNodesById.Add(id, hideNode);
return hideNode;
}
private PlayerLoopSystem lastPlayerLoop;
private class HideNode
{
public readonly TreeViewItem Item;
public bool Active = true;
public List<HideNode> Children;
public HideNode(TreeViewItem item)
{
Item = item;
}
public void AddChild(HideNode child)
{
if (Children == null)
Children = new List<HideNode>();
Children.Add(child);
}
public TreeViewItem BuildList(bool showInactiveSystems)
{
if (showInactiveSystems || Active)
{
Item.children = null;
if (Children != null)
{
Item.children = new List<TreeViewItem>();
foreach (var child in Children)
{
var childItem = child.BuildList(showInactiveSystems);
if (childItem != null)
Item.children.Add(childItem);
}
}
return Item;
}
else
{
return null;
}
}
}
private HideNode rootNode;
private void RebuildNodes()
{
rootNode = null;
Reload();
}
private void AddNodeIgnoreNulls(ref List<HideNode> list, HideNode node)
{
if (node == null)
return;
if (list == null)
list = new List<HideNode>();
list.Add(node);
}
private HideNode BuildNodesForPlayerLoopSystem(PlayerLoopSystem system, ref int currentId)
{
List<HideNode> children = null;
if (system.subSystemList != null)
{
foreach (var subSystem in system.subSystemList)
{
AddNodeIgnoreNulls(ref children, BuildNodesForPlayerLoopSystem(subSystem, ref currentId));
}
}
else
{
var executionDelegate = system.updateDelegate;
ScriptBehaviourUpdateOrder.DummyDelegateWrapper dummy;
if (executionDelegate != null &&
(dummy = executionDelegate.Target as ScriptBehaviourUpdateOrder.DummyDelegateWrapper) != null)
{
var rootSystem = dummy.System;
return BuildNodesForComponentSystem(rootSystem, ref currentId);
}
}
if (children != null || getWorldSelection() == null)
{
var systemNode = new HideNode(new TreeViewItem() {id = currentId++, displayName = system.type?.Name});
systemNode.Children = children;
return systemNode;
}
return null;
}
private HideNode BuildNodesForComponentSystem(ComponentSystemBase manager, ref int currentId)
{
switch (manager)
{
case ComponentSystemGroup group:
List<HideNode> children = null;
if (group.Systems != null)
{
foreach (var child in group.Systems)
{
AddNodeIgnoreNulls(ref children, BuildNodesForComponentSystem(child, ref currentId));
}
}
if (children != null || getWorldSelection() == null || getWorldSelection() == group.World)
{
var groupNode = CreateNodeForManager(currentId++, group);
groupNode.Children = children;
return groupNode;
}
break;
case ComponentSystemBase system:
{
if (getWorldSelection() == null || getWorldSelection() == system.World)
{
return CreateNodeForManager(currentId++, system);
}
}
break;
}
return null;
}
private void BuildNodeTree()
{
managersById.Clear();
worldsById.Clear();
recordersByManager.Clear();
hideNodesById.Clear();
var currentID = kAllEntitiesItemId + 1;
lastPlayerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
rootNode = BuildNodesForPlayerLoopSystem(ScriptBehaviourUpdateOrder.CurrentPlayerLoop, ref currentID)
?? new HideNode(new TreeViewItem {id = currentID, displayName = "Root"});
return;
}
private bool GetDefaultExpandedIds(HideNode parent, List<int> ids)
{
var shouldExpand = managersById.ContainsKey(parent.Item.id);
if (parent.Children != null)
{
foreach (var child in parent.Children)
{
shouldExpand |= GetDefaultExpandedIds(child, ids);
}
if (shouldExpand)
{
ids.Add(parent.Item.id);
}
}
return shouldExpand;
}
protected override TreeViewItem BuildRoot()
{
if (rootNode == null)
{
BuildNodeTree();
var expanded = new List<int>();
GetDefaultExpandedIds(rootNode, expanded);
expanded.Sort();
state.expandedIDs = expanded;
}
var root = rootNode.BuildList(getShowInactiveSystems());
if (!root.hasChildren)
root.children = new List<TreeViewItem>(0);
if (getWorldSelection() != null)
{
root.children.Insert(0, new TreeViewItem(kAllEntitiesItemId, 0, $"All Entities ({getWorldSelection().Name})"));
}
root.depth = -1;
SetupDepthsFromParentsAndChildren(root);
return root;
}
protected override void BeforeRowsGUI()
{
var becameVisible = false;
foreach (var idManagerPair in managersById)
{
var componentSystemBase = idManagerPair.Value;
var hideNode = hideNodesById[idManagerPair.Key];
if (componentSystemBase.LastSystemVersion != 0 && !hideNode.Active)
{
hideNode.Active = true;
becameVisible = true;
}
}
if (becameVisible)
Reload();
base.BeforeRowsGUI();
}
protected override void RowGUI (RowGUIArgs args)
{
if (args.item.depth == -1)
return;
var item = args.item;
var enabled = GUI.enabled;
if (managersById.ContainsKey(item.id))
{
var manager = managersById[item.id];
var componentSystemBase = manager as ComponentSystemBase;
if (componentSystemBase != null)
{
var toggleRect = args.GetCellRect(0);
toggleRect.xMin = toggleRect.xMin + 4f;
componentSystemBase.Enabled = GUI.Toggle(toggleRect, componentSystemBase.Enabled, GUIContent.none);
}
if (componentSystemBase != null)
{
var timingRect = args.GetCellRect(2);
if (componentSystemBase.ShouldRunSystem())
{
var recorder = recordersByManager[manager];
GUI.Label(timingRect, recorder.ReadMilliseconds().ToString("f2"), RightAlignedLabel);
}
else
{
GUI.enabled = false;
GUI.Label(timingRect, "not run", RightAlignedLabel);
GUI.enabled = enabled;
}
}
}
else if (args.item.id == kAllEntitiesItemId)
{
}
else
{
GUI.enabled = false;
}
var indent = GetContentIndent(item);
var nameRect = args.GetCellRect(1);
nameRect.xMin = nameRect.xMin + indent;
GUI.Label(nameRect, item.displayName);
GUI.enabled = enabled;
}
protected override void AfterRowsGUI()
{
base.AfterRowsGUI();
if (Event.current.type == EventType.MouseDown)
{
SetSelection(new List<int>());
}
}
protected override void SelectionChanged(IList<int> selectedIds)
{
if (selectedIds.Count > 0 && managersById.ContainsKey(selectedIds[0]))
{
systemSelectionCallback(managersById[selectedIds[0]], worldsById[selectedIds[0]]);
}
else
{
systemSelectionCallback(null, null);
SetSelection(getWorldSelection() == null ? new List<int>() : new List<int> {kAllEntitiesItemId});
}
}
protected override bool CanMultiSelect(TreeViewItem item)
{
return false;
}
public void TouchSelection()
{
SetSelection(GetSelection(), TreeViewSelectionOptions.FireSelectionChanged);
}
private bool PlayerLoopsMatch(PlayerLoopSystem a, PlayerLoopSystem b)
{
if (a.type != b.type)
return false;
if (a.subSystemList == b.subSystemList)
return true;
if (a.subSystemList == null || b.subSystemList == null)
return false;
if (a.subSystemList.Length != b.subSystemList.Length)
return false;
for (var i = 0; i < a.subSystemList.Length; ++i)
{
if (!PlayerLoopsMatch(a.subSystemList[i], b.subSystemList[i]))
return false;
}
return true;
}
public bool NeedsReload
{
get
{
if (!PlayerLoopsMatch(lastPlayerLoop, ScriptBehaviourUpdateOrder.CurrentPlayerLoop))
return true;
foreach (var world in worldsById.Values)
{
if (!world.IsCreated)
return true;
}
foreach (var manager in managersById.Values)
{
if (manager is ComponentSystemBase system)
{
if (system.World == null || !system.World.Systems.Contains(manager))
return true;
}
}
return false;
}
}
public void ReloadIfNecessary()
{
if (NeedsReload)
RebuildNodes();
}
private int lastTimedFrame;
public void UpdateTimings()
{
if (Time.frameCount == lastTimedFrame)
return;
foreach (var recorder in recordersByManager.Values)
{
recorder.Update();
}
lastTimedFrame = Time.frameCount;
}
public void SetSystemSelection(ComponentSystemBase manager, World world)
{
foreach (var pair in managersById)
{
if (pair.Value == manager)
{
SetSelection(new List<int> {pair.Key});
return;
}
}
SetSelection(new List<int>());
}
}
}