Show Buttons in entity editor

- ScriptEngine: Added HasCustomAttribute- extension method
- ScriptEngine: Added Application class
This commit is contained in:
Simon Lübeß
2023-12-12 13:38:29 +01:00
parent 13cb043cf4
commit e69e1b5526
12 changed files with 253 additions and 42 deletions
+6
View File
@@ -110,6 +110,8 @@ namespace GlitchyEditor
{ {
Application.Get().Window.IsVSync = true; Application.Get().Window.IsVSync = true;
ScriptEngine.ApplicationInfo.IsEditor = true;
_contentManager = contentManager; _contentManager = contentManager;
InitGraphics(); InitGraphics();
@@ -871,6 +873,8 @@ namespace GlitchyEditor
using (Scene runtimeScene = new Scene()) using (Scene runtimeScene = new Scene())
{ {
ScriptEngine.ApplicationInfo.IsInPlayMode = true;
_editorScene.CopyTo(runtimeScene, true); _editorScene.CopyTo(runtimeScene, true);
SetActiveScene(runtimeScene, startRuntime: true, startSimulation: true); SetActiveScene(runtimeScene, startRuntime: true, startSimulation: true);
@@ -951,6 +955,8 @@ namespace GlitchyEditor
/// Stops the simulation or game and returns to edit mode. /// Stops the simulation or game and returns to edit mode.
private void OnSceneStop() private void OnSceneStop()
{ {
ScriptEngine.ApplicationInfo.IsInEditMode = true;
SetActiveScene(_editorScene, startRuntime: true, startSimulation: false); SetActiveScene(_editorScene, startRuntime: true, startSimulation: false);
// TODO: _editorScene.DeserializeScripts(scriptData); // TODO: _editorScene.DeserializeScripts(scriptData);
@@ -113,6 +113,68 @@ static class ScriptEngine
internal static MonoClass* s_RunInEditModeAttribute; internal static MonoClass* s_RunInEditModeAttribute;
} }
public class ApplicationData
{
private bool _isEditor;
private bool _isPlayer;
private bool _isInEditMode;
private bool _isInPlayMode;
public bool IsEditor
{
get => _isEditor;
set
{
_isEditor = value;
if (_isEditor)
_isPlayer = false;
}
}
public bool IsPlayer
{
get => _isPlayer;
set
{
_isPlayer = value;
if (_isPlayer)
_isEditor = false;
}
}
public bool IsInEditMode
{
get => _isInEditMode;
set
{
_isInEditMode = value;
if (_isInEditMode)
_isInPlayMode = false;
}
}
public bool IsInPlayMode
{
get => _isInPlayMode;
set
{
_isInPlayMode = value;
if (_isInPlayMode)
_isInEditMode = false;
}
}
}
private static ApplicationData _applicationData = new ApplicationData() ~ delete _;
/// Contains information about the application context
public static ApplicationData ApplicationInfo => _applicationData;
public static void Init() public static void Init()
{ {
InitMono(); InitMono();
+23 -1
View File
@@ -475,9 +475,31 @@ static class ScriptGlue
id = UUID.Create(); id = UUID.Create();
} }
#region Editor Stuff #region Application
[RegisterCall("ScriptGlue::Application_IsEditor")]
static bool Application_IsEditor()
{
return ScriptEngine.ApplicationInfo.IsEditor;
}
[RegisterCall("ScriptGlue::Application_IsPlayer")]
static bool Application_IsPlayer()
{
return ScriptEngine.ApplicationInfo.IsPlayer;
}
[RegisterCall("ScriptGlue::Application_IsInEditMode")]
static bool Application_IsInEditMode()
{
return ScriptEngine.ApplicationInfo.IsInEditMode;
}
[RegisterCall("ScriptGlue::Application_IsInPlayMode")]
static bool Application_IsInPlayMode()
{
return ScriptEngine.ApplicationInfo.IsInPlayMode;
}
#endregion #endregion
-8
View File
@@ -202,14 +202,6 @@ namespace GlitchyEngine.World
} }
} }
public void Start(bool simulation, bool runtime)
{
if (simulation)
StartSimulation();
}
public void StartRuntime() public void StartRuntime()
{ {
ScriptEngine.StartRuntime(this); ScriptEngine.StartRuntime(this);
+28 -6
View File
@@ -1,15 +1,37 @@
namespace GlitchyEngine.Core; namespace GlitchyEngine.Core;
public class Application /// <summary>
/// Contains information about the application runtime and methods to control it.
/// </summary>
public static class Application
{ {
/// <summary> /// <summary>
/// Returns true when the script is running in edit mode. /// Returns <see langword="true"/> when the application is running in the editor (any mode e.g. edit mode or play mode).
/// </summary> /// </summary>
/// <seealso cref="IsPlaying"/> /// <seealso cref="IsPlayer"/>
public bool IsEditor = false; /// <seealso cref="IsInEditMode"/>
/// <seealso cref="IsInPlayMode"/>
public static bool IsEditor => ScriptGlue.Application_IsEditor();
/// <summary> /// <summary>
/// Returns true when the script is running in play mode or in the player. /// Returns <see langword="true"/> when the application is running in the dedicated player.
/// </summary> /// </summary>
/// <seealso cref="IsEditor"/> /// <seealso cref="IsEditor"/>
public bool IsPlaying = false; public static bool IsPlayer => ScriptGlue.Application_IsPlayer();
/// <summary>
/// Returns <see langword="true"/> when the application is running in the editor and the editor is in edit mode.<br/>
/// If <see cref="IsEditor"/> is <see langword="false"/> (i.e. the application is not running in the editor), <see cref="IsInEditMode"/> will always be <see langword="false"/>.
/// </summary>
/// <seealso cref="IsEditor"/>
/// <seealso cref="IsInPlayMode"/>
public static bool IsInEditMode => ScriptGlue.Application_IsInEditMode();
/// <summary>
/// Returns <see langword="true"/> when the application is running in the editor (<see cref="IsEditor"/> = <see langword="true"/>) and the editor is in play mode. Or when the application in running in the dedicated player (<see cref="IsPlayer"/> = <see langword="true"/>)<br/>
/// </summary>
/// <seealso cref="IsEditor"/>
/// <seealso cref="IsPlayer"/>
/// <seealso cref="IsInEditMode"/>
public static bool IsInPlayMode => ScriptGlue.Application_IsInPlayMode();
} }
-2
View File
@@ -1,5 +1,3 @@
using System;
namespace GlitchyEngine.Core; namespace GlitchyEngine.Core;
public abstract class EngineObject public abstract class EngineObject
+38 -10
View File
@@ -24,11 +24,16 @@ internal class EntityEditor
public static bool ShowFieldInEditor(FieldInfo fieldInfo) public static bool ShowFieldInEditor(FieldInfo fieldInfo)
{ {
if (fieldInfo.IsPublic) if (fieldInfo.IsPublic)
{
// Public fields are visible by default (No HideInEditorAttribute)
if (fieldInfo.HasCustomAttribute<HideInEditorAttribute>())
return false;
return true; return true;
}
var showInEditorAttribute = fieldInfo.GetCustomAttribute<ShowInEditorAttribute>(); // Private, protected and internal fields are hidden by default (No ShowInEditorAttribute)
if (fieldInfo.HasCustomAttribute<ShowInEditorAttribute>())
if (showInEditorAttribute != null)
return true; return true;
return false; return false;
@@ -357,13 +362,9 @@ internal class EntityEditor
public static void ShowEditor(Type type, object reference) public static void ShowEditor(Type type, object reference)
{ {
T GetValue<T>(FieldInfo fieldInfo)
{
return default;
}
int i = 0; int i = 0;
// Iterate all fields
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{ {
i++; i++;
@@ -371,8 +372,6 @@ internal class EntityEditor
if (ShowFieldInEditor(field)) if (ShowFieldInEditor(field))
{ {
//Log.Info(field.Name);
object value = field.GetValue(reference); object value = field.GetValue(reference);
IEnumerable<Attribute> attributes = field.GetCustomAttributes(); IEnumerable<Attribute> attributes = field.GetCustomAttributes();
@@ -388,6 +387,35 @@ internal class EntityEditor
ImGui.PopID(); ImGui.PopID();
} }
// Iterate all methods
foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
var showButton = method.GetCustomAttribute<ShowButtonAttribute>();
if (showButton == null)
continue;
if (Application.IsInEditMode && !showButton.Visibility.HasFlag(ButtonVisibility.InEditMode))
continue;
if (Application.IsInPlayMode && !showButton.Visibility.HasFlag(ButtonVisibility.InPlayMode))
continue;
i++;
ImGui.PushID(i);
if (method.GetParameters().Length > 0)
{
Log.Error($"Method {method.Name} cannot be executed from editor, because it expects arguments.");
}
else if (ImGui.Button(showButton.ButtonText))
{
method.Invoke(reference, null);
}
ImGui.PopID();
}
} }
struct ListPayload struct ListPayload
@@ -0,0 +1,11 @@
using System;
namespace GlitchyEngine.Editor;
/// <summary>
/// Specifies, that the field should not be visible in the editor.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public sealed class HideInEditorAttribute : Attribute
{
}
+42
View File
@@ -0,0 +1,42 @@
using System;
namespace GlitchyEngine.Editor;
public enum ButtonVisibility
{
/// <summary>
/// The button will be visible in edit mode.
/// </summary>
InEditMode = 1,
/// <summary>
/// The button will be visible in play mode.
/// </summary>
InPlayMode = 2,
/// <summary>
/// The button will always be visible.
/// </summary>
Always = InEditMode | InPlayMode
}
/// <summary>
/// Specifies that a button will be shown in the editor that, when clicked, executes the method this attribute is attached to.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class ShowButtonAttribute : Attribute
{
/// <summary>
/// The text on the button.
/// </summary>
public string ButtonText { get; private set; }
/// <summary>
/// Determines whether the button is visible in edit and/or play mode.
/// </summary>
public ButtonVisibility Visibility { get; set; } = ButtonVisibility.Always;
public ShowButtonAttribute(string buttonText)
{
ButtonText = buttonText;
}
}
+8 -3
View File
@@ -7,11 +7,16 @@ namespace GlitchyEngine.Editor;
* - this attribute also means that the Field is being serialized * - this attribute also means that the Field is being serialized
* - Editor-Namespace wont be available for distribution builds of the game * - Editor-Namespace wont be available for distribution builds of the game
*/ */
/// <summary>
/// Specifies that the field should be visible in the editor, regardless of it's code visibility (private, protected, etc...)
/// If this attribute is specified, the field will also be serialized.
/// </summary>
[AttributeUsage(AttributeTargets.Field)] [AttributeUsage(AttributeTargets.Field)]
public sealed class ShowInEditorAttribute : Attribute public sealed class ShowInEditorAttribute : Attribute
{ {
/// <summary>
/// The label with which the field will be shown in the editor.
/// If not specified, the fields name will be used.
/// </summary>
public string DisplayName { get; set; } = null; public string DisplayName { get; set; } = null;
public ShowInEditorAttribute()
{}
} }
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace GlitchyEngine.Extensions;
public static class FieldInfoExtension
{
/// <summary>
/// Returns <see langword="true"/> if the field has the specified attribute.
/// </summary>
/// <typeparam name="T">The type of the attribte.</typeparam>
public static bool HasCustomAttribute<T>(this FieldInfo fiedInfo) where T : Attribute
{
return fiedInfo.GetCustomAttribute<T>() != null;
}
}
+10 -5
View File
@@ -122,12 +122,17 @@ internal static class ScriptGlue
#region Application #region Application
// TODO: Implement IsEditor and IsPlaying [MethodImpl(MethodImplOptions.InternalCall)]
//[MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool Application_IsEditor();
//internal static extern bool Application_IsEditor();
//[MethodImpl(MethodImplOptions.InternalCall)] [MethodImpl(MethodImplOptions.InternalCall)]
//internal static extern bool Application_IsPlaying(); internal static extern bool Application_IsPlayer();
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool Application_IsInEditMode();
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool Application_IsInPlayMode();
#endregion #endregion
} }