Git Product home page Git Product logo

bones's People

Contributors

bayou-brogrammer avatar dependabot[bot] avatar erlend-sh avatar maxcwhitehead avatar nelson137 avatar pieking1215 avatar piturnah avatar rbran avatar zicklag avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

bones's Issues

Evaluate possibility of avoiding an `Arc` clone.

We might be able to just just pass references with a lifetime for acessing it, instead of cloning the Arc like we do here.


pub layout: Layout,
/// Cell containing the raw pointer to the resource's data
// TODO: Evaluate possibility of avoiding an `Arc` clone.
// We might be able to just just pass references with a lifetime for acessing it,
// instead of cloning the Arc like we do here.
pub cell: Arc<AtomicRefCell<*mut u8>>,
/// A function that may be called to clone the resource from one pointer to another.
pub clone_fn: unsafe extern "C" fn(*const u8, *mut u8),


This issue was generated by todo-issue based on a TODO comment in 27a70cd. It's been assigned to @zicklag because they committed the code.

Allow Changing Sprite Color

We want you to be able to set the sprite "color" or "tint": the color the sprite pixels are multiplied by, which is pure white ( no change ) by default.

This should be a simple change.

We just need to add a color field to Sprite here:

pub struct Sprite {
/// The sprite image handle.
pub image: Handle<Image>,
/// Whether or not the flip the sprite horizontally.
pub flip_x: bool,
/// Whether or not the flip the sprite vertically.
pub flip_y: bool,
}

And we need to set the Bevy sprite color from the bones sprite color here:

sprite.flip_x = bones_sprite.flip_x;
sprite.flip_y = bones_sprite.flip_y;

Alternative Entity Allocation Strategy

From chat:

It already removes dead entities from entities.iter_with(), and that's because it requires you to use the entities list to iterate, so it knows which ones are alive.

[17:57]
It just isn't automatic when using some_component.get() because it can't know which entities are alive without borrowing the entities.

[17:57]
Maybe we make some equivalent to some_component.get() that takes entities as an argument?

[17:57]
(edited)
Or maybe we do entities.get(some_component, entity) instead.

[17:58]
And then we recommend against using some_component.get() because it won't detect dead entities.

Yendor#2746
Yesterday at 18:14
how does bevy currently deal with this?

[18:14]
i think it might error out that entity doersnt exist

Zicklag
Yesterday at 18:14
Good question

[18:15]
I think the closest analogy to bones might be that all systems/components implicitly borrow Res<Entities> and therefore have access to the alive entities list, but that makes it impossible to borrow ResMut<Entities> in any system, and you are required to use Commands in order to create entities.

[18:16]
The tricky part might be how to allocate new entity IDs across multiple systems that might be running in parallel.

[18:17]
I don't think there's a way to do that deterministically.

[18:17]
Right now we don't do any multi-threading in bones, so maybe it's just not a problem.

[18:17]
(edited)
If we did multi-threading at all I think that might kill determinism gaurantees anyway.

Yendor#2746
Yesterday at 18:18
well thats the issue with bevy currently is that there is no determinism when running systems without explict system ordering

Zicklag
Yesterday at 18:18
Yeah, so if we say that we only guarantee determinism when not multi-threading...

[18:19]
Then we might be able to use an AtomicUsize to allocate new entities when you need to create them in a system.

[18:20]
Maybe we can just make the whole Entities resource completely thread safe.

[18:20]
So you can create and kill entities with only a Res<Entities>.

[18:21]
And then all of the Comp<SomComponent> borrows would have a handle to Entities that it could use to know when each entity is alive or not.

Yendor#2746
Yesterday at 18:30
Having the comp have access to entities is definitely a win there. I am a bit hesitant to hand the user the api to kill and create entities on demand

[18:32]
I think if we could hide that implementation and only use it within bones for components that would be ideal. Giving the user that much control over the system could lead to a foot gun scenario

Zicklag
Yesterday at 18:56
I am a bit hesitant to hand the user the api to kill and create entities on demand

[18:56]
I think that it's not that differet from the way we have it today.

[18:56]
We have to have a way to add and delete entities somehow.

