diff --git a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs index 91a89bba7..93a8ec6be 100644 --- a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs @@ -242,18 +242,43 @@ namespace FlaxEditor.CustomEditors.Dedicated if (attributes.Count > 0) { - foreach (var attribute in attributes) + foreach (var e in attributes) { - if (!attribute.RequiredType.IsSubclassOf(typeof(Script))) + if (!e.RequiredType.IsSubclassOf(typeof(Script))) continue; - requiredScripts.Add(new ScriptType(attribute.RequiredType)); + requiredScripts.Add(new ScriptType(e.RequiredType)); } } } + + // See if script requires a specific actor type + RequireActorAttribute actorAttribute = null; + if (scriptType.HasAttribute(typeof(RequireActorAttribute), false)) + { + foreach (var e in scriptType.GetAttributes(false)) + { + if (e is not RequireActorAttribute requireActorAttribute) + continue; + actorAttribute = requireActorAttribute; + break; + } + } + var actors = ScriptsEditor.ParentEditor.Values; for (int j = 0; j < actors.Count; j++) { var actor = (Actor)actors[j]; + + // If required actor exists but is not this actor type then skip adding to actor + if (actorAttribute != null) + { + if (actor.GetType() != actorAttribute.RequiredType && !actor.GetType().IsSubclassOf(actorAttribute.RequiredType)) + { + Editor.LogWarning($"{Utilities.Utils.GetPropertyNameUI(scriptType.Name)} not added to {actor} due to script requiring an Actor type of {actorAttribute.RequiredType}."); + continue; + } + } + actions.Add(AddRemoveScript.Add(actor, scriptType)); // Check if actor has required scripts and add them if the actor does not. foreach (var type in requiredScripts) @@ -614,7 +639,7 @@ namespace FlaxEditor.CustomEditors.Dedicated var editor = CustomEditorsUtil.CreateEditor(scriptType, false); // Check if actor has all the required scripts - bool hasAllRequiredScripts = true; + bool hasAllRequirements = true; if (scriptType.HasAttribute(typeof(RequireScriptAttribute), false)) { var scriptTypesToCheck = new List(); @@ -643,17 +668,40 @@ namespace FlaxEditor.CustomEditors.Dedicated var requiredScript = script.Actor.GetScript(type.Type); if (requiredScript == null) { - Editor.LogWarning($"{Utilities.Utils.GetPropertyNameUI(scriptType.Name)} on {script.Actor} is missing a required script of type {type}."); - hasAllRequiredScripts = false; + Editor.LogWarning($"{Utilities.Utils.GetPropertyNameUI(scriptType.Name)} on {script.Actor} is missing a required Script of type {type}."); + hasAllRequirements = false; } } } } + if (scriptType.HasAttribute(typeof(RequireActorAttribute), false)) + { + var scriptTypesToCheck = new List(); + RequireActorAttribute attribute = null; + foreach (var e in scriptType.GetAttributes(false)) + { + if (e is not RequireActorAttribute requireActorAttribute) + continue; + attribute = requireActorAttribute; + break; + } + + if (attribute != null) + { + var actor = script.Actor; + if (actor.GetType() != attribute.RequiredType && !actor.GetType().IsSubclassOf(attribute.RequiredType)) + { + Editor.LogWarning($"{Utilities.Utils.GetPropertyNameUI(scriptType.Name)} on {script.Actor} is missing a required Actor of type {attribute.RequiredType}."); + hasAllRequirements = false; + // Maybe call to remove script here? + } + } + } // Create group var title = Utilities.Utils.GetPropertyNameUI(scriptType.Name); var group = layout.Group(title, editor); - if (!hasAllRequiredScripts) + if (!hasAllRequirements) group.Panel.HeaderTextColor = FlaxEngine.GUI.Style.Current.Statusbar.Failed; if ((Presenter.Features & FeatureFlags.CacheExpandedGroups) != 0) { diff --git a/Source/Engine/Scripting/Attributes/Editor/RequireActorAttribute.cs b/Source/Engine/Scripting/Attributes/Editor/RequireActorAttribute.cs new file mode 100644 index 000000000..6e08217bf --- /dev/null +++ b/Source/Engine/Scripting/Attributes/Editor/RequireActorAttribute.cs @@ -0,0 +1,25 @@ +using System; + +namespace FlaxEngine; + +/// +/// This attribute is used to check for if a script requires an Actor type. +/// +[Serializable] +[AttributeUsage(AttributeTargets.Class)] +public class RequireActorAttribute : Attribute +{ + /// + /// The required type. + /// + public Type RequiredType; + + /// + /// Initializes a new instance of the class. + /// + /// The required type. + public RequireActorAttribute(Type type) + { + RequiredType = type; + } +}