Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by vElumi · Aug 04, 2019 at 09:32 AM · c#editorcomponentattribute

Custom [Require*] attribute

I'm trying to do something custom RequireTrait attribute that should mark components so that they are attached only if some other component of that gameObject has publicly available field or property of given type. I'm trying to determine where should that checking function run.


Say I have a custom attribute:

 [AttributeUsage(AttributeTargets.Class)]
 [BaseTypeRequired(typeof(Component))]
 public class RequireTraitAttribute : Attribute {
     public readonly Type traitType;
     public RequireTraitAttribute(Type traitType) {
         this.traitType = traitType;
     }
 }


And then use it like this:

 [RequireTrait(typeof(HitPoints))]
 public class HealthManager : MonoBehaviour {
   private HitPoints hitPoints;

   private void Awake() {
     hitPoints = gameObject.GetTrait<HitPoints>(); // custom extension function
   }
   
   ...
 }


Now HealthManager should require some provider of HitPoints, or otherwise should be detached from game object:

 [???] // Appropriate unity attribute?
 public static void CheckRequiredTraits() {
   ... // Detach components that do not fit criteria
 }


When and where should this check be done?
How does RequireComponent deal with that?

Reset() seems inaproptiate and cluttering. As well as creating custom editor every time.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by Dawdlebird · Aug 04, 2019 at 10:13 AM

Interesting approach.. but have you considered using OnValidate()? Doesn't require a custom editor, but allows you to run any code or method in the editor and can remove components based whatever criteria you manage to check gameobjects on.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image vElumi · Aug 04, 2019 at 02:50 PM 0
Share

OnValidate() would unnecessarily run every time some property would change, so I don't think that's correct.

Reset() seems better, because it executes when I add my annotated component, so I can validate it and, if needed, WaitForEndOfFrame() and DestroyImmediate().

But then I have to write that logic in every class, and it just doesn't look right conceptually. I really need similar behaviour to [RequireComponent(...)] attribute, but cannot find information on how to achieve that. :(

avatar image
0

Answer by vElumi · Aug 04, 2019 at 06:54 PM

I wrote this as a workaround. Maybe this can clarify what I'm after.

I used [InitializeOnLoad] class and subscribe to EditorApplication.update to check for all components and then remove component if no public provider was found.

Dounsides are that it:

  1. Loops through all components

  2. Executes every frame

    using System; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object;

    namespace Scenes.FightScene.Character.Trait { [InitializeOnLoad] public class TraitChecker { private class TypeData { public readonly Type markedType; public readonly Type requiredType;

              public TypeData(Type markedType, Type requiredType) {
                     this.markedType = markedType;
                     this.requiredType = requiredType;
                 }
             }
     
             private static TypeData[] typeData;
     
             private const BindingFlags Bindings = BindingFlags.Instance | BindingFlags.Public;
     
             static TraitChecker() {
                 UpdateMarkedTypes();
                 EditorApplication.update += CheckRequiredTraits;
             }
     
             [UnityEditor.Callbacks.DidReloadScripts]
             private static void UpdateMarkedTypes() {
                 typeData = AppDomain.CurrentDomain.GetAssemblies()
                     .SelectMany(asm => asm.GetTypes())
                     .Select(type => {
                         var attribute = type.GetCustomAttribute<RequireTraitAttribute>(true);
                         return attribute == null
                             ? null
                             : new TypeData(type, attribute.traitType);
                     })
                     .Where(td => td != null)
                     .ToArray();
             }
     
             private static void CheckRequiredTraits() {
                 // Get all components
                 var sceneComponents = Object.FindObjectsOfType<Component>();
     
                 foreach (var td in typeData) {
                     // Filter all instances of types, that are marked with [RequireTrait]
                     var markedInstances =
                         sceneComponents.Where(component =>
                             component.GetType() == td.markedType);
     
                     foreach (var instance in markedInstances) {
                         // Get all components on gameObject, that are not component itself
                         var components = instance.GetComponents<Component>()
                             .Where(c => c != instance);
     
                         // Select distinct types of those components 
                         var componentsTypes = components
                             .Select(component => component.GetType())
                             .Distinct().ToArray();
     
                         // If no components provide required trait via fields or properties
                         if (componentsTypes.All(type =>
                                 type.GetFields(Bindings)
                                     .All(fieldInfo => fieldInfo.FieldType != td.requiredType)
                                 && type.GetProperties(Bindings)
                                     .All(propertyInfo =>
                                         propertyInfo.PropertyType != td.requiredType)))
                             // Remove instance
                             Object.DestroyImmediate(instance);
                     }
                 }
             }
         }
     }
    
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

648 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Some public attributes not shown in inspector, default references 3 Answers

RequireComponent at variable level? 1 Answer

"Restart " C# script that has [ExecuteInEditMode] attribute and Start() function. 0 Answers

Initialising List array for use in a custom Editor 1 Answer

Create a Component Script for Editor Only 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges