Motivation
Shared facets are defined statically at a global level using the sharedFacet
function as a combination of a name
and a type
. As an example from our documentation:
export const userFacet = sharedFacet<UserFacet>('data.user', {
username: 'Alex'
signOut() {},
})
We want to take the existing concept of a name
and expand it to be more of a path
to look into a big global state object within the game engine.
Thinking about the previous example, the name data.user
could be interpreted the as the path to the contents of the user in the object below:
This is really interesting when we consider that we could build a path dinamically in a React component to point to an specific instance of an object. Let's say we have a list of creatures in a game:
{
entity: {
hostile: {
'123': { name: 'creeper' },
'456': { name: 'piglin' }
}
}
}
And we want to subscribe to changes only to the creeper entity. With the current static definition of shared facets this could only be achieved via a dynamicSelector
, but then every selector would be notified when any entity changes. So we propose that we remove sharedFacet
as a function and instead have our API for subscribing to a shared facet to be completely handled in a hook by taking both the path
and the type:
const entityFacet = useSharedFacet<Entity>(['entity', 'hostile', '123'])
Type safety
cc @xaviervia can you add some notes about it?
Global definitions
We could still have a "global definition" of a facet, but this would be instead achieved via a hook:
--- export const userFacet = sharedFacet<UserFacet>('data.user')
+++ export const useUserFacet = useSharedFacet<UserFacet>(['data', 'user'])
Deprecations
This change will remove/deprecate the APIs for:
sharedFacet
sharedSelector
sharedDynamicSelector
In favor of using hooks and useFacetMap
or useFacetMemo
to achieve the same functionality.
It is important to assess if there are any risks on removing these APIs. And although we would be removing them from the open-source packages, they could still be kept implemented internally by consumers of our packages (if we need to provide any backwards compatibility).
Implementation considerations
When requesting a shared facet to the engine we need to make sure we only make one request for a given "path", even if multiple places are subscribing to it. This is currently achieved by having a single instance for each shared facet via memoisation in the sharedFacet
definition.
This behavior would need to be re-implemented as part of the useSharedFacet
hook.