[18:59]
We might be able to steal the entity allocator from [hecs](https://docs.rs/hecs), though we'd have to see if it was a good fit.

[18:59]
I think Bevy's is too baked into the grander ECS to be stealable by itself.

In short, the idea is to make Entites thread safe so that component storage can always know when an entity is alive and avoid returning dead entities.

This would fix #82.

Double-Check `World.maintain()` is Working Properly

There's been at least one, and maybe two cases where we've run into a killed entity getting re-created ( with a different generation and the same entity index ), and then reading stale components from the deleted entity. ( See also #82 )

I just realized, though, that calling world.maintain() every loop should at least remove the component storage for killed entities, so that may not actually be removing stale component data properly. We need to test and make sure it's doing what it should be.

Create custom system parameter to prevent needing to manualy `.borrow()` `AssetProvidersResource`.

/// The type of the [`AssetProviders`] resource.
// TODO: Create custom system parameter to prevent needing to manualy `.borrow()` `AssetProvidersResource`.
#[derive(Deref, DerefMut, Clone, TypeUlid)]
#[ulid = "01GNWY5HKV5JZQRKG20ANJXHCK"]


This issue was generated by todo-issue based on a TODO comment in 27a70cd. It's been assigned to @zicklag because they committed the code.

World Checksum

For troubleshooting determinism failures, it'd be good to have a way to checksum the world. We could do that by having an optional checksum function pointer in our untyped storage, similar to how we have an optional function pointer for cloning non-Copy types.

evaluate cost of initializing systems.

impl SessionRunner for DefaultSessionRunner {
fn step(&mut self, world: &mut World, stages: &mut SystemStages) -> SystemResult {
// TODO: evaluate cost of initializing systems.
//
// We need to find out how long it takes to initialize systems and decide whether or not it
// is worth finding a way to avoid doing it every step. The issue is finding a place to make
// sure the initialization happens for every system at least once.
stages.initialize_systems(world);


This issue was generated by todo-issue based on a TODO comment in 6164d35.

Consider Removing the `TypeUlid` Requirement for Components and Resources

Right now bones makes heavy use of the TypeUlid trait to identify types uniquely apart from their unstable Rust TypeIds.

I'm realizing, though, that it might be more appropriate to take the approach used by Bevy for non-Rust types, which is to require all components and resources to be registered with the world, at which point they are given a ComponentId or a ResourceId.

Additionally, at registration, I think we would allow specifying a type path of sorts, that would look like a Rust module path probably.

When registering a type, you provide it's layout and its module path, and it would fail to register if you had already inserted a type with the same module path.

The module paths give us a much more explanatory way to reference the types in future scripting APIs, too, because otherwise we would be using the ULID, which has absolutely no correlation to the actual type being referenced.

Finally, this would make it much easier to use components in Rust, because we don't have to add a TypeUlid to everything.

Luckily, this change wouldn't really break any existing code. It would just remove the requirement to have a TypeUlid. We'd have to try it out in the codebase, though, just to make sure we're not using TypeUlids in some context where a pre-registered component/resource ID isn't going to work very well, but I think we'd be fine.

Double-Check Caching in Docs CI Job

I think something might be wrong with our cache for the docs job in CI. It seems to take longer than it should, but I haven't looked into it yet. I could be wrong.

Error when using quinn_runtime_bevy with Bevy 0.9.1

Hello, I'm currently trying to use quinn_runtime_bevy with Bevy 0.9.1 but when I run my program it tells me thread 'IO Task Pool (0)' panicked at 'A IoTaskPool has not been initialized yet. Please call IoTaskPool::init beforehand.', [...] whereas when I don't use Bevy directly but bevy_tasks with version 0.8.1 it works fine.

I think the solution is to update bevy_tasks to the latest version for quinn_runtime_bevy.

investigate possible ways to avoid allocating vectors every frame for event lists.

mut keyboard_events: EventReader<KeyboardInput>,
) -> (bones::MouseInputs, bones::KeyboardInputs) {
// TODO: investigate possible ways to avoid allocating vectors every frame for event lists.
(
bones::MouseInputs {
movement: mouse_motion_events
.iter()
.last()


This issue was generated by todo-issue based on a TODO comment in 6164d35.

Re-evaluate `EcsError` variants.

Some of them may not be used anymore.


/// The types of errors used throughout the ECS.
// TODO: Re-evaluate `EcsError` variants.
// Some of them may not be used anymore.
#[derive(Debug, thiserror::Error)]
pub enum EcsError {
/// A resource was not initialized in the [`World`][crate::World] but the


This issue was generated by todo-issue based on a TODO comment in 27a70cd. It's been assigned to @zicklag because they committed the code.

Update To Slimmer Version of `bevy_simple_tilemap`

In order to get bones published to crates.io, we started depending on the released version of bevy_simple_tilemap which pulls in a lot of bevy features and dependencies that we don't need.

We have an open PR to address this: forbjok/bevy_simple_tilemap#9.

As soon as that merges and gets released we want to update so that we can strip out those dependencies again.

Update `bevy_simple_tilemap` when our PR is merged.

forbjok/bevy_simple_tilemap#9


serde_json = "1.0"
serde_yaml = "0.9"
# TODO: Update `bevy_simple_tilemap` when our PR is merged.
# https://github.com/forbjok/bevy_simple_tilemap/pull/9
bevy_prototype_lyon = "0.8"
# Disable default features to remove rayon par-iter, is not performant. Once https://github.com/forbjok/bevy_simple_tilemap/pull/17 is merged,
# switch off fork back to original crate.


This issue was generated by todo-issue based on a TODO comment in 27a70cd. It's been assigned to @zicklag because they committed the code.

Allow deriving `hash_fn` and `eq_fn` for `HasSchema`.

default_fn: #default_fn,
drop_fn: Some(<Self as #schema_mod::raw_fns::RawDrop>::raw_drop),
// TODO: Allow deriving `hash_fn` and `eq_fn` for `HasSchema`.
eq_fn: None,
hash_fn: None,
kind: #schema_mod::SchemaKind::Primitive(#schema_mod::Primitive::Opaque {
size: layout.size(),
align: layout.align(),


This issue was generated by todo-issue based on a TODO comment in 6164d35.

Prevent Reading Dead Entities From Component Storage

Say you do this.

world.run_system(
  |mut entities: ResMut<Entities>, positions: CompMut<Pos>| 
    // Create an entity
    let entity = entities.create();
    positions.insert(entity, default());

    // Kill that entity
    entities.kill(entity);
    
    // This works
    let pos = positions.get(entity).unwrap();
  });

The issue is that the component storage doesn't know which entities are alive. So if you want this to behave as you would probably expect, you must do something like this:

world.run_system(
  |mut entities: ResMut<Entities>, positions: CompMut<Pos>| 
    // Create an entity
    let entity = entities.create();
    positions.insert(entity, default());

    // Kill that entity
    entities.kill(entity);
    
    // Pre-check entity live-ness
    if entities.is_alive(entity) {
      let pos = positions.get(entity).unwrap();
    }
  });

And that's not cool.


Maybe we can store store the list of valid generations for entities in the component stores, and update that every frame. So the example above would still work counter-intuitively, but after one frame the component store would become aware of the entity being deleted?

That's still kind of confusing.

I'm not sure if we can make some sort of atomic bitset that can efficiently update the list of alive entities across all components. We could put an Arc<AtomicRefCell<Bitset>> or something like that to keep track of alive entities, and then all component storages have a reference to the alive entities, maybe. That might hurt performance because of the locking, but it would only have to lock inefficiently when you have mutable access to the Entities in a system, so maybe that wouldn't be a problem.

I think that any solution that improves the ergonomics here, and doesn't seriously impact performance should probably be considered, even if it isn't perfect, or the fastest thing on the planet.

I haven't done a lot of in-depth thinking about different ways to design the ECS that might remedy this issue. Most of the overall design idea was borrowed from Planck, but there might be some divergence we can make here that might be more efficient and fix the confusion, I'm not sure.

Attempt to refactor component store so we can avoid the two-step borrow process.

/// Get the components of a certain type
// TODO: Attempt to refactor component store so we can avoid the two-step borrow process.
//
// With resources we were able to avoid this step, but component stores are structured
// differently and might need more work.
pub fn get_cell<T: HasSchema>(&self) -> Result<AtomicComponentStore<T>, EcsError> {
let untyped = self.get_cell_by_schema_id(T::schema().id())?;


This issue was generated by todo-issue based on a TODO comment in 6164d35.

Replace ComponentStore functions with non-validating ones.

}
// TODO: Replace ComponentStore functions with non-validating ones.
//
// Right now functions like `insert`, `get`, and `get_mut` use the checked and panicing versions
// of the `untyped` functions. These functions do an extra check to see that the schema matches,
// but we've already validated that in the construction of the `ComponentStore`, so we should
// bypass the extra schema check for performance.


This issue was generated by todo-issue based on a TODO comment in 6164d35.

System Parameters & Overlapping Borrows

This issue is to discuss an ergonomics issue that I've faced both in Bones ECS and in Bevy ECS, and to explore whether or not there's a good solution.

The scenario is simple:

I have a custom system parameter named CollisionWorld that contains helper methods and logic around detecting collisions and manipulating the physics world.

As a part of that CollisionWorld parameter, I borrow the Transform components mutably. This allows me to, as a part of collision world methods like translate move entities, and also to get the entities positions, as is necessary for collision detection.

This causes an ergonomics problem when any the user wants to include both a CollisionWorld system param, and a CompMut<Transforms> system param, because that is a conflict: you have two mutable borrows of Transform components.

The current solution in my WIP branch in jumpy is to make the transforms: CompMut<Transform> field of CollisionWorld public. This allows you to access a borrow of the transforms, but it's not a perfect solution, and users are not going to expect that it's impossible to borrow both their own transforms argument, and the CollisionWorld.

Also, considering the situation where the CollisionWorld and another system parameter needs to borrow CompMut<Transform>, there is no good workaround.


This is partially just a limitation of the way borrowing works. The issue is "solved" in Bevy using ParamSets which usually feels un-ergonomic, but again, there's only so much we can do in Rust, where we must make our borrowing intentions clear at compile time. We can't have two mutable references to the Transform components at the same time. The only way around this is to delay the actual borrowing of the components, requiring an extra lock()/borrow() step.

Maybe we make a Defer system parameter, that wraps around other system parameters, deferring the borrow, and requiring an extra borrow() call to do runtime borrow checking later in the function.

In that case you would be allowed to have transforms: Defer<CompMut<Transform>> and collision_world: Defer<CollisionWorld> in your system params, but you would have to .borrow() them before you could use them, and you wouldn't be able to .borrow() them at the same time without a panic at runtime.


Finally, another alternative, is to have CollisionWorld use it's own component to represent the entity positions, and this component must be synchronized somehow with the Transform component. This is also a foot-gun because it's easy to forget to synchronize the values, and that there is in fact a separate CollisionWorld version of the entity position.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.