kaosat-dev/Blenvy

Add support for references between entities

andriyDev opened this issue · 0 comments

Currently (correct me if I'm wrong), there doesn't seem to be a way to have entities in a blueprint/gltf reference each other.


Here is my proposal for this:

The core API

  1. A component storing the "identifier" that an entity should be referenced with.
  2. A resource mapping identifiers (per blueprint/gltf) to the corresponding entity.
// Component holding the identifier of the thing being referenced.
// Private so it can only be accessed in Blender.
struct GltfRefTarget(String);

// Resource mapping the gltf instance + ref identifier to the entity holding that identifier.
// Public so users can write their own custom components that take refs (see below).
pub struct GltfRefMap(HashMap<(Entity, String), Entity>)

We then update this map every frame based on the existing ref targets (and remove all ref targets each frame). Now component can lookup references when a blueprint is loaded. Note this means the references can only be accessed for the first frame. This seems fine since these references should only exist to create "normal" entity relations.

Convenience API for single-entity references

While we can get the references from the GltfRefMap, for the simplest case (a component containing only one entity reference), it would be nice to avoid as much boilerplate as possible. We can achieve this with another component, a trait, and a plugin:

// Component holding the identifier for the entity we want to reference.
// Private so it can only be accessed in Blender.
struct GltfRef<T: FromGltfRef>{
  target: String,
  _marker: PhantomData<T>,
};

// Trait to convert a referenced entity into the corresponding component.
// Public so users can define this conversion for their types.
pub trait FromGltfRef {
  fn from_ref(entity: Entity) -> Self;
}

// Registers the `GltfRef<T>` type and adds a system after updating the `GltfRefMap` to replace `GltfRef<T>` with `T::from_ref`.
pub struct GltfRefPlugin<T: FromGltfRef>;

Caveats

  • We can't handle every way of spawning Gltfs. We need to be able to differentiate between the same identifier used by different instances of the same Gltf/Blueprint. While this works for Blueprints (since Blueprints always have a BlueprintName component at their root), Gltfs can be spawned in all sorts of ways. Thankfully for the common case, we can handle Gltfs without blueprints by looking for the Handle<Scene> component.
  • Blueprints in blueprints cannot reference each other's entities. This would require a much more sophisticated naming scheme and for a v0 it might be overkill. I'm not sure how common Blueprints inside other blueprints is too.