From 9704e15e40290500e1eec0a9dc806a77f9bce7a0 Mon Sep 17 00:00:00 2001 From: Nixon <43715558+nixonyh@users.noreply.github.com> Date: Fri, 3 Jul 2026 00:15:34 +0800 Subject: [PATCH 1/4] Migrate motiongfx off bevy_ecs onto typarena MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ActionWorld` (renamed `ActionTable`) no longer wraps a bevy_ecs `World`; it now composes `typarena::id::{GenId, IdGenerator}` for entity-style ids and `typarena::type_table::TypeTable` for heterogeneous per-action storage. `IdRegistry`'s bevy hook-based cleanup is replaced by an explicit `Cleanup` fn stored once per subject-id type in `Resources`, a hand-rolled type-keyed singleton map standing in for bevy's `Resource` storage. `pipeline::sample`'s multi-component query is replaced by a manual column probe driven from the `SampleMode` column, with `ColumnId`s for hot, non-generic columns cached on `ActionTable` to skip repeat `TypeId` hashing. The `action` module is split into `action/id_registry.rs` (`IdRegistry`, `UId`, `Cleanup`) and `action/table.rs` (`ActionTable` and its builders), with `action.rs` left holding the plain component/value types and re-exporting the public surface. `bevy_platform` is dropped in favor of `hashbrown` directly, and `MotionGfxManager` (in `bevy_motiongfx`) becomes a non-send resource instead of requiring `ActionTable` to be `Send + Sync` — `typarena`'s `TypeTable` makes no such guarantee, and forcing one would preclude storing non-thread-safe values in it for other consumers. --- Cargo.lock | 21 +- Cargo.toml | 1 + crates/bevy_motiongfx/README.md | 6 +- crates/bevy_motiongfx/src/controller.rs | 4 +- crates/bevy_motiongfx/src/manager.rs | 31 +- crates/motiongfx/Cargo.toml | 6 +- crates/motiongfx/src/action.rs | 402 +----------------- crates/motiongfx/src/action/id_registry.rs | 222 ++++++++++ crates/motiongfx/src/action/table.rs | 369 ++++++++++++++++ crates/motiongfx/src/lib.rs | 1 + crates/motiongfx/src/pipeline.rs | 135 +++++- crates/motiongfx/src/registry.rs | 2 +- crates/motiongfx/src/resources.rs | 43 ++ crates/motiongfx/src/timeline.rs | 12 +- crates/motiongfx/src/track.rs | 19 +- .../bevy_examples/examples/custom_ease.rs | 2 +- .../bevy_examples/examples/custom_interp.rs | 2 +- examples/bevy_examples/examples/easings.rs | 2 +- .../bevy_examples/examples/hello_world.rs | 2 +- examples/bevy_examples/examples/minimal.rs | 2 +- examples/bevy_examples/examples/recording.rs | 2 +- .../bevy_examples/examples/slide_basic.rs | 4 +- examples/bevy_examples/src/lib.rs | 2 +- 23 files changed, 851 insertions(+), 441 deletions(-) create mode 100644 crates/motiongfx/src/action/id_registry.rs create mode 100644 crates/motiongfx/src/action/table.rs create mode 100644 crates/motiongfx/src/resources.rs diff --git a/Cargo.lock b/Cargo.lock index 1b14957..4fc00d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2920,6 +2920,8 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ + "allocator-api2", + "equivalent", "foldhash 0.2.0", ] @@ -3446,11 +3448,11 @@ dependencies = [ name = "motiongfx" version = "0.3.0" dependencies = [ - "bevy_ecs", "bevy_math", - "bevy_platform", "field_path", + "hashbrown 0.17.1", "nonempty", + "typarena", ] [[package]] @@ -4730,6 +4732,12 @@ dependencies = [ "serde", ] +[[package]] +name = "sparse_map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea8f483b9159a7efadd9a82915dc40fdc9cfef7985651bbb83a8db20b12bf629" + [[package]] name = "spin" version = "0.10.0" @@ -5084,6 +5092,15 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +[[package]] +name = "typarena" +version = "0.1.0" +dependencies = [ + "hashbrown 0.16.1", + "indexmap", + "sparse_map", +] + [[package]] name = "typeid" version = "1.0.3" diff --git a/Cargo.toml b/Cargo.toml index c726168..994bcc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ bevy_color = { version = "0.19", default-features = false } # other field_path = "0.4.1" nonempty = { version = "0.12", default-features = false } +hashbrown = "0.17" peniko = { version = "0.6", default-features = false } vello = "0.9.0" winit = "0.30" diff --git a/crates/bevy_motiongfx/README.md b/crates/bevy_motiongfx/README.md index 5367b33..a0bf53b 100644 --- a/crates/bevy_motiongfx/README.md +++ b/crates/bevy_motiongfx/README.md @@ -40,7 +40,7 @@ use bevy_motiongfx::prelude::*; fn build_timeline( mut commands: Commands, - mut motiongfx: ResMut, + mut motiongfx: NonSendMut, ) { // Spawn the Entity. let entity = commands @@ -72,7 +72,7 @@ use bevy_motiongfx::prelude::*; fn build_timeline( mut commands: Commands, - mut motiongfx: ResMut, + mut motiongfx: NonSendMut, mut materials: ResMut> ) { // Create the asset. @@ -112,7 +112,7 @@ use bevy_motiongfx::prelude::*; fn build_timeline( mut commands: Commands, - mut motiongfx: ResMut, + mut motiongfx: NonSendMut, ) { // Build the timeline. let mut b = motiongfx.create_builder(); diff --git a/crates/bevy_motiongfx/src/controller.rs b/crates/bevy_motiongfx/src/controller.rs index fae2d8b..f7e8c30 100644 --- a/crates/bevy_motiongfx/src/controller.rs +++ b/crates/bevy_motiongfx/src/controller.rs @@ -18,7 +18,7 @@ impl Plugin for ControllerPlugin { } fn realtime_player_timing( - mut motiongfx: ResMut, + mut motiongfx: NonSendMut, q_timelines: Query<(&TimelineId, &RealtimePlayer)>, time: Res