Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

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: 2 months ago
JSON representation

A small, plugin-less utility library making it easier to work with reflection in bevy.

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`.

The [menu](https://github.com/robertdodd/bevy_reflect_utils/blob/master/examples/menu.rs) (`cargo run --example menu`)
example demonstrates a few simple UI widgets used on a settings page.

## 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.add(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.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.