Editor/Inspectors/AttackDataInspector.cs
using System.Linq;
using Editor;
using Sandbox;
using Sandbox.UI;
using ControlSheet = Editor.ControlSheet;
using Label = Editor.Label;
namespace MANIFOLD.BHLib.Editor {
[Inspector(typeof(AttackData))]
public class AttackDataInspector : InspectorWidget {
public class TimelineInfo : Widget {
public TimelineInfo(string name, ITimeline timeline, Widget parent = null) : base(parent) {
var grid = Layout.Grid();
grid.Margin = 4;
grid.VerticalSpacing = 8;
Layout = grid;
grid.AddCell(0, 0, new Label(name));
grid.AddCell(1, 0, new Label(timeline.EventType.Name), alignment: TextFlag.Right);
grid.AddCell(0, 1, new Label($"Event Count: {timeline.Events.Count}"));
grid.AddCell(0, 2, new Label($"Duration: {(timeline.Events.Count > 0 ? timeline.Events[^1].Time : 0).ToString("N2")}"));
}
protected override void OnPaint() {
var rect = LocalRect;
rect.Bottom = Theme.RowHeight;
Paint.SetBrushAndPen(Theme.BaseAlt);
Paint.DrawRect(rect);
}
}
public class RendererInfo : Widget {
public RendererInfo(AttackData.RendererData data, Widget parent = null) : base(parent) {
Layout = Layout.Row();
var prefab = (PrefabScene)data.Prefab;
var renderer = Layout.Add(new SceneRenderingWidget());
renderer.Scene = Scene.CreateEditorScene();
renderer.FixedSize = 80;
using (renderer.Scene.Push()) {
var camera = new GameObject("Camera").AddComponent<CameraComponent>();
camera.BackgroundColor = new Color(0, 0.05f, 0.15f);
camera.WorldPosition = new Vector3(-60, 60, 100);
camera.WorldRotation = Rotation.LookAt((camera.WorldPosition * -1).Normal);
var clone = prefab.Clone();
clone.WorldTransform = Transform.Zero;
}
Layout.AddStretchCell();
var column = Layout.AddColumn();
column.Alignment = TextFlag.RightTop;
column.Add(new Label.Header(prefab.Name) { Alignment = TextFlag.Right });
column.Add(new Label($"Path: {prefab.Source.ResourcePath}") { Alignment = TextFlag.Right });
column.Add(new Label($"Use Count: {data.UseCount}") { Alignment = TextFlag.Right });
}
}
private AttackData target;
private ControlSheet sheet;
private Layout timelineLayout;
private Layout rendererLayout;
public AttackDataInspector(SerializedObject so) : base(so) {
Layout = Layout.Column();
Layout.Margin = 8;
Layout.Spacing = 4;
if (so.Targets.FirstOrDefault() is not AttackData resource) return;
target = resource;
sheet = new ControlSheet();
Layout.Add(sheet);
sheet.AddObject(so, SheetFilter);
Layout.Add(new Label.Header("Timelines"));
timelineLayout = Layout.AddColumn();
timelineLayout.Margin = new Margin(8, 0);
timelineLayout.Spacing = 4;
Layout.Add(new Label.Header("Renderers"));
rendererLayout = Layout.AddColumn();
rendererLayout.Margin = new Margin(8, 0);
rendererLayout.Spacing = 4;
Layout.AddStretchCell();
RebuildTimelines();
RebuildRenderers();
}
private void RebuildTimelines() {
timelineLayout.Clear(true);
var timelines = EditorTypeLibrary
.GetType(target.GetType())
.Properties.Where(x => x.PropertyType.IsAssignableTo(typeof(ITimeline)));
foreach (var prop in timelines) {
var timeline = (ITimeline)prop.GetValue(target);
timelineLayout.Add(new TimelineInfo(prop.Name, timeline, this));
}
}
private void RebuildRenderers() {
rendererLayout.Clear(true);
foreach (var data in target.RenderPoolingData) {
rendererLayout.Add(new RendererInfo(data, this));
}
}
private bool SheetFilter(SerializedProperty prop) {
if (prop.HasAttribute<HideAttribute>()) return false;
if (prop.PropertyType.IsAssignableTo(typeof(ITimeline))) return false;
if (prop.Name == nameof(AttackData.RenderPoolingData)) return false;
return true;
}
}
}