reeseschultz / ReeseUnityDemos

Unity packages and demos—emphasizing ECS, jobs and the Burst compiler—by Reese and others.

Home Page:https://reese.codes

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add a quality-of-life method to the prefab group package

williamtsoi opened this issue · comments

Hi @reeseschultz ,

Just wondering on this line here, should the entity query also include the component type Prefab as well?

=> entityManager.CreateEntityQuery(typeof(T)).GetSingleton<T>();

Since at the moment this cannot be used to get the prefab data that is loaded in the group?
Or am I misunderstanding the use of this, and its only expected to be used to get singletons which has already been initialised?

Currently getting this error when attempting to use this GetSingleton extension:
image
And there is a "TankShell" loaded in the prefab group, which does have a IComponent TankShell attached.
image


So what I am trying to do:

    var shellParams = EntityManager.GetSingleton<TankShell>();
    var maxVel = shellParams.maxVel;

But currently, it seems I have to do this:

    var shellPrefab = EntityManager.GetPrefab<TankShell>();
    var shellPrams = EntityManager.GetComponentData<TankShell>(shellPrefab);
    var maxVel = shellPrams.maxVel;

Best regards,
Will

Hi, Will.

at the moment this cannot be used to get the prefab data that is loaded in the group

By design, GetSingleton gets singletons, which may not necessarily have an associated Prefab component. This is not a bug. When I created this package, I assumed people would "instantiate" their prefabs, rather than treating them more as data stores, which may be better served by alternatives. That said, I completely understand the confusion, because there is, in fact, an instance of the converted prefab itself, but Unity ECS ignores it by default in queries (for good reason).

What it sounds like you want is a one-liner for fetching singleton prefab data. If so, does this extension method work for you?

/// <summary>Gets prefab data via the specified singleton component type.</summary>
public static T GetPrefabData<T>(this EntityManager entityManager) where T : struct, IComponentData
    => entityManager.CreateEntityQuery(
        ComponentType.ReadOnly(typeof(T)),
        ComponentType.ReadOnly(typeof(Prefab))
    ).GetSingleton<T>();

If so, I'd consider adding it to the package, although I'm worried folks will try to use it to affect instances of prefabs, and then submit more "bug" reports 😱.

Hi Reese,
I see, that makes sense and yeah that extension would work for me, though I would be happy to just add it separately to my own project instead of confusing this package if this isn't "best practice". I've not really thought out how I should be splitting out and managing the static "reference" data vs the changing data for units types yet.

For now, feel free to incorporate the above provided extension method in your codebase. I'd prefer to wait for related feedback from other users before any changes are made to this package.

Anyway, for your use case, you could consider leveraging blob assets. They are, to my understanding, the conventional data store mechanism for Unity ECS, at least in its current state. You can place references to blob assets in your components. That said, I find blob assets unwieldy from a DX perspective. There's so much less code and complexity if one either uses a) a static class, or b) accessible members of a system. Unless I'm missing something (it has happened before), what the blob asset achieves is the obfuscation of global variables, so they don't look like, well, global variables...

Which, brings me back around to my belief that you're not necessarily doing anything wrong by using prefabs as data stores. The best workflow is the one that makes you and/or your team most productive. One great thing about prefabs is that parameterizing them in the editor is a first-class feature. Any editor-compatible parameterization will ultimately have to occur via MonoBehaviour, so instantiating a blob asset from one in authoring just seems like too much contrived boilerplate for me, personally. Edit: I forgot to mention that the ScriptableObject satisfies this need as well, but it too would require similar boilerplate.

Giving credit where it's due, with the blob asset, you are at least explicitly defining references, although they could still be misleading—you could potentially refactor your code and have references declared in components that aren't used anymore. Regardless, "best practices" should be paths of least resistance, and if they're not, then something fundamental, beyond the application developer's control, needs to change.

I'll close this issue, for the time being. If you or another user want to reopen it, and contribute to the discussion, I'm happy to hear you out.