{"id":20521368,"url":"https://github.com/zeenobit/bevy_kindly","last_synced_at":"2025-10-20T08:57:00.079Z","repository":{"id":60817200,"uuid":"545778314","full_name":"Zeenobit/bevy_kindly","owner":"Zeenobit","description":"Minimalistic implementation of entity kinds for Bevy ECS.","archived":false,"fork":false,"pushed_at":"2023-11-02T21:40:00.000Z","size":67,"stargazers_count":18,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T16:40:07.889Z","etag":null,"topics":["bevy-engine","ecs","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Zeenobit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-05T00:49:13.000Z","updated_at":"2024-03-13T23:23:21.000Z","dependencies_parsed_at":"2022-10-05T07:06:21.249Z","dependency_job_id":"982f15b7-d667-4373-ac44-9cec32268b30","html_url":"https://github.com/Zeenobit/bevy_kindly","commit_stats":{"total_commits":32,"total_committers":1,"mean_commits":32.0,"dds":0.0,"last_synced_commit":"786c41e4196cb61fcb46229bd4d4dcb99079d186"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zeenobit%2Fbevy_kindly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zeenobit%2Fbevy_kindly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zeenobit%2Fbevy_kindly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Zeenobit%2Fbevy_kindly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Zeenobit","download_url":"https://codeload.github.com/Zeenobit/bevy_kindly/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248811748,"owners_count":21165317,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bevy-engine","ecs","rust"],"created_at":"2024-11-15T22:28:31.816Z","updated_at":"2025-10-20T08:56:59.976Z","avatar_url":"https://github.com/Zeenobit.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Bevy 💖 Kindly\n\n---\n### ⚠️ Warning\nDeprecated in favor of the more simplified and up-to-date version [Moonshine Kind](https://github.com/Zeenobit/moonshine_kind).\n\n---\n\nThis crate is a minimalistic implementation of [Kinded Entities](https://github.com/bevyengine/bevy/issues/1634) for Bevy game engine.\n\nIn summary, it allows the user to define, construct, and query entities of different kinds. Each kind of entity is defined with an expected set of components, and a specialized command queue which may be extended with commands for specific kinds of entities.\n\nThis means that instead of writing this... 😵‍💫\n```rust\n#[derive(Component)]\nstruct Friends(Vec\u003cEntity\u003e);\n\n#[derive(Component)]\nstruct Inventory {\n  items: Vec\u003cEntity\u003e,\n  buckets: HashMap\u003cEntity, Vec\u003cEntity\u003e\u003e,\n}\n```\n\nYou can write this... 😌\n```rust\n#[derive(Component)]\nstruct Friends(Vec\u003cPerson\u003e);\n\n#[derive(Component)]\nstruct Inventory {\n  items: Vec\u003cItem\u003e,\n  buckets: HashMap\u003cBucket, Vec\u003cItem\u003e\u003e,\n}\n```\n\nWhere `Person`, `Item`, and `Bucket` can be defined as unique entity kinds.\n\nThe end result is increased readability because it's much easier to distinguish references to different kinds of entities. It also allows the user to make safer assumptions about the existence of some expected components on a specific kind of entity.\n\n### Integration\n\nAdd to `Cargo.toml` (replace * with your desired version):\n```\n[dependencies]\nbevy_kindly = \"*\"\n```\n\n### Usage\n\nTo define an entity kind, you can derive `EntityKind`:\n```rust\n#[derive(EntityKind)]\n#[default_components(Friends)] // Optional: Components inserted into every `Person` by default\n#[components(Name, Age)]       // Optional: Components that must be provided to spawn a `Person`\nstruct Person(Entity);\n```\n\nYou may also use `default_bundle` and `bundle` to define a bundle yourself:\n```rust\n#[derive(EntityKind)]\n#[default_bundle(DefaultPersonBundle)] // Optional: Bundle inserted into every `Person` by default\n#[bundle(PersonBundle)]                // Optional: Bundle that must be provided to spawn a `Person`\nstruct Person(Entity);\n\n#[derive(Bundle, Default)]\nstruct DefaultPersonBundle {\n  friends: Friends,\n};\n\n#[derive(Bundle)]\nstruct PersonBundle {\n  name: Name,\n  age: Age,\n};\n```\n\nNote that you may either define `bundle` or `components`, not both. The same rule applies to `default_bundle` and `default_components`.\n\nAlternatively, you could also just implement `EntityKind` trait manually:\n```rust\nstruct Person(Entity);\n\nimpl EntityKind for Person {\n  type DefaultBundle = (Friends,);\n  type Bundle = (Name, Age);\n  \n  // This function is called by the library to create new instances of this kind, but only when it's actually safe to do so\n  // User should not be calling this function directly, unless in special cases.\n  unsafe fn from_entity_unchecked(entity: Entity) -\u003e Self {\n    Self(entity)\n  }\n  \n  fn entity(\u0026self) -\u003e Entity {\n    self.0\n  }\n}\n```\n\nEntities can be spawned with a kind in 3 separate ways, all of which are identical in underlying implementation.\nThey can either be spawned using `spawn_with_kind\u003cT\u003e`:\n```rust\ncommands.spawn_with_kind::\u003cPerson\u003e((\"Alice\".into(), Age(25)));\n```\nOr using `insert_kind\u003cT\u003e` if the entity is already spawned, or if the entity may have multiple kinds:\n```rust\ncommands.entity(entity).insert_kind::\u003cPerson\u003e((\"Alice\".into(), Age(25)));\n```\nOr by just inserting a `KindBundle\u003cT\u003e` directly:\n```rust\ncommands.entity(entity).insert(KindBundle::\u003cOwner\u003e::new((\"Alice\".into(), Age(25))));\n```\nNotice how you must provide the required components in order to mark the entity as the given kind.\n\nAny system can filter queries using `WithKind\u003cT\u003e` and `EntityWithKind\u003cT\u003e` world queries.\n`EntityWithKind\u003cT\u003e` is designed to function like an `Entity`, but with a kind.\n`WithKind\u003cT\u003e` can be used as a query filter when the actual entity is not needed.\n\nFor example:\n```rust\nfn do_something_with_people_and_their_friends(query: Query\u003c(EntityWithKind\u003cPerson\u003e, \u0026Friends)\u003e) {\n  for (person, friends) in \u0026query {\n    let person: Person = person.get();\n    ...\n    let entity: Entity = person.entity();\n    ...\n  }\n}\n```\n\nAdditionally, any entity kind can have special commands that may only be invoked on entities of that kind.\nThis is done by extending `EntityKindCommands\u003cT\u003e`:\n\n```rust\ntrait PersonCommands {\n    // Only people can be friends with each other\n    fn add_friend(self, friend: Person);\n}\n\nimpl PersonCommands for \u0026mut EntityKindCommands\u003c'_, '_, '_, Person\u003e {\n    fn add_friend(self, friend: Person) {\n        let person = self.get();\n        self.commands().add(move |world: \u0026mut World| {\n            // These unwraps are safe(er), because every `Person` entity has a `Friends` component\n            world.get_mut::\u003cFriends\u003e(person.entity()).unwrap().0.push(friend);\n            world.get_mut::\u003cFriends\u003e(friend.entity()).unwrap().0.push(person);\n        });\n    }\n}\n```\n\nThese commands can then be invoked on any entity with kind:\n```rust\nlet alice = commands.spawn_with_kind::\u003cPerson\u003e((\"Alice\".into(), Age(25))).get();\ncommands.spawn_with_kind::\u003cPerson\u003e((\"Bob\".into(), Age(30))).add_friend(alice);\n```\nOr:\n```rust\nlet alice = commands.spawn_with_kind::\u003cPerson\u003e((\"Alice\".into(), Age(25))).get();\nlet bob = commands.spawn_with_kind::\u003cPerson\u003e((\"Bob\".into(), Age(30))).get();\ncommands.with_kind(\u0026alice).add_friend(bob);\n```\n\nAny `EntityRef` may also be \"casted\" safely into a kind using `try_with_kind`:\n```rust\nlet person: Option\u003cPerson\u003e = world.entity(entity).try_with_kind::\u003cPerson\u003e();\n```\n\n### Cost\n\nThis implementation works by adding a private component with some `PhantomData\u003cT\u003e` to every entity with kind `T`.\nThis component is then checked or used as filter by systems as needed in order to guarantee kind correctness.\nBeyond that, there is no other runtime cost associated with this. There is no need to register any additional systems or types.\n\n### Examples\n\nIn `examples` directory, you can find some examples which outline some use cases:\n\nNote: It is recommended that you look at `person.rs` and `navigation.rs` before going through other examples.\n\n- [examples/person.rs](https://github.com/Zeenobit/bevy_kindly/blob/master/examples/person.rs)\u003c/br\u003e\n  Demonstrates how to use `EntityKind` to create readable and safe references to entities.\n- [examples/navigation.rs](https://github.com/Zeenobit/bevy_kindly/blob/master/examples/navigation.rs)\u003c/br\u003e\n  Demonstrates how entities can be queried by `EntityKind` to make strong guarantees about components.\n- [examples/multiple.rs](https://github.com/Zeenobit/bevy_kindly/blob/master/examples/multiple.rs)\u003c/br\u003e\n  Demonstrates how entities can have multiple kinds.\n- [examples/cast.rs](https://github.com/Zeenobit/bevy_kindly/blob/master/examples/cast.rs)\u003c/br\u003e\n  Demonstrates how to cast entities between different kinds.\n\n### Limitations\n\n- There is no safety against direct removal of entity kind components.\n- If an entity has multiple kinds, any intersection of the expected components can cause unwanted overrides.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeenobit%2Fbevy_kindly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzeenobit%2Fbevy_kindly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeenobit%2Fbevy_kindly/lists"}