You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In implementing custom components for plugins, I realized that the ECS implementation needs to allocate custom plugin components within the plugin's linear memory. We thus have two options:
continue using a further modified fork of hecs; or
implement our own ECS.
I am inclined to proceed with the latter because a custom ECS designed to work with the plugin system will be more flexible. Also, I have some ideas to solve #397 that we can integrate into the new ECS.
New ECS design
This is my plan for the new ECS:
Like EnTT, it will be based on sparse sets, whereas hecs uses archetypes. Sparse sets are easier and safer to implement than archetypes, and they have better performance characteristics when inserting/deleting components at a high frequency. (Our component-based event system does a lot of insertions and deletions, which convinces me that sparse sets are the best choice for Feather.)
It will support more flexibility with the borrow checker. In particular, components will have a stable location in memory, even if new entities and components are created. As a result, it should be possible to add/remove components and spawn entities inside a query loop, which will be convenient for some use cases in Quill.
The Component trait will not be implemented for all T; each component type needs to implement the trait instead. While this is less convenient in some areas, it prevents querying for types that are not components, like bundles. (We'll provide a derive macro for Component to avoid too much boilerplate.)
It will have built-in support for bundles and bundle accessors as an alternative implementation to HList and Plucker for components #388 and High-Level Entity Methods (WIP) #397. My vision is this: each entity type has its own Bundle struct, which is the set of components it spawns with. The ECS crate provides a derive macro that generates an accessor struct for the bundle that can be queried. The bundle accessor is a wrapper for EntityId that provides convenience methods to access components, and it can also include methods that access multiple components, like item_in_main_hand(). In code, this looks like:
#[derive(Bundle)]#[bundle(generate_accessor = "Player")]// generates the Player structpubstructPlayerBundle{/// another bundle containing default components for all living entities, like `Position` and `Health`/// (this emulates inheritance via composition)#[bundle(inherit)]base:LivingEntityBundle,inventory:Inventory,player_marker:PlayerMarker,}implPlayer{pubfnitem_in_main_hand(&self) -> &ItemStack{/* ... */}}// To spawn a player:
game.spawn_entity(PlayerBundle{base:LivingEntityBundle{
pos,
..Default::default()},
..Default::default()});// The accessor for the bundle can be queried using a new `query_as` function// to distinguish accessors from real components.for(entity_id, player):(EntityId,Player)in game.query_as::<Player,()>(){// the accessor provides methods to conveniently get componentsprintln!("{:?}", player.position());// it can also provide convenience functions that access multiple components// (HeldItem and Inventory in this case)println!("Player is holding {:?}", player.item_in_main_hand());}// Accessors also work with abstract bundles like LivingEntityfor(entity_id, entity):(EntityId,LivingEntity)in game.query_as::<LivingEntity,()>(){println!("{:?}", entity.position());}
I opened this issue to collect feedback in the proposal, in the hope that we can resolve any issues with it before I implement something we don't want. So feedback is welcome from all.
In implementing custom components for plugins, I realized that the ECS implementation needs to allocate custom plugin components within the plugin's linear memory. We thus have two options:
hecs; orI am inclined to proceed with the latter because a custom ECS designed to work with the plugin system will be more flexible. Also, I have some ideas to solve #397 that we can integrate into the new ECS.
New ECS design
This is my plan for the new ECS:
hecsuses archetypes. Sparse sets are easier and safer to implement than archetypes, and they have better performance characteristics when inserting/deleting components at a high frequency. (Our component-based event system does a lot of insertions and deletions, which convinces me that sparse sets are the best choice for Feather.)Componenttrait will not be implemented for allT; each component type needs to implement the trait instead. While this is less convenient in some areas, it prevents querying for types that are not components, like bundles. (We'll provide a derive macro forComponentto avoid too much boilerplate.)Bundlestruct, which is the set of components it spawns with. The ECS crate provides a derive macro that generates an accessor struct for the bundle that can be queried. The bundle accessor is a wrapper forEntityIdthat provides convenience methods to access components, and it can also include methods that access multiple components, likeitem_in_main_hand(). In code, this looks like:I opened this issue to collect feedback in the proposal, in the hope that we can resolve any issues with it before I implement something we don't want. So feedback is welcome from all.