Skip to content

refactor: bevy #882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft

refactor: bevy #882

wants to merge 3 commits into from

Conversation

andrewgazelka
Copy link
Member

@andrewgazelka andrewgazelka commented Apr 22, 2025

This is an experiment

Related: valence-rs/valence#685

Why switch from flecs to Bevy

Why stay in flecs

  • More performant
  • Has ability of us adding scripting language on top in non-Rust
  • Overall better design (at least for non-Rust). I expect flecs to always be ahead of Bevy in terms of its progress. Also less of a chance we get roadblocked by some Bevy design feature.

Issues that need to be resolved:

  • in Bevy not everything is an entity. This makes some things annoying. For instance, I am unsure how system-order (which is core to hyperion) will work

use std::collections::{BTreeSet, HashMap, HashSet};
use derive_more::Constructor;
use flecs_ecs::{
core::{
Builder, ComponentOrPairId, Entity, EntityView, EntityViewGet, IdOperations, QueryAPI,
QueryBuilderImpl, SystemAPI, flecs, flecs::DependsOn,
},
macros::Component,
prelude::{Module, World},
};
/// sort by depth and then by id
#[derive(PartialOrd, Ord, PartialEq, Eq, Debug)]
struct OrderKey {
depth: usize,
id: Entity,
}
#[derive(Default)]
struct DepthCalculator {
depths: HashMap<Entity, usize, rustc_hash::FxBuildHasher>,
}
impl DepthCalculator {
fn calculate_depth(&mut self, view: EntityView<'_>) -> usize {
if let Some(depth) = self.depths.get(&view.id()) {
return *depth;
}
// todo: add stackoverflow check
let mut entity_depth = 0;
view.each_target::<DependsOn>(|depends_on| {
let tentative_depth = self.calculate_depth(depends_on) + 1;
entity_depth = entity_depth.max(tentative_depth);
});
self.depths.insert(view.id(), entity_depth);
entity_depth
}
fn on_update_depth(&mut self, world: &World) -> usize {
let view = world
.component_id::<flecs::pipeline::PostUpdate>()
.entity_view(world);
self.calculate_depth(view)
}
}
#[derive(
Component,
Constructor,
Copy,
Clone,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord
)]
#[must_use]
#[meta]
pub struct SystemOrder {
value: u16,
}
impl SystemOrder {
#[must_use]
pub const fn value(&self) -> u16 {
self.value
}
pub fn of(entity: EntityView<'_>) -> Self {
entity.get::<&Self>(|order| *order)
}
}
fn calculate(world: &World) {
let mut depth_calculator = DepthCalculator::default();
let mut map = BTreeSet::new();
// get all depths for systems
world
.query::<()>()
.with::<flecs::system::System>()
.build()
.each_entity(|entity, ()| {
let depth = depth_calculator.calculate_depth(entity);
map.insert(OrderKey {
depth,
id: entity.id(),
});
});
// handle all observers
world
.query::<()>()
.with::<flecs::Observer>()
.build()
.each_entity(|entity, ()| {
let depth = depth_calculator.on_update_depth(world);
map.insert(OrderKey {
depth,
id: entity.id(),
});
});
// assert all entities are unique
assert_eq!(
map.len(),
map.iter().map(|x| x.id).collect::<HashSet<_>>().len()
);
for (idx, value) in map.into_iter().enumerate() {
let idx = u16::try_from(idx).expect("number of systems exceeds u16 (65536)");
let entity = value.id.entity_view(world);
entity.set(SystemOrder::new(idx));
}
}
#[derive(Component)]
pub struct SystemOrderModule;
impl Module for SystemOrderModule {
fn module(world: &World) {
world.component::<SystemOrder>().meta();
world
.observer::<flecs::OnAdd, ()>()
.with::<flecs::system::System>()
.run(|it| calculate(&it.world()));
world
.observer::<flecs::OnAdd, ()>()
.with::<flecs::Observer>()
.run(|it| calculate(&it.world()));
}
}

