https://github.com/robertdodd/bevy_reflect_utils
A small, plugin-less utility library making it easier to work with reflection in bevy.
https://github.com/robertdodd/bevy_reflect_utils
bevy bevy-engine game-development gamedev gui ui
Last synced: 8 months ago
JSON representation
A small, plugin-less utility library making it easier to work with reflection in bevy.
- Host: GitHub
- URL: https://github.com/robertdodd/bevy_reflect_utils
- Owner: robertdodd
- License: apache-2.0
- Created: 2024-06-24T02:47:37.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2024-07-05T05:21:20.000Z (almost 2 years ago)
- Last Synced: 2025-01-30T18:48:22.607Z (over 1 year ago)
- Topics: bevy, bevy-engine, game-development, gamedev, gui, ui
- Language: Rust
- Homepage:
- Size: 104 KB
- Stars: 4
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE-APACHE
Awesome Lists containing this project
README
# Bevy Reflect Utils
A small, plugin-less utility library making it easier to work with reflection
in [bevy](https://bevyengine.org/).
---
## Development
> [!WARNING]
> UNDER DEVELOPMENT, EXPECT BREAKING CHANGES
## Motivation
This library was written to build re-usable UI widgets.
Reflection code is usually very verbose and hard to follow. The functions in this library only require a `ReflectTarget`
pointing to a field and an `&mut World`, and return an easy-to-handle `Result`.
## Simple Example
```rust
use bevy::prelude::*;
use bevy_reflect_utils::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_resource::()
.add_systems(Startup, setup)
// IMPORTANT: The types you want to operate on must be registered
.register_type::()
.run();
}
// IMPORTANT: The types you operate on must derive `Reflect`
#[derive(Resource, Reflect, Debug, Default)]
#[reflect(Resource, Default, Debug)]
pub struct ExampleResource {
value: bool,
}
fn setup(world: &mut World) {
// Define a `ReflectTarget` pointing to `ExampleResource::value`
let target = ReflectTarget::new_resource::("value");
// Read the initial value
let initial_value = target.read_value::(world).unwrap();
println!("initial value: {}", initial_value);
// Set a new value
target.set_value(world, !initial_value).unwrap();
// Read the new value
let new_value = target.read_value::(world).unwrap();
println!("new value: {}", new_value);
}
```
This example will print the following:
```
initial value: false
new value: true
```
You can run this same example with:
```shell
cargo run --example simple
```
## Recommended Usage
Use `Commands` to perform reflection when possible. Use exclusive systems
when you can't avoid it.
For example, to update a value when a button is clicked:
```rust
fn handle_click_events(mut commands: &mut Commands) {
// if button was clicked...
let target = ReflectTarget::new_resource::("value");
commands.queue(move |world: &mut World| {
match target.set_value(world, true) {
Ok(ReflectSetSuccess::Changed) => info!("Success"),
Ok(ReflectSetSuccess::NoChanges) => warn!("Value not changed"),
Err(err) => error!("{err:?}"),
}
});
}
```
## `ReflectTarget` Target Types
Create a `ReflectTarget` referencing a field on an `Entity` and `Component`:
```rust
let target = ReflectTarget::new_component::(entity, "value");
```
Create a `ReflectTarget` referencing a field on a `Resource`:
```rust
let target = ReflectTarget::new_resource::("value");
```
## `ReflectTarget` Operations
`ReflectTarget` provides the following operations:
### Read Value
> Requires knowing the underlying type.
```rust
target.read_value::(world);
```
Return Value:
```rust
Result
```
### Set Value
> Requires knowing the underlying type.
```rust
target.set_value(world, 0.5);
```
Return Value:
```rust
Result
```
### Toggle Between Enum Variant
Toggle between the previous/next enum variants.
Also works with data variants, provided the variant implements and reflects `Default`.
> Does not require knowing the underlying type.
> **Important:** Does not wrap around when reaching the beginning or end of
> the list of variants.
```rust
target.toggle_enum_variant(world, EnumDirection::Forward);
target.toggle_enum_variant(world, EnumDirection::Backward);
```
Return Value:
```rust
Result
```
### Read Enum Variant Name
> Does not require knowing the underlying type.
```rust
target.read_enum_variant_name(world);
```
Return Value:
```rust
Result
```
### Read Serialized Value
> Does not require knowing the underlying type.
```rust
target.read_value_serialized(world);
```
Return Value:
```rust
Result
```
Example:
```rust
Ok("{\"f32\":0.5}")
```
### Set Serialized Value
> Does not require knowing the underlying type.
```rust
target.set_value_serialized(world, "{\"f32\":0.5}".to_string());
```
Return Value:
```rust
Result
```
### Partial Equality Against a Serialized Value
> Does not require knowing the underlying type.
```rust
target.partial_eq_serialized(world, "{\"f32\":0.5}".to_string());
```
Return Value:
```rust
Result
```
## Errors
The primary error type is [`ReflectError`](https://github.com/robertdodd/bevy_reflect_utils/blob/master/src/errors.rs).
## Set Value Return Type
Most operations that set a value have the following return type:
```rust
Result
```
Where [`ReflectSetSuccess`](https://github.com/robertdodd/bevy_reflect_utils/blob/master/src/errors.rs)
allows you know whether the field was changed by the operation:
```rust
pub enum ReflectSetSuccess {
Changed,
NoChanges,
}
```
## Compatible Bevy versions
| `bevy_reflect_utils` | `bevy` |
|:---------------------|:-------|
| `0.4` | `0.16` |
| `0.3` | `0.15` |
| `0.2` | `0.14` |
| `0.1` | `0.13` |
## License
Dual-licensed under either of
- Apache License, Version 2.0,
([LICENSE-APACHE](https://github.com/robertdodd/bevy_round_ui/blob/master/LICENSE-APACHE) or
https://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](https://github.com/robertdodd/bevy_round_ui/blob/master/LICENSE-MIT) or
https://opensource.org/licenses/MIT)
at your option.
## Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as
defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.