Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Add IcomponentData to Prefab/GameObject from custom window editor ( not at runtime )

Discussion in 'Entity Component System' started by fas3r_, Jan 3, 2022.

  1. fas3r_

    fas3r_

    Joined:
    May 6, 2021
    Posts:
    11
    Hello,

    For the past few days Im trying to find a way to add/attach IComponentData to some Prefab/GameObject from a custom window editor (accessible from Tools menu ) that I made with Odin Inspector ( from asset store ) to manage my prefabs.

    As shown in the screenshot, I have a button `Add IcomponentData` and the goal is to check and attach (if missing) specific IComponentData to the Prefab/GameObject with some default values.

    Example of IComponentData:

    Code (CSharp):
    1. using Unity.Entities;
    2.  
    3. [GenerateAuthoringComponent]
    4. public struct PrefabWallData : IComponentData
    5. {
    6.     public PrefabLayout Layout;
    7.     public int LifeTime;
    8.     public bool IsWalkable;
    9.     public int Max;
    10. }
    Just to clarify, Im know how to use the entityManager to setComponentData and how to convert Prefabs to entity at runtime / playmode.

    Im basically trying to reproduce what we do from the UI, meaning dragging / dropping the IComponentData to a prefab/gameobject and set a values ( if any ) like we would do from the editor.

    I have ~200 prefabs to modify and I would be really happy if I could do that from a custom window editor with one click.

    For example, if I do the following to add the `ConvertToEntity` Component it works :
    Code (CSharp):
    1.  
    2. ....
    3. string pathGO = AssetDatabase.GetAssetPath(this.Prefab);
    4. GameObject rootGO = PrefabUtility.LoadPrefabContents(pathGO);
    5. ConvertToEntity addConvertToEntity = rootGO.AddComponent<ConvertToEntity>();
    6.  
    But when I try with `PrefabWallData` it complains that `The type 'PrefabLevelCategoryData' cannot be used as type parameter 'T' in the generic type or method 'GameObject.AddComponent<T>()'. There is no boxing conversion from 'PrefabLevelCategoryData' to 'UnityEngine.Component'`

    I understand the Error but Im not sure how to work around this ? Maybe its not possible to achieve what Im trying to do ?

    Any help would be welcome.

    Thanks

    upload_2022-1-2_23-28-35.png
     
    Last edited: Jan 3, 2022
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    With
    GenerateAuthoringComponent
    you can't. Post-processor generates MonoBehaviour for that component and in your case, it will be called
    PrefabWallDataAuthoring
    , but it's internal (you can see that in DOTS Compiler Inspector)
    upload_2022-1-3_12-10-19.png
    In your case you should manually implement
    MonoBehaviour
    with
    IConvertGameObjectToEntity
    , and then you can add that authoring to your prefabs.
     
  3. fas3r_

    fas3r_

    Joined:
    May 6, 2021
    Posts:
    11
    Hello Eizenhorn,

    Thank you for your answer.

    Indeed I created an internal class `PrefabLevelCategoryDataAuthoring` for a IComponentData `PrefabLevelCategoryData` like this:

    Code (CSharp):
    1. [GenerateAuthoringComponent]
    2. public struct PrefabLevelCategoryData : IComponentData
    3. {
    4.     public PrefabLevelCategory Value;
    5.  
    6. }
    Then I did the following but Im getting an error, Im not sure how to fix it :

    with :
    Code (CSharp):
    1. EntityManagerManagedComponentExtensions.AddComponentData(dstManager, entity, prefabLevelCategoryData);
    upload_2022-1-3_4-0-8.png

    It's true that when I look at `AddComponentData` I can see a generic method that expect a `<T>` as a class or IcomponentData

    upload_2022-1-3_3-49-12.png

    but even if I do, its complaining:

    upload_2022-1-3_4-1-58.png


    Also if I comment the 3 lines inside the `Convert` method in `PrefabLevelCategoryDataAuthoring` ( just an empty Convert method) , the component `PrefabLevelCategoryDataAuthoring` is added to the Prefab.

    The script part is empty, while the Value of the DataComponent ( `PrefabLevelCategory` ) is correct. I guess its normal as `EntityManagerManagedComponentExtensions.AddComponentData` is not set.

    upload_2022-1-3_4-18-24.png

    I do like this to add the component :

    Code (CSharp):
    1.  
    2. string pathGO = AssetDatabase.GetAssetPath(this.Prefab);
    3. GameObject rootGO = UnityEditor.PrefabUtility.GetCorrespondingObjectFromOriginalSource(this.Prefab);
    4.  
    5. PrefabLevelCategoryDataAuthoring addComponentCategoryDataAuthoring = rootGO.gameObject.AddComponent<PrefabLevelCategoryDataAuthoring>();
    6.  
    7. addComponentCategoryDataAuthoring.Value = PrefabLevelCategory.Trap;
    8.  
    9. UnityEditor.PrefabUtility.ApplyAddedComponent(addComponentCategoryDataAuthoring, pathGO, UnityEditor.InteractionMode.AutomatedAction);
    10.          
    11. //PrefabUtility.SaveAsPrefabAsset(rootGO, pathGO);
    12. //PrefabUtility.UnloadPrefabContents(rootGO);
    13.  
    14. UnityEditor.AssetDatabase.CreateAsset(rootGO, pathGO);
    15. UnityEditor.AssetDatabase.SaveAssets();
    16. UnityEditor.EditorUtility.SetDirty(rootGO);
    Thanks
     

    Attached Files:

  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    Read carefully
    Because you shouldn't use that. One of Convert arguments is EM which you should use.

    It's not how
    where
    keyword works. It's AND not OR.

    You shouldn't create that internal, I showed what
    GenerateAuthoringComponent
    does, read my previous answer again. If you use the manual conversion approach for components you shouldn't have
    GenerateAuthoringComponent
    .

    It seems you didn't read conversion documentation, I suggest you start from this first to understand how it works.
    https://docs.unity3d.com/Packages/com.unity.entities@0.17/manual/conversion.html
     
    bb8_1 likes this.
  5. fas3r_

    fas3r_

    Joined:
    May 6, 2021
    Posts:
    11
    Hello Eizenhorn,

    Thank you for your patience yesterday. Indeed I looked at it again just now and its working:

    Code (CSharp):
    1. public struct PrefabLevelCategoryData : IComponentData
    2. {
    3.     public PrefabLevelCategory Value;
    4.  
    5. }
    6.  
    7. class PrefabLevelCategoryDataAuthoring : MonoBehaviour, IConvertGameObjectToEntity
    8. {
    9.     public PrefabLevelCategory Value;
    10.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    11.     {
    12.  
    13.         dstManager.AddComponentData(entity, new PrefabLevelCategoryData
    14.         {
    15.             Value = Value
    16.         }) ;
    17.     }
    18. }
    19.  
    ( both are in 2 differents files .. I prefer to mention it )

    The documentation was pretty clear ... sorry about that.


    upload_2022-1-3_17-27-58.png


    Thanks for your help once again.
     
    Last edited: Jan 4, 2022
    bb8_1 likes this.
  6. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,626
    Side note, so I can't remember the exact method name from the top of my head but I figured out a year or so ago how to add GenerateAuthoringComponent to gameobjects from script. From memory you need to dig deep in the UnityEngine source code of the Inspector and look at the Add Component popup window and there is an internal method you can call via reflection that'll allow you to do this.

    Not sure I'd recommend it, but in theory it is possible!
     
    bb8_1 likes this.
  7. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,626
    Here's the method for the interest of anyone

    upload_2022-1-5_7-22-59.png

    This is the method. EditorApplication.ExecuteMenuItemOnGameObjects

    Code (CSharp):
    1. [GenerateAuthoringComponent]
    2. public struct BulletAgeComponent : IComponentData
    String format is just "Component/Scripts/YOURASSEMBLY/YOUR COMPONENT NAME SPLIT"

    (Note above break pointed example does not include YOURASSEMBLY but you need it if it's in an asmdef)
     
    Last edited: Jan 5, 2022
    bb8_1 likes this.