Created
February 3, 2025 04:16
-
-
Save thelebaron/fbce52112bfacda38f943ccd7a6f3af9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
using System.Reflection; | |
using UnityEditor; | |
using UnityEditor.ShortcutManagement; | |
using UnityEngine; | |
using UnityEngine.UIElements; | |
namespace Junk.Entities.Editor | |
{ | |
[InitializeOnLoad] | |
public static partial class CustomEntityEditor | |
{ | |
private static UnityEditor.Editor m_EntityEditor; | |
static CustomEntityEditor() | |
{ | |
// Hook into the Editor lifecycle when the inspector is created | |
UnityEditor.Editor.finishedDefaultHeaderGUI += OnFinishedDefaultHeaderGUI; | |
EditorApplication.update += InitializeFrameShortcut; | |
} | |
// Add these new members to your class | |
private static bool m_IsSubscribedToSceneView; | |
private static KeyCode m_FrameKey = KeyCode.F; | |
private static EventModifiers m_FrameModifiers = EventModifiers.None; | |
private static void InitializeFrameShortcut() | |
{ | |
if (!m_IsSubscribedToSceneView) | |
{ | |
SceneView.duringSceneGui += DuringSceneGui; | |
m_IsSubscribedToSceneView = true; | |
} | |
} | |
private static void DuringSceneGui(SceneView sceneView) | |
{ | |
KeyDown(Event.current); | |
} | |
private static void KeyDown(Event evt) | |
{ | |
// if this check isnt here, any clicked entity will frame automatically. could be useful but would need a checkbox | |
if (evt.keyCode != KeyCode.F) | |
return; | |
var combination = ShortcutManager.instance.GetShortcutBinding("Main Menu/Edit/Frame Selected in Window under Cursor") | |
.keyCombinationSequence.ToList(); | |
if (combination.Count == 1) | |
{ | |
EditorComponentManager.FrameSelectedEntity(m_EntityEditor); | |
// Prevent default framing behavior | |
//Event.current.Use(); | |
} | |
} | |
// Add this to your cleanup if you implement proper disposal | |
// [InitializeOnLoad] classes should generally remain subscribed though | |
private static void OnDestroy() | |
{ | |
SceneView.duringSceneGui -= DuringSceneGui; | |
EditorApplication.update -= InitializeFrameShortcut; | |
} | |
private static void OnFinishedDefaultHeaderGUI(UnityEditor.Editor editor) | |
{ | |
m_EntityEditor = editor; | |
// Check if the target editor is an EntityEditor | |
if (editor.GetType().Name != "EntityEditor") | |
return; | |
// Try to retrieve the root visual element | |
var root = GetRootVisualElement(editor); | |
// Check if the container already exists | |
if (root.Q<VisualElement>("JunkEntityInspectorHeaderContainer") == null) | |
{ | |
var container = new VisualElement | |
{ | |
name = "JunkEntityInspectorHeaderContainer", | |
style = | |
{ | |
flexDirection = FlexDirection.Row, | |
marginBottom = 5, | |
marginLeft = 5, | |
marginRight = 5, | |
paddingLeft = 0, | |
paddingRight = 0 | |
} | |
}; | |
// Schedule the addition of the container | |
root.schedule.Execute(() => | |
{ | |
// Double-check if the container still doesn't exist | |
if (root.Q<VisualElement>("JunkEntityInspectorHeaderContainer") == null) | |
{ | |
root.Insert(0, container); | |
} | |
}); | |
TryAddFoldoutElements(root, container, 0); | |
TryAddDeleteElements(root, container, 1); | |
} | |
} | |
internal static VisualElement GetRootVisualElement(UnityEditor.Editor editor) | |
{ | |
// Access the private `m_Root` field from the EntityEditor | |
var rootField = editor.GetType().GetField("m_Root", BindingFlags.NonPublic | BindingFlags.Instance); | |
return rootField?.GetValue(editor) as VisualElement; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
using Unity; | |
using Unity.Entities; | |
using Unity.Mathematics; | |
using Unity.Transforms; | |
using UnityEditor; | |
using UnityEngine.UIElements; | |
namespace Junk.Entities.Editor | |
{ | |
internal static class EditorComponentManager | |
{ | |
public static void FrameSelectedEntity(UnityEditor.Editor entityEditor) | |
{ | |
if (entityEditor == null) | |
return; | |
var root = CustomEntityEditor.GetRootVisualElement(entityEditor); | |
var componentsTab = root?.Query<VisualElement>("ComponentsTab").First(); | |
if (componentsTab == null) | |
return; | |
var localTransformData = LocalTransform.Identity; | |
var isLocalToWorld = false; | |
var localToWorldData = new LocalToWorld(); | |
var localTransform = componentsTab.Query("LocalTransform").First(); | |
if (localTransform != null) | |
{ | |
//Debug.Log("Framing selected entity"); | |
var vector3 = localTransform.Query("Position").First(); | |
var data = vector3 as Vector3Field; | |
localTransformData.Position = data.value; | |
} | |
var localToWorld = componentsTab.Query("LocalToWorld").First(); | |
var haveTransform = localTransform != null || localToWorld != null; | |
if (localToWorld != null) | |
{ | |
//Debug.Log("Found localToWorld" + localToWorld.GetType()); | |
// get all children of localToWorld | |
var children = localToWorld.Children(); | |
//var child = localToWorld.ElementAt(1).ElementAt(1).ElementAt(1).ElementAt(1); | |
//Unity.Debug.Log(children.Count()); | |
// get child | |
var first = children.First(); | |
var second = first.Children().First(); // bindableelement | |
// Get all Vector4Fields | |
var floatFields = second.Children().ToList().Select(x => x.Q<Vector4Field>()).ToList(); | |
//Debug.Log("Found " + floatFields.Count + " Vector4Fields"); | |
//Debug.Log($"floatFields {floatFields.Count}"); | |
localToWorldData = new LocalToWorld{Value = new float4x4 | |
{ | |
c0 = floatFields[0].value, | |
c1 = floatFields[1].value, | |
c2 = floatFields[2].value, | |
c3 = floatFields[3].value | |
}}; | |
//Debug.Log($"localToWorld {localToWorldData.Position}"); | |
isLocalToWorld = true; | |
} | |
if (haveTransform) | |
{ | |
var position = localTransformData.Position; | |
//if (position.Equals(Vector3.zero)) | |
{ | |
if (localToWorld != null) | |
{ | |
//Debug.Log($" localToWorldData {localToWorldData.Position}"); | |
position = localToWorldData.Position; | |
} | |
} | |
// get scene view camera | |
var sceneView = SceneView.lastActiveSceneView; | |
if (sceneView != null) | |
{ | |
//Frame selected in scene view | |
sceneView.pivot = position; | |
sceneView.Repaint(); | |
} | |
} | |
} | |
public static void DeleteEntity(VisualElement root, bool b) | |
{ | |
var entityNameField = root.Q<TextField>("Entity Name"); | |
var child = entityNameField.Children().First(); | |
var textElement = child.Children().First(); | |
var entityTextElement = textElement as TextElement; | |
var entityNameText = entityNameField.text; | |
// name is parsed as: Entity {105:1}, we are only interested in the index and version of the entity which is {index:version} | |
Entity entity = new Entity {Index = int.Parse(entityNameText.Split('{')[1].Split(':')[0]), Version = int.Parse(entityNameText.Split(':')[1].Split('}')[0])}; | |
var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; | |
if (entityManager.Exists(entity)) | |
{ | |
entityManager.DestroyEntity(entity); | |
} | |
Debug.Log($"Deleted entity: {entityNameText}, {entity.Index } {entity.Version}"); | |
Selection.activeObject = null; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Unity.Entities.Editor; | |
using UnityEngine; | |
using UnityEngine.UIElements; | |
namespace Junk.Entities.Editor | |
{ | |
public static partial class CustomEntityEditor | |
{ | |
private static void TryAddFoldoutElements(VisualElement root, VisualElement containerElement, int index) | |
{ | |
if (containerElement != null && !IsCollapseButtonAdded(containerElement)) | |
{ | |
AddFoldoutButtons(root, containerElement, index); | |
} | |
} | |
private static bool IsCollapseButtonAdded(VisualElement containerElement) | |
{ | |
// Check if the button already exists to prevent duplication | |
return containerElement.Q<Button>("CollapseExpandContainer") != null; | |
} | |
private static void AddFoldoutButtons(VisualElement root, VisualElement containerElement, int index) | |
{ | |
// Schedule the button addition to prevent hierarchy modification during layout calculation | |
containerElement.schedule.Execute(() => | |
{ | |
if (!IsCollapseButtonAdded(containerElement)) | |
{ | |
var subContainer = new VisualElement | |
{ | |
name = "CollapseExpandContainer", | |
style = | |
{ | |
//position = Position.Absolute, | |
//top = 0, | |
//right = 0, | |
paddingTop = 0, | |
paddingBottom = 0, | |
paddingLeft = 0, | |
paddingRight = 0, | |
flexDirection = FlexDirection.Row, | |
} | |
}; | |
var expand = new Button(() => { ExpandComponentsTabFoldout(root, true); }) | |
{ | |
name = "Expand", | |
text = "Expand", | |
tooltip = "Expand all components", | |
style = | |
{ | |
paddingTop = 4, | |
paddingBottom = 4, | |
paddingLeft = 8, | |
paddingRight = 8, | |
backgroundColor = new Color(0.35f, 0.35f, 0.35f, 0.8f), // Modern green | |
color = Color.white, | |
borderTopLeftRadius = 0, | |
borderTopRightRadius = 0, | |
borderBottomLeftRadius = 6, | |
borderBottomRightRadius = 6, | |
whiteSpace = WhiteSpace.NoWrap, | |
width = Length.Auto(), | |
flexShrink = 0, | |
marginLeft = 0, | |
marginRight = 0 | |
} | |
}; | |
var collapse = new Button(() => { ExpandComponentsTabFoldout(root, false); }) | |
{ | |
name = "Collapse", | |
text = "Collapse", | |
tooltip = "Collapse all components", | |
style = | |
{ | |
paddingTop = 4, | |
paddingBottom = 4, | |
paddingLeft = 8, | |
paddingRight = 8, | |
backgroundColor = new Color(0.35f, 0.35f, 0.35f, 0.8f), | |
color = Color.white, | |
borderTopLeftRadius = 0, | |
borderTopRightRadius = 0, | |
borderBottomLeftRadius = 6, | |
borderBottomRightRadius = 6, | |
whiteSpace = WhiteSpace.NoWrap, | |
width = Length.Auto(), | |
flexShrink = 0, | |
marginLeft = 0, | |
marginRight = 0 | |
} | |
}; | |
// Add hover effects | |
expand.RegisterCallback<MouseEnterEvent>(_ => expand.style.backgroundColor = new Color(0.20f, 0.72f, 0.42f)); | |
expand.RegisterCallback<MouseLeaveEvent>(_ => expand.style.backgroundColor = new Color(0.35f, 0.35f, 0.35f, 0.8f)); | |
collapse.RegisterCallback<MouseEnterEvent>(_ => collapse.style.backgroundColor = new Color(0.96f, 0.41f, 0.37f)); | |
collapse.RegisterCallback<MouseLeaveEvent>(_ => collapse.style.backgroundColor = new Color(0.35f, 0.35f, 0.35f, 0.8f)); | |
subContainer.Add(expand); | |
subContainer.Add(collapse); | |
containerElement.Insert(index, subContainer); | |
} | |
}); | |
} | |
private static void ExpandComponentsTabFoldout(VisualElement root, bool value) | |
{ | |
var componentsTab = root.Query<VisualElement>("ComponentsTab").First(); | |
if (componentsTab != null) | |
{ | |
// get all children and log their count | |
var allComponentsTabs = root.Query<ComponentElementBase>().ToList(); | |
foreach (var component in allComponentsTabs) | |
{ | |
var foldout = component.Query<Foldout>().First(); // Assumes one foldout per component | |
if (foldout != null) | |
{ | |
foldout.value = value; | |
} | |
} | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Unity.Entities.Editor; | |
using UnityEngine; | |
using UnityEngine.UIElements; | |
namespace Junk.Entities.Editor | |
{ | |
public static partial class CustomEntityEditor | |
{ | |
private static void TryAddDeleteElements(VisualElement root, VisualElement container, int index) | |
{ | |
if (container != null && !IsDeleteButtonAdded(container)) | |
{ | |
AddDeleteButtons(root, container, index); | |
} | |
} | |
private static bool IsDeleteButtonAdded(VisualElement container) | |
{ | |
// Check if the button already exists to prevent duplication | |
return container.Q<Button>("DeleteEntity") != null; | |
} | |
private static void AddDeleteButtons(VisualElement root, VisualElement container, int index) | |
{ | |
// Schedule the button addition to prevent hierarchy modification during layout calculation | |
container.schedule.Execute(() => | |
{ | |
if (!IsDeleteButtonAdded(container)) | |
{ | |
var buttonContainer = new VisualElement | |
{ | |
style = | |
{ | |
flexDirection = FlexDirection.Row, | |
marginBottom = 0, | |
marginLeft = 0, | |
marginRight = 0, | |
paddingLeft = 0, | |
paddingRight = 0 | |
} | |
}; | |
var deleteEntityButton = new Button(() => { EditorComponentManager.DeleteEntity(root, false); }) | |
{ | |
name = "DeleteEntity", | |
text = "Delete Entity", | |
tooltip = "Destroy the entity", | |
style = | |
{ | |
paddingTop = 4, | |
paddingBottom = 4, | |
paddingLeft = 8, | |
paddingRight = 8, | |
backgroundColor = new Color(0.35f, 0.35f, 0.35f, 0.8f), | |
color = Color.white, | |
borderTopLeftRadius = 0, | |
borderTopRightRadius = 0, | |
borderBottomLeftRadius = 6, | |
borderBottomRightRadius = 6, | |
whiteSpace = WhiteSpace.NoWrap, | |
width = Length.Auto(), | |
flexShrink = 0, | |
marginLeft = 0, | |
marginRight = 0 | |
} | |
}; | |
// Add hover effects | |
deleteEntityButton.RegisterCallback<MouseEnterEvent>(_ => deleteEntityButton.style.backgroundColor = new Color(0.96f, 0.41f, 0.37f)); | |
deleteEntityButton.RegisterCallback<MouseLeaveEvent>(_ => deleteEntityButton.style.backgroundColor = new Color(0.35f, 0.35f, 0.35f, 0.8f)); | |
buttonContainer.Add(deleteEntityButton); | |
container.Insert(index, buttonContainer); | |
} | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment