Skip to content
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

Scenes Example isn't Recognizing Vec3 Type #5745

Closed
Carter0 opened this issue Aug 19, 2022 · 9 comments
Closed

Scenes Example isn't Recognizing Vec3 Type #5745

Carter0 opened this issue Aug 19, 2022 · 9 comments
Labels
A-Scenes Serialized ECS data stored on the disk C-Bug An unexpected or incorrect behavior D-Trivial Nice and easy! A great choice to get started with Bevy

Comments

@Carter0
Copy link
Contributor

Carter0 commented Aug 19, 2022

Bevy version

I just pulled down main yesterday.

What you did

I ran the bevy scene example with cargo run --example scene.

What went wrong

I get this error and it prevents any of the data in the ron file from being uploaded.

WARN bevy_asset::asset_server: encountered an error while loading an asset: No registration found for glam::vec3::Vec3

If I delete the transform component from the ron file then things seem to work as usual and I get

2022-08-19T15:50:03.689570Z  INFO scene:   Entity(3)
2022-08-19T15:50:03.689615Z  INFO scene:     ComponentA: { x: 3 y: 2 }

2022-08-19T15:50:03.689641Z  INFO scene:   Entity(4)
2022-08-19T15:50:03.689652Z  INFO scene:     ComponentA: { x: 3 y: 4 }
@Carter0 Carter0 added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Aug 19, 2022
@MrGVSV
Copy link
Member

MrGVSV commented Aug 19, 2022

This is because the scene file is using the incorrect type name. It should be glam::f32::vec3::Vec3 not glam::vec3::Vec3. Same goes for glam::quat::Quat which should be glam::f32::scalar::quat::Quat.

@MrGVSV MrGVSV added D-Trivial Nice and easy! A great choice to get started with Bevy A-Scenes Serialized ECS data stored on the disk and removed S-Needs-Triage This issue needs to be labelled labels Aug 19, 2022
@afonsolage
Copy link
Contributor

This isn't something that should be caught by CI?

@DJMcNab
Copy link
Member

DJMcNab commented Aug 20, 2022

Do we document that scenes shouldn't be used across compiler versions - I can't find this documented anywhere?

If not, we shouldn't be using type_name anyway.

Frankly, this is the first time I've looked at our reflect code, and I'm slightly horrified by our gung-ho usage of type_name.

@cart
Copy link
Member

cart commented Aug 20, 2022

To my knowledge, type_name is our best and only option when it comes to identifying a type across compiler versions.

We could mitigate this by adding CI to detect type_name changes early and couple that with either an alias database or migration tools. Not a full solution, but probably would work pretty well in practice, given how rare rustc-driven type_name changes are. This is literally the first time this has come up, and it may have been because glam actually changed their module path.

The alternatives (manually defining TypeUuid on every reflected type, parsing rust files in a pre-build step and generating our own ids, etc) are not reasonable in the context of "reflect everything". Thats a level of complexity I'm not willing to foist on users.

@DJMcNab called out that module_path exists, which might work for our scenarios. When I wrote Bevy Reflect, I wasn't aware of that api. However it doesn't handle the name of the type itself (which would need to either be extracted from type_name or within the Reflect proc macro). Notably, the macro approach won't handle generic type names properly. Theres also the question of the static lifetime, which could be lost if we need runtime string ops.

So yeah, if we can find a "better" path, we should take it. But at the time, type_name was the only real viable option from my perspective. And from my perspective, its still our best option.

@PROMETHIA-27 had an idea on discord that might work though!

@PROMETHIA-27
Copy link
Contributor

Potential solution for a PR:

  • use the module_path macro, which provides a stable module path
  • create a new trait, ReflectTypeName, which has a function type_name() to return the module-path-qualified type name, with generic parameters
  • this trait gets derived alongside Reflect, so no extra derives needed.
  • For simple types, it just returns module_path + the ident of the type name
  • For generic types, it returns module_path + ident of the type name + <ReflectTypeName of each parameter>
    • To do this, it also needs to put a constraint on each parameter to implement ReflectTypeName

Upsides:

  • Perfectly stable
  • Allows us to completely forgo type_name()

Downsides:

  • No lifetimes are represented in the type names (meh)
  • Reflect is now even more infectious. Any type parameters to a reflected type must be reflect as well in order for that type to have a reflectable type name. Maybe introduce a #[only_reflect_name] helper macro in the case that something needs a ReflectTypeName impl but can't be reflected fully?

@cart
Copy link
Member

cart commented Aug 20, 2022

Actually, even if we do find a better path forward, if we continue using type names / module paths as identifiers, we should do a dump of the default Bevy type registry for the last stable version, compare that to a dump of the type registry for main, and have some sort of policy around defining aliases / migrations.

(validated in CI)

@cart
Copy link
Member

cart commented Aug 20, 2022

ReflectTypeName

I think I like this. It also has the benefit (or downside, depending on your perspective), of enabling library authors to define their own type_names. Ex: maybe they don't want to deal with migrations when the module changes, so they make it return my_lib::MyType instead of my_lib::some::path::MyType. It would open to doors to unstructured names like BlAH@blah blah, but we could add validation if we really want to.

If this is a pattern we want to encourage, we could add a convenience to the Reflect derive like:

#[derive(Reflect)]
#[reflect_type_name("my_crate::Foo")]
struct Foo {
}

@cart
Copy link
Member

cart commented Aug 20, 2022

We could also use that to "force" good / short / stable type names for core types (ex: Vec3 instead of glam::f32::vec3::Vec3)

@cart
Copy link
Member

cart commented Aug 20, 2022

Although thats also what the short_name system was designed for. We might still want to encourage module-like paths for ReflectTypeName, then use short_name where appropriate.

@bors bors bot closed this as completed in 04538fd Aug 20, 2022
maccesch pushed a commit to Synphonyte/bevy that referenced this issue Sep 28, 2022
…m the logs (bevyengine#5751)

# Objective
- Fixes bevyengine#5745.

## Solution
- Changes the Vec3 and Quat types.
james7132 pushed a commit to james7132/bevy that referenced this issue Oct 28, 2022
…m the logs (bevyengine#5751)

# Objective
- Fixes bevyengine#5745.

## Solution
- Changes the Vec3 and Quat types.
ItsDoot pushed a commit to ItsDoot/bevy that referenced this issue Feb 1, 2023
…m the logs (bevyengine#5751)

# Objective
- Fixes bevyengine#5745.

## Solution
- Changes the Vec3 and Quat types.
github-merge-queue bot pushed a commit that referenced this issue Sep 18, 2024
# Objective

When deriving `Reflect`, users will notice that their generic arguments
also need to implement `Reflect`:

```rust
#[derive(Reflect)]
struct Foo<T: Reflect> {
  value: T
}
```

This works well for now. However, as we want to do more with `Reflect`,
these bounds might need to change. For example, to get #4154 working, we
likely need to enforce the `GetTypeRegistration` trait. So now we have:

```rust
#[derive(Reflect)]
struct Foo<T: Reflect + GetTypeRegistration> {
  value: T
}
```

Not great, but not horrible. However, we might then want to do something
as suggested in
[this](#5745 (comment))
comment and add a `ReflectTypeName` trait for stable type name support.
Well now we have:

```rust
#[derive(Reflect)]
struct Foo<T: Reflect + GetTypeRegistration + ReflectTypeName> {
  value: T
}
```

Now imagine that for even two or three generic types. Yikes!

As the API changes it would be nice if users didn't need to manually
migrate their generic type bounds like this.

A lot of these traits are (or will/might be) core to the entire
reflection API. And although `Reflect` can't add them as supertraits for
object-safety reasons, they are still indirectly required for things to
function properly (manual implementors will know how easy it is to
forget to implement `GetTypeRegistration`). And they should all be
automatically implemented for user types anyways as long they're using
`#[derive(Reflect)]`.

## Solution

Add a "catch-all" trait called `Reflectable` whose supertraits are a
select handful of core reflection traits.

This allows us to consolidate all the examples above into this:

```rust
#[derive(Reflect)]
struct Foo<T: Reflectable> {
  value: T
}
```

And as we experiment with the API, users can rest easy knowing they
don't need to migrate dozens upon dozens of types. It should all be
automatic!

## Discussion

1. Thoughts on the name `Reflectable`? Is it too easily confused with
`Reflect`? Or does it at least accurately describe that this contains
the core traits? If not, maybe `BaseReflect`?

---

## Changelog

- Added the `Reflectable` trait

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Scenes Serialized ECS data stored on the disk C-Bug An unexpected or incorrect behavior D-Trivial Nice and easy! A great choice to get started with Bevy
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants