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

Help needed: ConvertToEntity works but SubScene does not for SharedComponentData

Discussion in 'Entity Component System' started by simi_, Nov 2, 2019.

  1. simi_

    simi_

    Joined:
    Sep 15, 2018
    Posts:
    2
    I have written a converter for the SpriteRenderer that looks as follows:

    Code (CSharp):
    1. public class SpriteRendererConverter : MonoBehaviour, IConvertGameObjectToEntity
    2. {
    3.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    4.     {
    5.         var spriteRenderer = GetComponent<SpriteRenderer>();
    6.         var sprite = spriteRenderer.sprite;
    7.         var mesh = new Mesh() {
    8.             vertices = Array.ConvertAll(sprite.vertices, x => (Vector3)x),
    9.             triangles = Array.ConvertAll(sprite.triangles, x => (int)x),
    10.             uv = sprite.uv
    11.         };
    12.         dstManager.AddComponentData(entity, new PerInstanceRenderInfo
    13.         {
    14.             Tint = spriteRenderer.color,
    15.             Layer = gameObject.layer
    16.         });
    17.         dstManager.AddSharedComponentData(entity, new SharedSprite
    18.         {
    19.             Value = sprite
    20.         });
    21.         dstManager.AddSharedComponentData(entity, new SharedMesh
    22.         {
    23.             Value = mesh
    24.         });
    25.     }
    26. }
    This works fine when I'm attaching the ConvertToEntity script. But when I want to create a subscene out of a gameobject it throws the following error:

    ArgumentException: SharedMesh has no valid proxy shared component data. Please create one.
    The problem seems to be with SharedComponentData in general; when I comment out SharedMesh it throws the same error with SharedSprite.

    As far as my understanding goes Proxies are deprecated, so I'm unsure if this error is even correct. I was also unable to find any information about how exactly Proxies are supposed to be implemented.
    Providing simple stubs like:

    public class SharedMeshProxy : SharedComponentDataProxy<SharedMesh>{}
    prevents the errors but doesn't make it work correctly.
    Does anyone have a clue what it is that I'm doing wrong and how to fix it?
     
    TotallyRonja likes this.
  2. Sibz9000

    Sibz9000

    Joined:
    Feb 24, 2018
    Posts:
    149
    Same issue here. I just ran it to it. I had the item in my main scene, but when I moved it to the sub scene and removed Convert To Entity, I got this error. Remove the SharedComponentData and it works.
     
    simi_ likes this.
  3. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    Show your shared component declaration.
     
  4. TotallyRonja

    TotallyRonja

    Joined:
    Oct 1, 2016
    Posts:
    9
    I figured it out. The problem is the way ISharedComponentData is Serialized.

    Because the problem is serialisation and the ConvertToEntity workflow works at runtime they never collide, the subscene is superior because the heavy lifting for conversion can be done at editor time, but this leads to the need to serialize the data.

    The requirements for ISharedComponentData (that I've found) is that you have a class called "{YourSharedComponent}Proxy" which inherits from "SharedComponentDataProxy<{YourSharedComponent}>" (it can be completely empty). This Proxy class has to be in a file called "{YourSharedComponent}Proxy.cs". In addition to this your shared component also has to have the "[System.Serializable]" attribute. It's easiest to pack both your component as well as the proxy in the same file and call it the name of the proxy class.

    As straightforward example of a serializable ISharedComponentData would be this script in a file called "SharedSpriteProxy.cs":

    Code (CSharp):
    1. using System;
    2. using Unity.Entities;
    3. using UnityEngine;
    4.  
    5. [Serializable]
    6. public struct SharedSprite : ISharedComponentData, IEquatable<SharedSprite>
    7. {
    8.     public Sprite Value;
    9.  
    10.     //insert object equals, SharedSprite equals, GetHashCode, == and != functions
    11. }
    12.  
    13.  
    14. public class SharedSpriteProxy : SharedComponentDataProxy<SharedSprite>
    15. {}
    It would be really nice if the file name and proxy class requirements would go in the future or be generated in the background where you don't have to worry about them.
     
    Last edited: Nov 2, 2019
    simi_ and Sibz9000 like this.
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    As you have found out, the serializer is quite out of date and still uses SharedComponentDataProxy to handle ISharedComponentData. Don't expect SharedComponentDataProxy to hang around though. It's part of the old GameObjectEntity workflow that while isn't technically depreciated yet will be removed at some point.

    I'm hoping the next version removes this dependency as it's been 8 months since conversion workflow as was added.
     
    simi_, Sibz9000 and MNNoxMortem like this.
  6. Sibz9000

    Sibz9000

    Joined:
    Feb 24, 2018
    Posts:
    149
    All I needed was a sleep, was so annoyed I couldn't figure this out last night!
    Thanks @tertle and @Ronja42 for the info/updates.
     
  7. simi_

    simi_

    Joined:
    Sep 15, 2018
    Posts:
    2
    Thank you all so much for the quick help! I was able to solve my problem and get subscenes to work :)

    I really wish this was documented better - or at all actually...
    I found some other curiosities that might help people searching for this problem so here goes:

    Serializing meshes did not work, probably because they are cleaned up since they don't have another reference to them. Saving them into a serialized field on the conversion script unfortunately didn't help either. The solution was to just generate the mesh at runtime and add the SharedComponent then.

    The subscene will take some time to load and does so without stalling the main thread. So not seeing anything for the first few frames is normal. This is kind of documented in that there are forum entries talking about it - adding that to the sparse documentation of SubScene would be a start though...as would be having a direct callback when its done loading.