system-order is used for re-ordering packets once they reach the proxy. I definitely feel like flecs has fewer things that would hard roadblock us... however sadly flecs rust has some quality of life issues that can be annoying

Copy link

Benchmark Results for general

ray_intersection/aabb_size_0.1                     [  33.7 ns ...  33.6 ns ]      -0.29%
ray_intersection/aabb_size_1                       [  33.4 ns ...  33.3 ns ]      -0.23%
ray_intersection/aabb_size_10                      [  24.8 ns ...  24.7 ns ]      -0.26%
ray_intersection/ray_distance_1                    [  13.5 ns ...  13.5 ns ]      -0.06%
ray_intersection/ray_distance_5                    [  13.5 ns ...  13.5 ns ]      -0.02%
ray_intersection/ray_distance_20                   [  13.6 ns ...  13.5 ns ]      -0.12%
overlap/no_overlap                                 [  24.5 ns ...  24.8 ns ]      +1.25%
overlap/partial_overlap                            [  24.7 ns ...  24.6 ns ]      -0.15%
overlap/full_containment                           [  22.5 ns ...  22.5 ns ]      -0.11%
point_containment/inside                           [   4.9 ns ...   4.9 ns ]      +0.09%
point_containment/outside                          [   4.4 ns ...   4.4 ns ]      +0.06%
point_containment/boundary                         [   4.9 ns ...   4.9 ns ]      -0.06%

Comparing to d817614

Copy link

Benchmark Results for general

ray_intersection/aabb_size_0.1                     [  38.4 ns ...  36.2 ns ]      -5.72%
ray_intersection/aabb_size_1                       [  34.9 ns ...  36.5 ns ]      +4.74%
ray_intersection/aabb_size_10                      [  24.8 ns ...  25.8 ns ]      +4.04%
ray_intersection/ray_distance_1                    [  14.0 ns ...  13.8 ns ]      -1.75%
ray_intersection/ray_distance_5                    [  15.5 ns ...  14.3 ns ]      -7.87%
ray_intersection/ray_distance_20                   [  14.1 ns ...  14.1 ns ]      +0.20%
overlap/no_overlap                                 [  24.2 ns ...  24.4 ns ]      +0.86%
overlap/partial_overlap                            [  24.6 ns ...  24.6 ns ]      +0.02%
overlap/full_containment                           [  22.5 ns ...  22.5 ns ]      -0.17%
point_containment/inside                           [   4.9 ns ...   4.9 ns ]      +0.22%
point_containment/outside                          [   4.4 ns ...   4.4 ns ]      -0.18%
point_containment/boundary                         [   5.0 ns ...   5.0 ns ]      +0.11%

Comparing to 4c402d0

Copy link

Benchmark Results for general

ray_intersection/aabb_size_0.1                     [  33.7 ns ...  33.8 ns ]      +0.22%
ray_intersection/aabb_size_1                       [  33.5 ns ...  33.6 ns ]      +0.19%
ray_intersection/aabb_size_10                      [  24.6 ns ...  24.6 ns ]      -0.27%
ray_intersection/ray_distance_1                    [  13.4 ns ...  13.5 ns ]      +0.53%
ray_intersection/ray_distance_5                    [  13.6 ns ...  13.6 ns ]      -0.23%
ray_intersection/ray_distance_20                   [  13.5 ns ...  13.5 ns ]      +0.16%
overlap/no_overlap                                 [  24.5 ns ...  24.7 ns ]      +0.86%
overlap/partial_overlap                            [  24.7 ns ...  24.6 ns ]      -0.24%
overlap/full_containment                           [  22.6 ns ...  22.5 ns ]      -0.20%
point_containment/inside                           [   4.9 ns ...   4.9 ns ]      -0.11%
point_containment/outside                          [   4.4 ns ...   4.4 ns ]      +0.16%
point_containment/boundary                         [   4.9 ns ...   4.9 ns ]      +0.02%

Comparing to 4c402d0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant