Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Upcoming API changes in 0.27

Discussion in 'Entity Component System' started by v_vuk, Apr 5, 2019.

  1. v_vuk

    v_vuk

    Unity Technologies

    Joined:
    Jul 11, 2017
    Posts:
    36
    We're working hard to make the DOTS API more approachable and intuitive. As part of this, we're taking a look at our API naming and overall API surface. The next release (Samples 0.27, DOTS core preview 30) of the core packages will include some significant renames that will require some manual updates to your projects. I understand the pain this causes! Normally we'd lean on our obsolete API updater to handle these changes, but some of these were beyond its capabilities.

    We believe these changes get us to a more pleasant and intuitive API as our core foundation for years to come, and would love to hear feedback on other parts of the API that feel confusing or inconsistent.

    There are three major API changes, and some manual steps required for each change.

    The ScriptBehaviourManager type has been removed

    ScriptBehaviourManager served as a base class for all ComponentSystems and EntityManager. This led to some awkward API, such as methods called GetOrCreateManager when they really referred to systems. There are two core changes here:

    1. EntityManager is now just a property on World: World.EntityManager

    This will require a manual search and replace:

    GetOrCreateManager<EntityManager>() => EntityManager
    GetExistingManager<EntityManager>() => EntityManager


    2. OnCreateManager and OnDestroyManager virtual methods on ComponentSystems have been renamed to OnCreate and OnDestroy. The OnCreateManager/OnDestroyManager methods will continue to work for a few releases.

    This unfortunately can't be handled by our script updater.

    3. *Manager methods on World have been renamed to refer to systems

    These should be handled by the script updater, but in case something fails, a search and replace of

    Manager( => System(


    to catch GetOrCreateManager, GetExistingManager, etc. should handle this. But be careful to not change OnCreateManager/OnDestroyManager (those should become OnCreate/OnDestroy).

    Most code should already have been inheriting from ComponentSystem or JobComponentSystem, so should not need any changes there. If you had any ScriptBehaviourManagers, a quick fix would be to just make them a ComponentSystem.

    IJobProcessComponentData has been renamed to IJobForEach

    This matches Entities.ForEach naming, and is both much simpler to type and say (internally we often referred to it as “I Job Component Process Thing Whatever It Is” or similar!):

    This will require a manual search and replace:

    IJobProcessComponentData => IJobForEach

    ComponentGroup has been renamed to EntityQuery

    ComponentGroup as a name has been the source of a lot of confusion. It has been renamed to EntityQuery to better represent what it does. Method names have been renamed to match, e.g. CreateEntityQuery.

    This change is unfortunately complex, and while most should be handled by the script updater, some core APIs cannot be which will cause issues. In general, doing the following search and replaces should get you to a place where the script updater can take over. Obsolete attributes should guide you along the way.

    Manual search and replace:

    CreateComponentGroup => CreateEntityQuery
    GetComponentGroup => GetEntityQuery


    Job scheduling using an EntityQuery has been renamed and simplified, and should be taken care of by the obsolete updater:

    ScheduleGroup => Schedule
    ScheduleGroupSingle => ScheduleSingle
    RunGroup => Run


    EntityArchetypeQuery has been renamed to EntityQueryDesc.

    We also require C# 7.3 support in your IDE.
    • For Visual Studio, this means VS 2017 update 15.7 or above.
      • If you are using ReSharper earlier than 2019.1 with Visual Studio, you'll need to right-click on the project and set "C# Language Level" to 7.3.
    • For Rider, this means 2018.2 or above.
      • If using a version earlier than 2019.1, you will also need to go into Unity -> Preferences -> Rider and turn on “Override LangVersion” and set it to 7.3.
    Without C# 7.3 support, you’ll run into ambiguous overload resolution errors, as DOTS code takes advantage of the better overload resolution rules in C# 7.3. (The Rider/ReSharper manual steps required are due to those tools getting confused by "latest" LangVersion combined with Unity's custom csc wrapper; that's been fixed in Rider/ReSharper 2019.1.)

    Please let us know if you run into any problems with these updates!
     
    Last edited: Apr 8, 2019
    Alverik, Fijit, Attatekjir and 25 others like this.
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,683
    You mean Samples I think, because 0.27 is samples version, not packages version (which now 0.0.12-preview.29 for Entities etc.) And here one suggestion, because I saw many confusing from beginners in DOTS between samples version and packages version. And if you told in this post about
    Maybe in addition lead to common denominator DOTS core version and samples version? Or at worst, in Release Notes, mark versions of packages relevant to the version of examples in brackets?
    Just suggestion for better life for beginners, because in this case we facilate forum from obvious questions and stopping waste time to this unnecessary questions and experienced peoples can target on real problems and helps people with DOTS problems and not "versions confusions" :)
     
    Enzi, starikcetin, rz_0lento and 3 others like this.
  3. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    You mean no more IJPCDWE? :)

    Thanks for the update instructions. I assume this'll be in entities .30?
     
  4. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    789
    The sample and entity version is confusing right from the start. Why are the changes for entities package preview 29 in the release notes of the samples 0.0.26? Or was is sample 0.0.25?
     
    Enzi and sirxeno like this.
  5. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,114
    Hi @v_vuk, when new version will be released?
     
  6. Deleted User

    Deleted User

    Guest

    When Unity will follow C# naming conventions? EntityQueryDesc.

    Ridiculous.

    Meanwhile we are waiting for adequate custom World support, proper EnityDebugger and understandable workflow we receive minor API changes that basically bring cosmetic.
     
    Last edited by a moderator: Apr 5, 2019
    Mikael-H, RaL and Knightmore like this.
  7. dzamani

    dzamani

    Joined:
    Feb 25, 2014
    Posts:
    122
  8. starikcetin

    starikcetin

    Joined:
    Dec 7, 2017
    Posts:
    340
    I am all for usability refactoring. I like these changes.
     
    leni8ec likes this.
  9. v_vuk

    v_vuk

    Unity Technologies

    Joined:
    Jul 11, 2017
    Posts:
    36
    Oh man, yes. Sorry -- I didn't realize we had separate versions for these. I'll try to get this sorted, because I agree, this is super confusing (uh, to us, too :).
     
    Alverik, Enzi, siggigg and 5 others like this.
  10. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    After update to entities.30, the following code:
    Code (CSharp):
    1. protected override void OnUpdate() {
    2.     Entities.WithAll<Transform, Translation, CopyTransformToGameObject>()
    3.     .ForEach( (Transform transform, ref Translation translation) =>
    4.     {
    5.         transform.position = translation.Value;
    6.     });
    7. }
    produces the following error
    Have I misunderstood that Entities.WithAll defines the EntityQuery to be used in ForEach? Is this error telling me that ForEach is creating a new query which conflicts with the WithAll query?

    Full error:
     
  11. v_vuk

    v_vuk

    Unity Technologies

    Joined:
    Jul 11, 2017
    Posts:
    36
    That should be allowed, but looks like we have a bug. The components referenced in the ForEach delegate are also added to the query, and code isn't handling the case where they've already been added to the query. For a fix, remove the mention of Transform/Translation from the WithAll.

    You can also try ref Transform in the delegate. One could be getting added ReadWrite (the first one) and the delegate param ReadOnly.

    Not allowing duplicate type references here is currently by design. Looking for feedback if this makes sense though!
     
    Last edited: Apr 5, 2019
    Alverik likes this.
  12. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    The delegate params are implicitly part of "All" so the exception is complaining about the redundancy.
     
    Alverik likes this.
  13. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    Yes but I need the query in WithAll as CopyTransformToGameObject is a tag and can't be used in the delgate.

    Is EntityQueryBuilder.m_Query actually getting set?
    WithAll adds to m_All but I can't see where it's updating/setting m_Query before ForEach is called?
    In which case ForEach goes if(m_Query == null)->recreate query from delegate.
     
  14. v_vuk

    v_vuk

    Unity Technologies

    Joined:
    Jul 11, 2017
    Posts:
    36
    You can still use WithAll -- they're additive:
    Code (csharp):
    1.  
    2. Entities.WithAll<CopyTransformToGameObject>().ForEach((Transform transform, ref Translation translation) => ... );
    3.  
     
    Alverik likes this.
  15. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    A major problem here is the lack of docs and I will work to address that soon.
     
    NeatWolf, Alverik, GilCat and 5 others like this.
  16. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    Gotcha, thanks.
     
  17. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I'm getting a weird error every time i stop playing the scene. I'm using Unity 2019.2.0a9
    InvalidOperationException: Late bound operations cannot be performed on fields with types for which Type.ContainsGenericParameters is true.
    System.Reflection.MonoField.CheckGeneric () (at <23c160f925be47d7a4fd083a3a62c920>:0)
    System.Reflection.MonoField.SetValue (System.Object obj, System.Object val, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Globalization.CultureInfo culture) (at <23c160f925be47d7a4fd083a3a62c920>:0)
    System.Reflection.FieldInfo.SetValue (System.Object obj, System.Object value) (at <23c160f925be47d7a4fd083a3a62c920>:0)
    Unity.Entities.TypeManager.ClearStaticTypeLookup ()
     
  18. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I've tracked down what is causing this error and it seems like it's because i use ComponentData with generics
    eg:
    Code (CSharp):
    1. public struct GenericComponent<T> : IComponentData {
    2.   public T Value;
    3. }
    It was working just fine on previous API
     
  19. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    You may need to enforce a constraint,
    where T : struct
    or
    where T : unmanaged
     
    GilCat likes this.
  20. v_vuk

    v_vuk

    Unity Technologies

    Joined:
    Jul 11, 2017
    Posts:
    36
    Hmm. Generic components cause some issues and we haven't fully decided whether they will or won't be supported though. That crash should be fixable, though; I'll take a look.
     
    Alverik, rsodre and GilCat like this.
  21. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I was forgetting that as the errors pointed away from it. Unfortunately that doesn't work either.
     
  22. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    How do we use ConvertToEntity with hierarchies of hybrid GameObjects?
    ConvertToEntity aborts if the parent GameObject contains ConvertToEntity, yet ConvertToEntity.ConvertAndInjectOriginal doesn't recurse the tree.
     
  23. GingerKendal3

    GingerKendal3

    Joined:
    May 16, 2018
    Posts:
    8
    I converted everything just fine with the exception that I get this error:

    error CS0117: 'ProjectWindowUtil' does not contain definition for 'CreateScriptAssetFromTemplateFile' 


    Library\PackageCache\com.unity.entities@0.0.12-preview.30\Unity.Entities.Editor\ScriptTemplates\ScriptTemplates.cs(15,31): error CS0117: 'ProjectWindowUtil' does not contain definition for 'CreateScriptAssetFromTemplateFile'

    I commented out the internal of the methods inside ScriptTemplates as a temporary bypass to test my project but I definitely don't want to leave commented out code inside a class I will eventually forget about.
     
  24. BanJaxe

    BanJaxe

    Joined:
    Nov 20, 2017
    Posts:
    47
    I think you need to update to the latest Unity beta, I had this on an older version but it's working now on 2019.1.0b10.
     
  25. Fito06

    Fito06

    Joined:
    Apr 4, 2019
    Posts:
    1
    Hi, I got the same error as GingerKenfal3.
    I just started a new project and added the "Entities" package when I got the same error message.
    I'm on 2019.2.0a7.
     
  26. Attatekjir

    Attatekjir

    Joined:
    Sep 17, 2018
    Posts:
    23
    I resolved this error by installing the latest visual studio 2017 instead of the 2019 version. I think when i installed the newest unity beta it even prompted me to install the visual studio 2017 version while a visual studio 2019 version was already installed.
     
  27. GingerKendal3

    GingerKendal3

    Joined:
    May 16, 2018
    Posts:
    8
    I tried updating VS 2017 but that did not fix the issue. I was on 2019.2.0a9, however, back tracking to 2019.1.0b10 fixed the issue. Which included redownloading packages - it is working fine now
     
  28. EvansT

    EvansT

    Joined:
    Jan 22, 2015
    Posts:
    22
    @scobi Has this always been the case? In a previous version, I did not include the delegate params in the WithAll<> and even though I was not getting errors, I was seeing weird behaviour - entities that did not have all the components listed in the delegate params were still being iterated over.
     
  29. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    How would manual SystemGroup creation be handled with the new APIs?

    Old API example:
    ExampleSystemGroup group = World.Active.GetOrCreateManager<ExampleSystemGroup>();
     
  30. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,223
    GetOrCreateManager is now GetOrCreateSystem. It should otherwise work as before (assuming you are coming from preview 29).
     
  31. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    I am getting null reference exception when I try to call group.Update() inside a FixedUpdate... I am not sure why if I only replaced that line:
    ExampleSystemGroup group = World.Active.GetOrCreateManager<ExampleSystemGroup>();
    to:
    ExampleSystemGroup group = World.Active.GetOrCreateSystem<ExampleSystemGroup>();
     
  32. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,223
    Which is null? group or World.Active?
     
  33. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    group seems to be giving the nullreferenceexception

    Edit: my mistake seems to have fixed this...
     
    Last edited: Apr 8, 2019
  34. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    What about OnCreateManager and OnDestroyManager wording? Wouldn't it be appropriate if they become OnCreate/DestroySystem too?
     
    optimise and zephyr831125 like this.
  35. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    Yes! After I replaced all "Manager(" to "System(", All my "OnCreateManager()" were replace to "OnCreateSystem()" and got an error :(
     
  36. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,114
    @v_vuk, any plan to add InitializeSystem to initialize some entities.
     
  37. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    They are called OnCreate and OnDestroy now
     
    Alverik, FROS7, 5argon and 2 others like this.
  38. v_vuk

    v_vuk

    Unity Technologies

    Joined:
    Jul 11, 2017
    Posts:
    36
    You should be able to use OnCreate for this -- the EntityManager is guaranteed to be available when that's called.
     
  39. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,114
    Currently ComponentSystem will force you to implement OnUpdate() function even u just want to use OnCreate.

    Looks like OnCreateManager() and OnDestroyManager() still not getting deprecated yet.
     
  40. Deleted User

    Deleted User

    Guest

    @optimise

     
    optimise likes this.
  41. rsodre

    rsodre

    Joined:
    May 9, 2012
    Posts:
    229
    My vote to support generic components, I can see many situations where this may be useful.
    Please, the System I'm building relies a lot on those!
     
    JesOb likes this.
  42. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    I would need more info to understand the weird behavior you had been seeing, but to answer your question: yes, it's always been the case. The behavior was and is: delegate+With = EntityQuery.

    All that changed was adding a test+throw for duplicates. For example, you could have done
    Code (CSharp):
    1. Entities.WithNone<Foo>().ForEach((ref Foo f) => { ... })
    and it wouldn't have complained.
     
    NotaNaN likes this.
  43. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    @rsodre would you mind giving some more info about your system? We are having an internal debate right now about the level of support for generic components we can provide, and more real-world examples are always helpful.

    For the curious: the problem with generic components is that they cannot be discovered quickly. You have to do a very expensive deep scan of all methods in all assemblies to find where each Foo<T>:IComponentData is instantiated to understand what concrete types are actually being created. (We need to do this to build various internal static tables.) It's not that we don't think it is useful, it's just that it is expensive to solve fully, and possibly relies on new build-time codegen tech that is in very early dev stages.
     
    amarcolina, NotaNaN and GilCat like this.
  44. rsodre

    rsodre

    Joined:
    May 9, 2012
    Posts:
    229
    Sure! At the core of my game is a system that stores generic parameters (float, float2, float3, ...) that are assigned different characters in the game. Each character can have multiple parameters, some more, some less, and are created and deletes all the time. I can select one and build a dynamic GUI with the parameters assigned to them to change their behaviour.

    The parameters look like this:

    Code (CSharp):
    1.     using Parameter1f = ParameterT<float>;
    2.     using Parameter2f = ParameterT<float2>;
    3.     using Parameter3f = ParameterT<float3>;
    4.  
    5.     public struct ParameterT<T> : IComponentData where T : unmanaged
    6.     {
    7.         public T Value;
    8.     }
    9.  
    And one simple job is like this...

    Code (CSharp):
    1.         [BurstCompile]
    2.         struct ReadersUpdateForceJob<T> : IJobChunk where T : unmanaged
    3.         {
    4.             public ArchetypeChunkComponentType<ParameterReader> ReadersType;
    5.             [ReadOnly] public ArchetypeChunkComponentType<ParameterDescription> DescriptionsType;
    6.             public ArchetypeChunkComponentType<ParameterT<T>> ValuesType;
    7.  
    8.             [ReadOnly] public NativeHashMap<int, ParameterT<T>> Storage;
    9.  
    10.             public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    11.             {
    12.                 var chunkReader = chunk.GetNativeArray(ReadersType);
    13.                 var chunkDescriptions = chunk.GetNativeArray(DescriptionsType);
    14.                 var chunkValues = chunk.GetNativeArray(ValuesType);
    15.                 for (var i = 0; i < chunk.Count; i++)
    16.                 {
    17.                     var reader = chunkReader[i];
    18.                     if (reader.Force)
    19.                     {
    20.                         var desc = chunkDescriptions[i];
    21.                         if (Storage.TryGetValue(desc.Hash, out ParameterT<T> newValue))
    22.                         {
    23.                             reader.Changed = true;
    24.                             reader.Force = false;
    25.                             chunkReader[i] = reader;
    26.                             chunkValues[i] = newValue;
    27.                         }
    28.                     }
    29.                 }
    30.             }
    31.         }
    32.  
    33.         JobHandle ScheduleParameterJobs<T>(JobHandle inputDeps, NativeHashMap<int, ParameterT<T>> mainStorage, EntityQuery ownersGroup, EntityQuery writersGroup, EntityQuery readersGroup) where T: unmanaged
    34.         {
    35.             //------------------------------
    36.             // Readers: Update Forced values
    37.             //
    38.             var readersUpdateForceJob = new ReadersUpdateForceJob<T>()
    39.             {
    40.                 Storage = mainStorage,
    41.                 ReadersType = GetArchetypeChunkComponentType<ParameterReader>(false),
    42.                 DescriptionsType = GetArchetypeChunkComponentType<ParameterDescription>(true),
    43.                 ValuesType = GetArchetypeChunkComponentType<ParameterT<T>>(false),
    44.             };
    45.             inputDeps = readersUpdateForceJob.Schedule(readersGroup, inputDeps);
    46.  
    47.             return inputDeps;
    48.         }
    49.  

    Does it have to be done every time we need to run a job or only when the system starts?
    Couldn't it be cached in some way?
    What if we declare all the generics we're using?
     
    krzysie7, GilCat and DreamingImLatios like this.
  45. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,223
    @rsodre That is a super cool use case! I might have to borrow that technique for injecting cinematic sequences into a simulation.

    Another use case that I have for generics, I currently use a generic IComponentData of type ISharedComponentData to trick the automatic job dependency management to take into account the NativeContainers on my Shared Components. All of this happens in some base classes that don't know nor care what types of ISharedComponentData they are managing dependencies for. Of course this could be solved with an API that lets us add additional rules to the automatic dependency management system.
     
    rsodre, krzysie7 and GilCat like this.
  46. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I also use a similar approach for animating values based also on float, float3, Color, etc

    Code (CSharp):
    1. public struct AnimationComponentData<T> : IComponentData where T : struct {
    2.   public float Elapsed;
    3.   public T Value;
    4.   public T Start;
    5.   public T End;
    6.   public bool Complete;
    7.   public float Duration;
    8. }
    My animation system has several jobs that will play the animation for the specif generic parameter and it looks like this:
    Code (CSharp):
    1. public class AnimateSystem : JobComponentSystem {
    2.  
    3.   [BurstCompile]
    4.   struct PlayFloatAnimation : IJobForEach<AnimationComponentData<float>> {
    5.     public float DeltaTime;
    6.     public void Execute(ref AnimationComponentData<float> animation) {
    7.       if (animation.Complete)
    8.         return;
    9.       animation.Elapsed += DeltaTime / animation.Duration;
    10.       animation.Value = math.lerp(animation.Start, animation.End, animation.Elapsed);
    11.     }
    12.   }
    13.  
    14.   [BurstCompile]
    15.   struct PlayFloat3Animation : IJobForEach<AnimationComponentData<float3>> {
    16.     public float DeltaTime;
    17.     public void Execute(ref AnimationComponentData<float3> animation) {
    18.       if (animation.Complete)
    19.         return;
    20.       animation.Elapsed += DeltaTime / animation.Duration;
    21.       animation.Value = math.lerp(animation.Start, animation.End, animation.Elapsed);
    22.     }
    23.   }
    24.  
    25.   [BurstCompile]
    26.   struct PlayColorAnimation : IJobForEach<AnimationComponentData<Color>> {
    27.     public float DeltaTime;
    28.     public void Execute(ref AnimationComponentData<Color> animation) {
    29.       if (animation.Complete)
    30.         return;
    31.       animation.Elapsed += DeltaTime / animation.Duration;
    32.       animation.Value = Color.Lerp(animation.Start, animation.End, animation.Elapsed);
    33.     }
    34.   }
    35.  
    36.   /*
    37.   More jobs come here for future animations
    38.   */
    39.  
    40.   protected override JobHandle OnUpdate(JobHandle inputDeps) {
    41.     var deltaTime = Time.deltaTime;
    42.     inputDeps = JobHandle.CombineDependencies(
    43.       new PlayFloatAnimation {
    44.         DeltaTime = deltaTime
    45.       }.Schedule(this, inputDeps),
    46.       new PlayFloat3Animation {
    47.         DeltaTime = deltaTime
    48.       }.Schedule(this, inputDeps),
    49.       new PlayColorAnimation {
    50.         DeltaTime = deltaTime
    51.       }.Schedule(this, inputDeps));
    52.     return inputDeps;
    53.   }
    54. }
    I use the animations values on other systems such as a system that animates Translation/Rotation/Scale values or another that animates alpha values of a render property.
     
    rsodre and Deleted User like this.
  47. Guerro323

    Guerro323

    Joined:
    Sep 2, 2014
    Posts:
    25
    I'm also using generic components as for checking if components data values were changed since the start of the frame or to check owners of an entity.
    (I also have other usages for generic components, but I only prioritized the components I use the most)

    I got some examples on how I'm using them, and why I think using generic components is better for these tasks.

    For the way I'm checking for data change:
    Code (CSharp):
    1. public struct DataChanged<T> : IComponentData
    2.     where T : struct, IComponentData
    3. {
    4.     public T    Previous;
    5.     public bool IsDirty;
    6.  
    7.     // this function is actually inside of a system, not in the component
    8.     public unsafe bool Update(ref T next)
    9.     {
    10.         IsDirty  = UnsafeUtility.MemCmp(UnsafeUtility.AddressOf(ref Previous), UnsafeUtility.AddressOf(ref next), UnsafeUtility.SizeOf<T>()) != 0;
    11.         Previous = next;
    12.  
    13.         return IsDirty;
    14.     }
    15. }
    16.  
    17. Entity entity = EntityManager.CreateEntity(typeof(Position), typeof(DataChanged<Position>));
    18.  
    19. void OnUpdate()
    20. {
    21.    var positionChanged = EntityManager.GetComponentData<DataChanged<Position>>(entity);
    22.    if (positionChanged.IsDirty)
    23.       // some code I guess...
    24. }
    25.  
    Or for checking owners of an entity...

    Code (CSharp):
    1.  
    2. public interface IOwnerDescription : IComponentData
    3. {
    4. }
    5.  
    6. public struct ColliderDescription : IOwnerDescription
    7. {
    8.     public class OwnerSync : OwnerStateSync<ColliderDescription>
    9.     {}
    10. }
    11.  
    12. public struct MovableDescription : IOwnerDescription
    13. {
    14.     public class OwnerSync : OwnerStateSync<MovableDescription>
    15.     {}
    16. }
    17.  
    18. public struct LivableDescription : IOwnerDescription
    19. {
    20.     public class OwnerSync : OwnerStateSync<LivableDescription>
    21.     {}
    22. }
    23.  
    24. public struct OwnerState<TOwnerDescription> : IStateData, IComponentData, ISerializableAsPayload
    25.     where TOwnerDescription : struct, IOwnerDescription
    26. {
    27.     public Entity Target;
    28.  
    29.     // I ommitted some methods here...
    30. }
    31.  
    32. var entity = EntityManager.CreateEntity(typeof(ColliderDescription));
    33. EntityManager.ReplaceOwnerData(target: entity, owner: movableEntity);
    34. EntityManager.ReplaceOwnerData(target: entity, owner: livableEntity);
    35. // actually, this extension method does a recursing search to search for others owners of the owner, so I can create an entity that will group multiple entities with different description.
    36.  
    37. var movableOwner = EntityManager.GetComponentData<OwnerState<MovableDescription>>(entity);
    38. var livableOwner = EntityManager.GetComponentData<OwnerState<LivableDescription>>(entity);
    39.  
    40.  

    If I don't use generic components, I will need to create a component everytime for the same task, and I could easily make errors when I need to make a change in the way the original component worked (especially if I have a lot of variations...).
     
    Last edited: Apr 23, 2019
  48. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,114
    Hi @scobi, any plan to add more parameters to better support Entities.With(query).ForEach API? Currently it's not possible to have more than one managed Component with multiple ComponentData.

    Hi @v_vuk, does the plan still release DOTS Core API 1.0 at 2019.2 cycle according to roadmap?
     
    Last edited: Apr 23, 2019
  49. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    We would need to do a deep scan of all methods to discover actual generic types being instantiated. And it would need to be done in advance (i.e. at build time), as we do cannot rely on reflection in all our supported .NET profiles. Doing this in a scalable way requires hooking into the compiler toolchain. This kind of thing is planned, as we have many things that need this, but it's not going to be soon.

    To get things moving sooner, we're looking at supporting manual registration of concrete types. In code you'd declare what types the generics would parameterize on, likely via attributes, and we'd scan that at build time and codegen the registrations.

    This is also a problem we're going to be looking at soon. We're up against limitations of what we can express in C# and have to balance delegate param type combinations we codegen against an explosion of thousands of overloads. The real solution is a more sophisticated codegen combined with more generic parameter types, but that's also the "not going to be soon" problem. There's a middle ground that we will be looking at sooner that will open up more flexibility in what combos of param types you can receive without exploding the overload list.
     
    FROS7, GilCat and optimise like this.
  50. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    That is good to know.
    Is this coming on the next release of Entities?