jamiebrynes7/spatialos-sdk-rs

Add some sort of Entity Builder API

jamiebrynes7 opened this issue ยท 4 comments

It's very idiomatic to use the builder pattern in Rust and this pattern has worked well for defining entity templates in the past/

#6 added an Entity type which can gather component data. Currently it's only used for entity creation, I'm not sure at this point what other APIs would benefit from accessing this functionality.

One thing that other EntityBuilder APIs that I've seen is auto-building the Entity ACL component for you (as its very verbose) through exposing APIs like:

add_component<C: Component, S: Into<String>>(&mut self, component: C, layer: &S);
set_read_acl(&mut self, layers: &[String]);

and adding special methods for well known SpatialOS components:

set_position<S: Into<String>>(&mut self, x: f64, y: f64, z: f64, layer: &S);
set_persistence(&mut self, is_persistent: bool);

which allow you to build entities more fluently than the current method, which can be verbose.

Current entity code:

let mut entity = Entity::new();
    entity.add(improbable::Position {
        coords: improbable::Coordinates {
            x: 10.0,
            y: 12.0,
            z: 0.0,
        },
    });
    entity.add(improbable::EntityAcl {
        read_acl: improbable::WorkerRequirementSet {
            attribute_set: vec![improbable::WorkerAttributeSet {
                attribute: vec!["rusty".into()],
            }],
        },
        component_write_acl: BTreeMap::new().tap(|writes| {
            writes.insert(
                improbable::Position::ID,
                improbable::WorkerRequirementSet {
                    attribute_set: vec![improbable::WorkerAttributeSet {
                        attribute: vec!["rusty".into()],
                    }],
                },
            );
        }),
    });

Better entity code

let entity = EntityBuilder::new()
	.set_position(10.0, 12.0, 0.0, RUST_WORKER_LAYER)
	.set_persistence(true)
	.set_read_acl(&[RUST_WORKER_LAYER, RUST_CLIENT_LAYER])
	.build();

There's also the consideration that there is a such a thing as an invalid entity and you can protect a user from those by throwing errors at build() rather than when SpatialOS tries to load the snapshot or handles a CreateEntity command.

I think there are two levels of things we can do to make this better:

  • Have helper methods on the entity builder, as you suggest.
  • Add helper methods on the component types themselves that make them easier to work with.

Currently, the latter option isn't really possible, and is part of what #56 will enable. I do really like the idea of specifying the layer for a component when it's added, that would greatly reduce the boilerplate when building an entity ๐Ÿ‘

Will open a WIP PR for this once #80 is merged! ๐ŸŽ‰