Deprecating ComponentDataProxy

Hello there,

I’m posting to let you know that we have plans for deprecating ComponentDataProxy and friends. Specifically, we plan to deprecate:

ComponentDataProxyBaseEditor, DynamicBufferProxyBaseEditor from Unity.Entities.Editor
ComponentDataProxy<T>, ComponentDataProxyBase, DynamicBufferProxy<T>, SharedComponentDataProxy<T>, SceneSectionProxy from Unity.Entities.Hybrid
MockDataProxy, MockDynamicBufferDataProxy, MockSharedDataProxy, MockSharedDisallowMultipleProxy from Unity.Entities.Tests
CopyInitialTransformFromGameObjectProxy, CopyTransformFromGameObjectProxy, CopyTransformToGameObjectProxy, LocalToWorldProxy, NonUniformScaleProxy, RotationProxy, TranslationProxy from Unity.Transforms

Since the deprecation of IJobForEach has caused lots of discussion, I wanted to give you a heads-up. If you have any concerns or questions, please use this thread.

3 Likes

I haven’t come across these before, what was their utility, why are they being deprecated and what, if anything, is replacing them?

2 Likes

Good questions! :slight_smile: Should have included them in the opening post.

  • What was their utility? They were part of a hybrid-workflow that allowed users to have a GameObject with an associated entity and read data from that entity using the GameObject.
  • Why are they being deprecated? We are deprecating them officially because we do not plan to support that workflow moving forward. There are several problems: ComponentDataProxy<T> tightly couples the authoring representation to the runtime representation. Reading entity-data at arbitrary points during the update will generally cause bubbles since you usually have to wait for jobs to finish. Creating entities from GameObject using this method doesn’t work in subscenes and doesn’t support LiveLink.
    Some of the types that are deprecated were already marked as deprecated in the menus for adding them to GameObjects for quite some time now.
  • What, if anything, is replacing them? We recommend that you use the GameObject-to-Entity conversion workflows instead to add data to entities converted from GameObjects. If you need to associate and read arbitrary data from entities in GameObjects, I suggest that you consider copying that data in a system once per frame. For the reverse scenario, we suggest using the new hybrid components instead.
4 Likes

Does this mean that GameObjectEntity would be removed as well? We’re still using those for a game in production since entity conversion just doesn’t fit with how we structured our game. Too much code needs to be revamped in order for it to work.

We’re not touching GameObjectEntity yet and the only changes planned are to get rid of the ComponentDataProxy references in there.

1 Like

Thanks. We can live with that.

Kill it :slight_smile:

4 Likes

Any plans to have transformsync system work without adding CopyTransformFromGameObject component to a hybrid gameobject?

We’re only deprecating the proxy component part of this. The functionality itself is still there, you merely have to write the conversion script yourself.

Will there be a way to access DrawGizmo stuff etc from a system? Or do you have another convenient way for in editor debug drawing?

Sorry to necro this, but I am trying to figure out the proper way to replace this while still having similar functionality. It has been about 6 months since I touched this project, so I am trying to get back up to speed on things.

Right now, this is how I was making use of it.

    [Serializable]
    public struct WheelSpin : IComponentData
    {
        public float speed;
        public float direction;
    }
    public class WheelSpinComponent : ComponentDataProxy<WheelSpin> { }

I then put one of those on each wheel, so then they were good to go. Now though, I am not sure what the best way is to go about referencing them so I can add the WheelSpin component.

I thought that maybe on the top level of the vehicle I could add this:

    public class WheelComponent : MonoBehaviour
    {
        public List<GameObject> wheels;
    }

But then once I run the vehicle itself through my:

var vehEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(prefab, settings);

I thought maybe I could then do something like this:
csharp* *var wheels = entityManager.GetComponentObject<WheelComponent>(vehEntity); for (int w = 0; w < wheels.wheels.Capacity; w++) { entityManager.AddComponentData(wheels.wheels[w].??, new WheelSpin()); }* *
But then it doesn’t seem like that would get me access to the wheel objects either. Do I just need to do the separately and create a whole other process just to add the WheelSpin component?
I realize that just dropping a conversion object on to the root of a game object and having it convert the whole object at once is great, but doesn’t seem that great in this instance. It feels like I am losing an extremely flexible way to easily add component data to individual parts of complex hierarchies by removing the ComponentDataProxy. Hopefully, there is just something else I am missing?

Are you aware of IConvertGameObjectToEntity? You don’t typically need to touch ConvertGameObjectHierarchy with the conversion workflow.

I am as of just a few moments ago as I just used it on a list of wheels.

This was what I have been using for the vehicle below, I originally set it up when the conversion system was first introduced a while back, but made the necessary changes to it the other day to get it working with the current api. Is there any sort of difference between doing it either way?

