Search Unity

Delegate 'EntityQueryBuilder.F_E' does not take 3 arguments

Discussion in 'Entity Component System' started by Garzec, May 21, 2019.

  1. Garzec

    Garzec

    Joined:
    Mar 3, 2016
    Posts:
    151
    Hey guys. I am new to the ECS and want to get into it. I use Ubuntu 19.4. and had some issues with the latest alpha version so I installed Unity 19.1.3f1 today and installed the preview packages some hours ago.

    I am trying to recreate the Roll-A-Ball tutorial.

    First of all I created two components for my movement

    Code (CSharp):
    1. public class MovementInput : IComponentData
    2. {
    3.     public float x;
    4.     public float y;
    5.     public float z;
    6. }
    7.  
    Code (CSharp):
    1. public class MovementSpeed : IComponentData
    2. {
    3.     public float value;
    4. }
    After that I created the input and movement system

    Code (CSharp):
    1. public class PlayerInputSystem : ComponentSystem
    2. {
    3.     protected override void OnUpdate()
    4.     {
    5.         float horizontalInput = Input.GetAxis("Horizontal");
    6.         float verticalInput = Input.GetAxis("Vertical");
    7.  
    8.         Entities.ForEach((ref MovementInput movementInput) => {
    9.             movementInput.x = horizontalInput;
    10.             movementInput.z = verticalInput;
    11.         });
    12.     }
    13. }
    Code (CSharp):
    1. public class MovementSystem : ComponentSystem
    2. {
    3.     protected override void OnUpdate()
    4.     {
    5.         float deltaTime = Time.deltaTime;
    6.  
    7.         Entities.ForEach((ref Rigidbody rigidbody, ref MovementInput movementInput, ref MovementSpeed movementSpeed) => {
    8.             float3 movementDirection = new float3(movementInput.x, movementInput.y, movementInput.z);
    9.             rigidbody.AddForce(movementDirection * movementSpeed * deltaTime);
    10.         });
    11.     }
    12. }
    So I get these errors

    - Assets/Scripts/Systems/PlayerInputSystem.cs(12,26): error CS1661: Cannot convert lambda expression to type 'EntityQueryBuilder.F_E' because the parameter types do not match the delegate parameter types

    - Assets/Scripts/Systems/PlayerInputSystem.cs(12,45): error CS1678: Parameter 1 is declared as type 'ref MovementInput' but should be 'Unity.Entities.Entity'

    - Assets/Scripts/Systems/MovementSystem.cs(11,26): error CS1593: Delegate 'EntityQueryBuilder.F_E' does not take 3 arguments

    and don't know how to fix them. I took this tutorial and I think my code is similiar to his code ..

     
  2. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    Hi @Garzec - congratulations, you're hitting the edge of the compiler's ability to give useful errors! :(

    So the problem is that we have a lot of overloads of ForEach, which are necessarily required to support the different ways you can receive components (and an optional Entity) in your lambda. And your particular combo is confusing the compiler, so it's giving up and complaining about parameter mismatch in an even more confusing way.

    Here's the basic problem: you're receiving `ref class`. This doesn't make sense in ECS and isn't part of the overloads we provide. So try just removing the `ref`.

    But I think what you actually want to do is keep the `ref` but change all those classes to structs. ECS is about valuetypes. The support for classes is mostly about bridging with components from the GameObject world, which isn't what you're doing here.

    Give that a try, let us know how it goes.
     
    FuDaNing likes this.
  3. Garzec

    Garzec

    Joined:
    Mar 3, 2016
    Posts:
    151
    oh ... yeah I forgot to change class to struct ... stupid me. @scobi But I still get the error

    in this line

    Code (CSharp):
    1.  
    2. Entities.ForEach((ref MovementInput movementInput, ref MovementSpeed movementSpeed, Rigidbody rigidbody) => {
    3.     float3 movementDirection = new float3(movementInput.x, movementInput.y, movementInput.z);
    4.     rigidbody.AddForce(movementDirection * movementSpeed.value * deltaTime);
    5. });
    6.  
    and I'm not sure if I can access the rigidbody this way..? The code is just my first try :rolleyes:
     
    Last edited: May 22, 2019
  4. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    You can...as scobi was saying they created a lot of overloads for all the foreach calls. Sometimes the types of the arguments you're passing into ForEach will need to be in a specific order. In this case it seems they want you to pass classes first before components but after the (optional) entity.

    Hopefully at some point we will get some decent documentation about this in particular since the error messages you get from it are truly bad and unhelpful.
     
  5. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    @Sarkahn is correct - we have a F_CDD overload that should match. Put the class first.

    Unfortunately to avoid crazy exponential combinatorial explosion of codegen, we needed to select the combinations we thought most common and also add some constraints (such as "if class and struct mixed, you get one class, and it has to be first").

    This situation is crappy and hard to discover what's wrong and what to do about it. We're hitting language limits here with the current technique and it is due for an overhaul. Large effort, will probably be a while before we get to that, but it is on the agenda.
     
    abixbg and Sarkahn like this.
  6. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    Btw here is the enum we use for the codegen so you can see what the letter codes mean:

    Code (CSharp):
    1. enum Category
    2. {
    3.     // note: 'in' is broken in c# (very easy for user to accidentally cause a copy) so we do not
    4.     // include it in the combos we support yet.
    5.  
    6.     D, // ref ComponentData
    7.     I, // in ComponentData
    8.     C, // class
    9.     B, // IBufferElementData
    10.     K, // in IBufferElementData
    11.     S, // ISharedComponentData
    12. }
    13.  
    (Note that I and K are not currently generated because we are limiting combinatorial explosion, plus `in` has potential surprising perf implications depending on usage. We plan to support `in` when the codegen gets an overhaul.)

    The F_ prefix on a delegate is just "here's a function", and the rest of the letters are the parameters. So the compiler erroring about F_E means that it's trying to match the plain Entity delegate for some reason. You can look at autocomplete to see all the variants, or you can just open up the code from the package directly. The EntityQueryBuilder_ForEach.tt file is the codegen source.
     
    Sarkahn likes this.
  7. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    This is very helpful, thank you. On a related note these names and conventions seem to be slightly different from the new IJobForEach_X conventions which makes it even more confusing. It's nice to know you guys are thinking about rehauling it at least.
     
  8. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    Ugh, I missed that in my review. Good point, I'll add an issue to align these.
     
    Sarkahn likes this.
  9. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    Actually @Sarkahn I took a closer look and am not sure what is misaligned. What specifically are you referring to being slightly different between IJobForEach and Entities.ForEach?
     
  10. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    In IJobForEach C = ComponentData rather than class (yes I understand you can't use classes in jobs), where in ForEach C = Class. In IJobForEach the type ordering is strictly alphabetical based on their assigned letters after entity. In Foreach it just seems kinda...random.

    IE:
    (ref Translation t, RigidBody r) <- Okay
    (ref Translation t, RigidBody r, ref Rotation rot) <- Not Okay
    (RigidBody r, ref Translation t, ref Rotation rot) <- Okay

    It's basically a guessing game in ForEach (unless I'm missing something), whereas in IJobForEach the rules are clearly defined.
     
  11. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32
    Ah, right, I spaced on the C. Ok thanks, also extra useful to know about how it feels like a guessing game in ForEachland.
     
    drhodor and Sarkahn like this.
  12. Garzec

    Garzec

    Joined:
    Mar 3, 2016
    Posts:
    151
    thanks guys!
     
  13. sinjimonkey

    sinjimonkey

    Joined:
    Jul 31, 2013
    Posts:
    72
    UGHH this is so frustrating. Sorry for 'necroing' this thread but this is the best one on the subject and I'd rather bump this than create a new one;

    Why does this not work with the _EDB combo?

    ForEach<NumPlayersComponentData, PlayerPocketsBufferElement>
    ((Entity entity, ref NumPlayersComponentData numPlayers, ref PlayerPocketsBufferElement pocket)

    I've tried using and removing the ref on the BufferElement. I can get the ComponentData to work by itself and with the entity, but as soon as I try to add buffer elements it doesn't work.

    I know I can grab the buffer elements from within the code itself (Which is what I'm currenly doing) but as it stands now I have to use component tags to tag things with the buffer elements in order to pull them into a system. I think this would create issues if I were to try to do parallel jobs though (which I'm not currently)
     
    Last edited: Apr 30, 2020
  14. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    You shouldn't try to include the generic parameters on the ForEach, they will be inferred automatically. And for buffers you need to pass it as
    DynamicBuffer<BufferType> buffer
    , so something like:

    Code (CSharp):
    1.         Entities.ForEach((Entity e, ref DynamicBuffer<PlayerPocketsBufferElement> pocket, ref NumPlayersComponent numPlayers) =>
    2.         {
    3.            
    4.         }).Schedule();
    The manual page for the ForEach explains everything pretty well, I suggest you review it carefully if you run into trouble.
     
    Last edited: Apr 30, 2020
    joepl likes this.