public NativeList<Entity> SpawnVehicle()
{
    blobAssetStore = new BlobAssetStore();
    var settings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, blobAssetStore);
    var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    for (int i = 0; i < prefab.Count; i++)
    {
        var vehEntity = GameObjectConversionUtility.ConvertGameObjectHierarchy(prefab[i], settings);
        vehEntities.Add(vehEntity);
        entityManager.AddComponentData(vehEntity, new VehicleEntity
        {
            entity = vehEntity
        });

        entityManager.AddBuffer<WaypointPathList>(vehEntity);
        entityManager.AddComponentData(vehEntity, new VehicleTag());
        entityManager.AddComponentData(vehEntity, new MovableTag());
        entityManager.AddComponentData(vehEntity, new MoveSpeed());
        entityManager.AddComponentData(vehEntity, new WaypointData());
        entityManager.AddComponentData(vehEntity, new WPPathStatus { PathStatus = VehicleController.instance.pathStatus });
        entityManager.AddComponentData(vehEntity, new WPGoalStatus { ReachedGoal = VehicleController.instance.goalStatus });
        entityManager.AddComponentData(vehEntity, new WPMoveStatus { movementStatus = VehicleController.instance.moveStatus });
        entityManager.AddComponentData(vehEntity, new SettingData
        {
            currentIndex = 1,
            CurrentTurnSpeed = vehicleTurnSpeed,
            DistanceFromWaypoint = distanceFromWaypoint
        });

        entityManager.AddComponent(vehEntity, typeof(Prefab));
#if UNITY_EDITOR
        entityManager.SetName(vehEntity, $"Vehicle_{i}");
#endif
    }

    return vehEntities;
}

I put a script on the top level of the vehicle, then added each of the child wheels to the list and then used this:

public class WheelComponent : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
{
    public List<GameObject> wheels;

    public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    {
        for (int i = 0; i < wheels.Count; i++)
        {
            referencedPrefabs.Add(wheels[i].gameObject);
        }
    }

    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        for (int i = 0; i < wheels.Count; i++)
        {
            var vehicleWheelEntity = new Wheel
            {
                entity = conversionSystem.GetPrimaryEntity(wheels[i])
            };
            var wheelSpin = new WheelSpin();
            dstManager.AddComponentData(vehicleWheelEntity.entity, wheelSpin);
        }
    }
}

It seems to be working, but I am not sure yet if there are going to be any negatives to doing it this way, as the wheels are technically already part of the vehicle, which is getting converted with the top script, but then on the same prefab I have the second script to take care of the wheels. I am not sure of how else to do it without physically separating their hierarchy.

I’m not 100% sure that I understand what you’re trying to do. Is this for runtime spawning, like prefabs? I think that you’re over-complicating things. Why do you need the list of wheel entities?

Sorry for the confusion. Yeah, I am doing runtime spawning.

Just before you made your first post I had discovered and used the IConvertGameObjectToEntity workflow on the wheels and it seemed to work fine. The reason I had a list was that I used it to add the wheels that were on the vehicle prefab.

The way I have it setup now is working. I was able to replace the ComponentDataProxy with the above pictured WheelComponent (which needs its name changed) which is the script I posted above utilizing IConvertGameObjectToEntity.

This brought up another question though because the wheels using the IConvertGameObjectToEntity workflow are in the same hierarchy as the actual vehicle, they are of course just a child object, but that is because I am not sure of any other way to get access to the actual wheels during or after the conversion of the root vehicle object now that it doesn’t have the ComponentDataProxy on it.

So the vehicle, from the top-level down, is getting converted. Which then from my understanding, is converting the entire vehicle, wheels and all. But to get reference to the wheels in order to add the wheelspin component, I have to run a separate IConvertGameObjectToEntity on them so I can add the wheelspin component. So it sounds like the wheels are getting converted twice? I don’t see any extra entities in the entity debugger though, so I am wondering if doing it this way is ok or not.

Why don’t the wheel GameObjects just have an IConvertGameObjectToEntity component on them that adds the WheelSpin component?

struct VehicleTag : IComponentData { }

struct WheelSpin : IComponentData {
    public float Spin; // Or whatever data goes here
}


// Goes on the root vehicle GameObject
public class VehicleAuthor : MonoBehaviour, IConvertGameObjectToEntity
{
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        dstManager.AddComponent<VehicleTag>(entity);
        // And whatever else you need added here
    }
}


// Goes on the wheel GameObjects
public class WheelAuthor : MonoBehaviour, IConvertGameObjectToEntity
{
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        dstManager.AddComponentData(entity, new WheelSpin() { Spin = 0 });
        // And whatever else you need added here
    }
}

If you want to get the entity reference for the wheels from the top level Convert method, you should be able to use conversionSystem.GetPrimaryEntity.

struct WheelEntityReferences : IComponentData
{
    public Entity FrontLeft;
    public Entity FrontRight;
    public Entity BackLeft;
    public Entity BackRight;
}


// Goes on the root vehicle GameObject
public class VehicleAuthor : MonoBehaviour, IConvertGameObjectToEntity
{
    public GameObject FrontLeftWheel;
    public GameObject FrontRightWheel;
    public GameObject BackLeftWheel;
    public GameObject BackRightWheel;

    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        dstManager.AddComponent<VehicleTag>(entity);
        dstManager.AddComponentData(entity, new WheelEntityReferences() {
            FrontLeft = conversionSystem.GetPrimaryEntity(this.FrontLeftWheel),
            FrontRight = conversionSystem.GetPrimaryEntity(this.FrontRightWheel),
            BackLeft = conversionSystem.GetPrimaryEntity(this.BackLeftWheel),
            BackRight = conversionSystem.GetPrimaryEntity(this.BackRightWheel)
        });
        // And whatever else you need added here
    }
}

I haven’t run this code to check it now, but I think it should be along the right lines.

1 Like

Is this documented anywhere?
All I found about it is some forum posts with bunch of 404 links.

all of the ECSSamples should pretty clearly showcase conversion https://github.com/Unity-Technologies/EntityComponentSystemSamples

This blog post from our esteemed community friend @5argon is also very useful to understand the conversion flow.