#Next Generation Scenes

1 messages ยท Page 2 of 1

native mesa
#

ah, ok cool I need to read that.

rough cave
#

No polymorphism required.

native mesa
#

don't have time now but will get back to it.

rough cave
#

Fair enough! ๐Ÿ™‚

crisp garden
#

The BSN part of it was less important, it was the fact that there was a required components proposal that would have access to the rest of the entity to decide between adding the UI-space or world-space transform. That said I don't think that part of the proposal is in the PR yet, since it relies on further work (iirc Construct?)

rough cave
#

I don't think that would even solve the issue I'm describing, though.

#

The point is that, at the time that the component X is authored, and made to require Y, it cannot know about hypothetical future component Z that might want to replace component Y. How can it be written to know not to insert Y?

#

With ECS' we get this lovely flexible system where systems only run if entities match the requirements, and then we add and remove components as the primary API for choosing which behaviours we want to opt into.

Required components take away the users choice about what components are added, therefore taking away their choice about what behaviours they are opting into.

native mesa
#

i lied, read it anyway. in the 'plugin dependencies' work, we also ran into this problem.

#

the solution was to add a 'provides: X' option, which lets you say 'any plugin that needs X can actually use Y instead'

#

in your example, you could annotate with SpecialComponent with provides(Transform) which makes way less sense semantically but would still maybe work?

#

idk, this defiantly is an issue.

native mesa
crisp garden
# rough cave With ECS' we get this lovely flexible system where systems only run if entities ...

Looking at your description I think the main thing here is that there isn't really any "user choice". Plenty of crates already entirely forgo using Bundles, instead using systems or hooks to add all the components the users forgot, because if you don't you'll get flooded by users saying "I spawn a X but it doesn't work" and it always turns out to be them forgetting to use XBundle instead

frosty shell
#

If Required Components had the other half of archetype invariants (disallowed types), you could do

#[derive(Component)]
#[require(Button, MyUiTransform)]
#[disallow(UiTransform)]
struct MyCustomButton;
rough cave
frosty shell
#

which isn't fantastically usable understandably

native mesa
#

'X substitutes for Y' is probably clearer than 'provides'

crisp garden
rough cave
#

@crisp garden by "what @native mesa described" do you mean his "provides" idea?

crisp garden
#

Yes

rough cave
#

That's great, but has never been on the table for discussion before.

#

I'm raising concerns with the required components system as implemented and up for PR right now.

#

There are mitigations (allowing requires to be dynamically overridden during app initialisation, or this new "provides" idea, etc.).

native mesa
#

fair. i think it's a framework that we can work to solve problems within. but i'm really glad you brought this up, it is a serious flaw i had not considered.

crisp garden
rough cave
#

@crisp garden that's fair, but I'm surprised this feature has been in discussion & planning for 4+ months and this hasn't come up!

crisp garden
#

There are probably cases where this could make sense. Avian's Position/Rotation + some scale component could probably "provide Transform", instead of doing this funny dance where Position/Rotation update Transform, and Transform updates them

#

But now you're also getting into the realm of "If Y provides X, should they be mutually exclusive" ... The answer is probably yes in many cases, but now we also need archetype invariants ferris_sob

native mesa
crisp garden
native mesa
#

it's especially hard to discover these edge cases before the code is in-hand.

crisp garden
#

Transform is easily the most obvious example here, but barely anyone tried to "fix" the problem

thick slate
#

Interaction is the other problem case that I've seen worked around

rough cave
#

For context I spent ~2 years working on a Unity DOTS Netcode game (that eventually got cancelled ๐Ÿ™„), and it was frustrating when using third party code that made assumptions that limited your ability to configure them. I am now just very sensitive to the addition of ECS features that make it even easier for people to "just add an annotation" and limit your ability to override something in their crate.

crisp garden
copper dragon
#

https://youtu.be/_N--2xOXEN0

Huh, anyone else heard of this/considered before bsn?

To try everything Brilliant has to offer for free for a full 30 days, visit https://brilliant.org/Acerola/ youโ€™ll also get 20% off an annual premium subscription! #ad

Creating a functional 3d tools pipeline that interfaces with multiple kinds of software can be an absolute drag due to data incompatibilities. Thankfully, Pixar has saved the day ...

โ–ถ Play video
native mesa
thick slate
crisp garden
# rough cave For context I spent ~2 years working on a Unity DOTS Netcode game (that eventual...

I think ultimately the solution here is to have it go both ways: We make it easy easier to forget about those uscases, while also making it easier to override them. @native mesa's solution is really elegant in that regard, you can just override whatever other plugin authors say you need, and there's nothing they can do to stop you because they already threw their manual required components systems in the trash ๐Ÿ˜‚

rough cave
#

I have slight concerns on how you'd actually express the "provides" contract, but it definitely sounds like something to look at.

thick slate
#

@rough cave are you comfortable opening an issue for the "must be able to override required components" requirement?

rough cave
#

There's also, as I previously discussed with Alice, just allowing you to "disable" requires via a hypothetical app.remove_requires::<A, B>().

thick slate
#

I'd like to get it properly written down and in the milestone

rough cave
#

@thick slate yeah sure ๐Ÿ™‚ it's the least I can do after I've caused so much angst.

thick slate
#

Awesome โค๏ธ

crisp garden
thick slate
#

I'm not going to block merging the main PR over this, but I will make sure we don't ship 0.15 without it

magic belfry
crisp garden
#

Yea that's exactly where I got the idea from!

#

I also have a few usecases like that ๐Ÿ˜…

native mesa
#

if you like provides then i came up with it, if you hate it then it was Joy.

rough cave
crisp garden
crisp garden
thick slate
native mesa
rough cave
native mesa
#

i don't actually remember if dots was around back then

#

probably not

round ridge
#

I mean, I think the earliest available preview was like ~2020.

native mesa
#

yeah no i'm not that young, i used unity only a bit ages ago is my point. the community's practical gamedev experience tends not to be very evenly distributed.

rough cave
#

(or to anyone interested, pls review this issue to see if I've captured things correctly)

magic belfry
thick slate
#

Yep, this is solid!

crisp garden
# magic belfry I'm not sure if I fully understood how exactly `provides` works or how it'd help...

provides would essentially signal bevy "If the entity has Y, consider it as already having X and don't add it". Meaning you would be able to replace built-in components with something that provides equivalent functionality, avoiding the double state like "Position says 0, 1, 13 but Transform says 3, 12, 5" that needs to be synchronized ... So basically a RigidBody wouldn't get Transform, and thus there's no confusion or synchronisation necessary (of course this assumes a tuple of components can also provide another component, since Position alone does not provide Transform)

thick slate
magic belfry
#

Also most users would just add Transform anyway, not Position

crisp garden
bitter nymph
#

Alternative would be a "I know what I'm doing" api to opt out of required components

crisp garden
crisp garden
magic belfry
#

(also Position is global and Transform is local, so the relationship would rather be that it provides GlobalTransform, which has its own issues... but that's unrelated to the discussion)

thick slate
crisp garden
thick slate
#

I think there's a good chance we want both in the end

native mesa
#

they seem complimentary

bitter nymph
#

True true

native mesa
#

subs_for is probably more useful for 3d-party crate authors who want to extend other crates, or let users add custom marker components or something.

magic belfry
native mesa
#

the remove api is good for code-monkeys who want to make their app work properly

hybrid flare
#

I don't understand the use case of subbing out a required component. If a component is required doesn't that mean that systems will look for it?

#

Since it doesn't exist wouldn't that be a problem?

#

Unless we had trait queries or some such

native mesa
#

sometimes you want it to stop working with the existing systems, and start working with a new custom system

#

you need to prevent the old component from being added in that case

#

#ecs-dev message

hybrid flare
#

I see

crisp garden
hybrid flare
#

subbing out required components would work really well with trait queries

native mesa
#

oh yeah, it's all coming together.

bitter nymph
crisp garden
crisp garden
# bitter nymph Would that also apply to mixing 2d and 3d transforms?

That's originally where all the plans for changing Transform started, then it became worse with how UI abuses Transform, and we also got usecases where Transform allows weird invariants not supported by crates used (raymarchers can't have non-uniform scale, and hierarchies with non-uniform scale + rotation can introduce shear which messes with physics)

#

But the Transform discussion is probably off-topic other than the idea of being able to sub out components with similar components

#

Maybe such a system and split could also rid us of weird things like Handle<Mesh> in 3D vs Mesh2dHandle(Handle<Mesh>) in 2D thonk

bitter nymph
#

I want to mix 2d and 3d though. Like a hybrid. Like not 2d but also not 3d. Something in between. Like... 2.5d

copper dragon
#

That'd give a 2d look with 3d space

bitter nymph
copper dragon
#

Ah

#

Don't see the issue with that, just axis lock everything

native mesa
#

sometimes it would be nicer to be able to mix 3d transforms to create layers, and then use 2d transforms within those layers

bitter nymph
#

Right now using avian 2d. Would be disappointing not to be able mix things

native mesa
#

i do have schemes for this

magic belfry
#

physics has its own global position and rotation types anyway, it doesn't really care if you mix transforms (except syncing them with physics positions would need to be supported for each of the transform types of course)

split harness
#

Just responded to the "overrides" conversation here: https://github.com/bevyengine/bevy/issues/14927#issue-2487241990. For this topic, I think we should keep the discussion on github at this point to avoid thoughts and info getting buried

GitHub

What problem does this solve or what need does it fill? We are adding the ability to require components in Bevy, this feature request asks for the ability to override this behaviour when it prevent...

bitter nymph
#

How are animations in reactive bsn envisioned to work?

#

Including transitions (animating in and out) and value changes?

rare whale
#

The transition component is driven by a separate system which updates every frame.

#

The template is responsible for updating the animation parameters: duration, target value and so on. These properties are updated reactively.

bitter nymph
#

I was wondering if you'd need to keep both the incoming and outgoing trees around in bsn

bitter nymph
#

Because that's something I dislike in react

rare whale
#

There's a helper hook called bistable_transition which provides a state machine that implements the exited -> entering -> entered -> exiting -> exited states. This internally keeps a timer and a state variable.

#

So we don't need to keep around a copy of the whole VDOM, just the state of the one thing.

split harness
split harness
rare whale
# split harness Required Components is merged! https://github.com/bevyengine/bevy/pull/14791

Question I have been meaning to ask with required components: currently my game relies heavily on the ability to have more than one material for a mesh - it's how I do toon outlines. I'm worried that this might not be supported in the future, since it seems like it works only by accident. How will this work in a world where materials are required components? (Or will they be?)

thick slate
#

And can't you just add the component?

rare whale
thick slate
split harness
#

We will likely revisit the Material / Mesh instance API in the context of required components

#

The big question Required Components creates is "what do we do about raw Handle<T> components"

#

Either we embrace them, and build an API into handle that lets you add required components for a give T type, or we add wrapper components

#

I'm largely on team "wrapper component"

nocturne lotus
#

a raw Handle as a component is akin to a raw f32 component

#

it makes no sense imo

#

it's just data with no meaning

split harness
#

Ex: MeshInstance instead of Handle<Mesh>

thick slate
#

Yeah, I'm on team yeet too

rare whale
split harness
#

If so, yes you can do that

rare whale
cobalt stone
frosty shell
#

wrapper components also enables struct MyHandles(Vec<Handle<T>>)

thick slate
#

And Mesh cannot require StandardMaterial

copper dragon
thick slate
cobalt stone
copper dragon
rare whale
#

In my case, I currently have two materials for the same mesh instance: Handle<StandardMaterial> and Handle<OutlineMaterial>.

thick slate
native mesa
#

when it's really just data

#

not behavior

frosty shell
#

plain ole data vs semantic data

nocturne lotus
cobalt stone
#

All components are supposed to be data without semantics, that's the point of separating systems out ๐Ÿ˜…

native mesa
#

i feel like components are often used to represent behaviors implemented by systems, but i'm no ecs expert

nocturne lotus
#

and it's still just data

native mesa
#

getting into that will go off topic very quickly

#

lets stay focused

split harness
split harness
cobalt stone
thick slate
rare whale
#

@split harness @thick slate I'm wondering if, at this point, it makes sense to split off required components (and the follow-up refactorings of bundles) to a separate working group.

split harness
thick slate
native mesa
thick slate
frosty shell
#

Also it would be a good place to collect feedback mid-cycle rather than get off topic about scenes

weary nebula
#

If making all Bundles defaultable is less of a concern with required components, it could be nice to remove the Default impl from Handles where the underlying asset doesn't have a default (such as Font)

#

Though I understand if the Bundle API is meant to be preserved

nocturne lotus
#

Default for handles is still convenient when deriving Default for a component that includes a handle as a field
you can still do a manual Default impl ofc

split harness
# rare whale <@153249376947535872> <@159873981174906880> I'm wondering if, at this point, it ...

Yeah the bundle refactor is something that should be done very carefully and very intentionally. Timing also matters on this:

  1. Some required components ports might be blocked on Construct (ex: the no-default-handle stuff)
  2. Doing a "partial port" of the engine across releases feels confusing / suboptimal
  3. Landing the new scene system "as a whole" might be good optically, rather than slowly bleeding it in.
native mesa
thick slate
#

and bundles won't have a representation in scenes

weary nebula
native mesa
#

(off topic, but i would also prefer land a full scene system, even if it means pushing back the release. the current workload is significantly different from how things have been done for the last two/three cycles. better optics, and first-impressions are vital)

split harness
thick slate
frosty shell
#

I think the best case for Handle is to make whether it implements default opt-in per type

nocturne lotus
weary nebula
thick slate
weary nebula
split harness
thick slate
#

Cool, I'm down for that

split harness
#

Components just "happen" to be bundles

#

But yeah in general we should bias toward "component only"

thick slate
#

I have a few bundles that I can't swap over to required components since either combination is valid, so that's nice to hear

#

In terms of shipping this, I'd like to do the bundle -> component only changes in a single cycle, using deprecation notices on all of our bundle types

native mesa
#

are we actually planning full deprecation?

split harness
#

I do want a lot of scrutiny and thought to go into the port. We are essentially re-defining the Bevy API surface / how people interact with the engine. Not something to do lightly

#

We should identify and codify the general patterns we're going for. And I'd like significant involvement from the maintainers and SMEs for pretty much all of these decisions.
<@&1064695155975803020>

split harness
nocturne lotus
#

i wonder how Text2dBundle and TextBundle will be migrated

#

since they share the Text component

native mesa
#

probably means Text won't have any requires. TextBundle is just NodeBundle in a hat.

nocturne lotus
#

Sprite and UiImage are separate rn otoh, although they're very close to being identical components

split harness
nocturne lotus
#

ic so either (Text, Node) or (UiText) for TextBundle

split harness
#

In general I'd like us to move in the "top-level driver component" direction that corresponds to a single unique concept

native mesa
#

most bundles already work that way. Ok @thick slate i see what you mean about the new working group.

nocturne lotus
#

hm Text2dBundle in bevy main also includes a SpriteSource, which you wouldn't get as a required component from Text

split harness
thick slate
split harness
#

Given that Text in this case is "just" a wrapper over a string, im happy duplicating this into Text2d

#

Ex: Text2D(String) and Text(String)

#

They can still share internals

#

And components like TextStyle

nocturne lotus
#

ic. XyzBundle -> Xyz component is probably a good rule of thumb then

split harness
#

Agreed

thick slate
#

FYI, we should consider how this concept of required components ties into inspector tooling. It might be nice to be able to track the "originating component" of an entity

#

Probably only in dev tool mode

split harness
thick slate
#

(or we have a component / reflect attribute for "please consider me defining")

split harness
thick slate
#

Yeah, that's pretty valid

#

I just went less "Entity" spam in the inspector panels ๐Ÿ˜›

split harness
#

If we find a need for this concept (and I'm not sure we need it), then we could introduce it on top

native mesa
#

Some of them don't have a single entrypoint, we probably do want visibility <-> inherited_visibility <-> view_visibility

split harness
#

Ex: require_defining or something, where an entity can only have one defining component

#

(and it would play nicely with require-inheritance)

#

But id prefer to not go down that route unless we absolutely have to

thick slate
#

Yeah, I think this can mostly live in reflection land

split harness
#

Now that Required Components is in I'm back to getting that prepped

#

I haven't done much porting yet. Just Cameras (and relevant deps) and some UI things

native mesa
#

Just having that for Visibility and Transform will make like half of the current bundles trivial.

split harness
native mesa
#

turns out the oop guys were right all along

#

i think this is technically a mixin-based inheritance scheme?

frosty shell
split harness
#

(I'm actually in favor of supporting classical inheritance in Rust ... just memeing)

native mesa
#

the bevy rust esolang is now oop-pilled

split harness
#

Definitely in a way. But in that case I'm talking about vtables / expanded data layouts / etc

native mesa
#

yeah, i can see how that would fit. i don't think the lang team will ever consider it.

split harness
#

virtual / override functions, properties, give me it all

frosty shell
#

just not templates

split harness
#

I do think C#'s "give people lots of language tools" approach is the move

karmic rock
split harness
karmic rock
#

Oh interesting ๐Ÿค”

#

Does it support overriding component values?

copper dragon
split harness
karmic rock
#

Gotcha, so you're inheriting the components to add, not necessarily component values

split harness
#

Yup!

karmic rock
#

Neat, yeah that's what with does

split harness
#

In the context of BSN inheritance (which is different from Component Requires), inherited component values are always stored per-entity and accessed directly

#

I do think the flecs approach is cool, but so far I feel inclined to keep the "every entity has its values" approach

karmic rock
#

Yeah that does seem to be in line with what most developers expect

#

In the newest version I've also switched the default to copying to the instance vs. inheriting

split harness
#

I think the inherit approach feels coolest in the context of quickly + cheaply applying inherited scene changes. Could cut down iteration times

karmic rock
#

Yup, and it can also cut down on instantiation time

split harness
karmic rock
#

... but adds a lot of complexity all over the place

split harness
#

And some indirection

#

Data access overhead increases slightly

karmic rock
#

Yeah it can, get is more expensive for the "can't find the component on the entity" branch

#

It cuts both ways though, only loading one value in the cache vs 1000 can reduce cache trashing

#

Though most components are probably not inheritable so not a huge effect

split harness
#

(the indirection overhead)

karmic rock
#

When you say indirection, do you mean in the context of queries?

split harness
#

Seems like there might also be iteration overhead because its no longer accessing data linearly

#

(unless im missing something)

karmic rock
karmic rock
split harness
molten oar
#

or rather, the fact that sometimes it is inside a struct (like the layout field in TextureAtlas) and sometimes bare, which is pretty bad UX imo

#

bare somehow feels wrong, given that there are situations where the API is made clearer by having it inside a struct, like with the texture atlas stuff

#

so imo, for UX consistency, handles should not impl Component

molten oar
#

btw, fyi, another use case for bundles that isn't often talked about is using them for removal, rather than spawning/insertion. for example, in my project, i have bundles representing a set of various optional components that may or may not exist on specific entities, to make sure i can easily remove all of them when my cleanup code runs

#

for example, i might have some gameplay-related entity, which could have various optional components representing different state, depending on what it is currently doing. i might want to "reset" the entity by keeping it alive (not despawning) and keeping all the various components that should always exist, but removing any of the optional components that may exist. having a bundle with all the optional component types makes that very convenient. i can just do commands.entity(e).remove::<MyOptionalComponentsBundle>();

#

this is just another one of my arguments for not removing/deprecating bundles as a concept in bevy_ecs completely ๐Ÿ™‚

coral marsh
#

I hope bundles will stay. I usually limit myself to only using 1 bundle per entity โ€“ I define a bundle for every type of entity that I expect to exist. It works but I haven't made anything more complicated with bevy yet so I dunno if it scales well.

I even think that bevy editor should work like that too and require specifying a single bundle for every entity. I feel like most level editors work like that. After all it doesn't make sense to create for example a Player AND an Enemy as a single entity.

I know that bevy editor is planned to be more than just a level editor, but it would be cool if it still supported that, so you can get a level editor for your game for free and release it with your game.

molten oar
#

1 bundle per entity sounds unnecessarily restrictive and dogmatic. i use extra bundles for extra optional modular state. bundles are generally useful for ensuring correctness at compile time.

#

IMO the best course of action for bevy is to:

  1. add required components
  2. migrate "spawning common kinds of entities like cameras, sprites, ui, etc" (i.e all the stuff that is currently bundles in bevy) to required components
  3. deprecate these bundles
  4. do not deprecate the concept of bundles in general

that is, have the "spawning your entities with the right set of components" use case be handled by required components, but keep around bundles for the "inserting/removing optional extra components" use case

native mesa
#

this is what we are doing.

#

though i welcome the suggestion, there's broad consensus about this, so i don't think we need to discuss this proposal. the editor will not be built around bundles.

molten oar
#

okay

#

sorry for taking up space in the chat for something that was already decided. i kinda lost track.

native mesa
#

no problem, sorry didn't mean to be curt. just trying to gently keep things focused ๐Ÿ‘

#

it's never an issue to make sure we're all on the same page, and it's a good overview!

rare zealot
rare zealot
fallow cloak
#

I'd love to help migrating to required components. Would it work to submit multiple smaller PRs gradually subtracting from the engine bundles, or is it something that needs to be done all at once?

#

I imagine bevy_transform would be a good place to start in the former case

cobalt stone
fallow cloak
#

Then I'll probably just start with Transform -> GlobalTransform and remove GlobalTransform from a bunch of bundles

#

Actually, wait

#

then there's the question of which one is actually "required" by the bundle itself

native mesa
#

nuke spatial bundle. discussion with cart seems to imply it's Transform -> GlobalTransform (Transform is the end-user facing type) and Visibility -> ViewVisibility & InheritedVisibility (again, only Visibility is end-user facing).

#

-> is requires

fallow cloak
#

Visibility will probably be PR #2

#

since it's rendering

cobalt stone
#

There's also lots of bundles (e.g. MaterialMeshBundle) that use transform/visibility components directly instead of inherient SpatialBundle, so watch out for those.

thick slate
fallow cloak
#

nice. PR should be up in a few minutes then, once my rust install stops dying for whatever reason (thanks arch)

native mesa
#

deprecation notice

buoyant venture
native mesa
#

cart posted code from his dev bsn branch, and Transform did not require Visibility.

#

There's plenty of things which can have a location without visibility making sense.

#

Nav-targets

#

sound sources

nocturne lotus
#

it's awkward because there's a SpatialBundle but no Spatial component

native mesa
#

SpatialBundle will be replaced with Transform + Visibility. It's not that bad imo.

nocturne lotus
#

does visibility not imply transform?

native mesa
#

we could introduce a Spatial construct or something maybe

native mesa
buoyant venture
fallow cloak
rough cave
#

I wrote a little toy parser for BSN examples as an excuse to learn the nom crate, it doesn't use bevy_reflect (or anything else). Is this of interest to anyone?

native mesa
#

yes

#

very much so

split harness
#

I don't want to get half way through and then get blocked (or find that its time to cut a release)

wind dock
#

Happy to see required components merged. Is the plan to post the constructs pr soon? Or a break while required components are digested?

split harness
#

I think the biggest question is the Mesh / Material / PbrBundle question

fallow cloak
#

absolutely that yeah, rendering is going to be difficult

native mesa
fallow cloak
#

I was going to tackle Visibility and leave the rest pending more discussion

split harness
native mesa
#

cool cool

split harness
#

The complexity isn't particularly high

native mesa
#

hack md then on just in discord?

fallow cloak
#

Also there shouldn't really be any merge conflicts afaict, we're just removing fields

#

so they can all (or most of the simpler ones) be just off of main I bet

split harness
#

With one central "hub" document?

native mesa
#

yeah we can do that. it's a bit clunky, but they have a "book mode".

split harness
#

With landing Construct (or even more of the proposal) as a stretch goal

fallow cloak
#

as a procedural thing for dealing with affected bundles:

  • should we delete newly "useless" bundles like TransformBundle (in the short term)? Alternative would be deprecating and removing affected fields. This would make TransformBundle a simple newtype for example.
  • If the latter, should we remove those bundles from the crate prelude?
native mesa
split harness
# native mesa <https://hackmd.io/@bevy/required_components>

Excellent. I'm thinking one page per bundle (to organize the discussions), with a list of every component in the bundle, followed by an initial proposal for the new layout.

Each proposal should be a ## Proposal 1 followed by a code block with the require section. We can then discuss, add new proposals, and at the top have a "currently selected proposal: Proposal X"

native mesa
#

alright, i can set that up when i'm not at work

split harness
native mesa
#

anyone who is part of the bevy hackmd org can edit

split harness
#

Also as a rule, lets make proposals append-only to properly preserve comments

native mesa
#

let me post the link to join again

rough cave
#

@native mesa fyi here's a gist, the important part being all the tests at the bottom showing what currently is supported, so you can decide if it's interesting https://gist.github.com/omaskery/42a67ebca36b5ad73897355b2c3ac1dc - the code isn't nice at all, so please forgive that. Was just learning nom on a day off. As a note, I generally write recursive descent parsers for fun in my spare time, so if somebody was actually interested in a "proper" parser for BSN that was reflection-independent etc. then I might have the spoons for that. Not sure if an actual useful requirement though, or if everything in carts private branches has all this sorted ๐Ÿ™‚

native mesa
rough cave
#

@native mesa note some caveats, the syntax is ambiguous without type information, so I don't bother supporting call syntax explicitly, as at the moment all the BSN examples only use Rust syntax that is indistinguishable from a tuple struct initialization. Similar for enums, which are syntactically just struct literals.

#

I also do a bunch of hacky stuff to just get it working, loads of fragile cheats around strings/characters/numbers/type-names/etc.

split harness
#

Ex: Camera2d and Camera3d should probably have a unified discussion

rare whale
#

What about NodeBundle/ImageBundle/TextBundle etc? Is that a separate effort?

patent cliff
split harness
split harness
#

(with all of the bundles)

rare whale
#

I'm looking at NodeBundle and wondering what is meant by "required". Almost all of the components in NodeBundle can be left out, defaulted, and frequently are. However, internally, the engine might need some components to be present, even in default form (e.g. transform). This is not something that I, as a Bevy end user, am going to be able to judge.

#

Like for example, if your node has a transparent background color, there's no need to insert a BackgroundColor component - but it's present in the bundle.

#

I'm guessing the reason it's there is for purposes of suggestion, not because it's required.

native mesa
rare whale
native mesa
#

i personally think we should stick to required components being just for invariants.

#

and just add docs to explain how components interact

rare whale
#

Leaving out all of the non-required components from NodeBundle means that UIs are going to get a ton smaller, memory-wise.

#

Moreso if we adopt one of the various suggestions for breaking up Style

native mesa
#

break up of style is probably the next thing we should do after this

#

since we are already in the business of restructuring all our apis a bit

rare whale
#

Unfortunately there isn't a clear consensus on a new design

#

Just some vague hand-wavy proposals

native mesa
#

that might be something cart has to bless us with his infinite wisdom on

rare whale
#

At the very least, it's out of scope for this WG

split harness
#

I'm modifying this rule:

  • Do not modify existing proposals, add new ones (this will help preserve conversation history)

I don't want a bunch of duplicate code with minor changes

#

Done

split harness
# rare whale Like for example, if your node has a transparent background color, there's no ne...

I would (personally) like to move away from "implied default values":

  1. It makes it harder to reason about what those are, as they often don't live in / near the struct, but rather in a system somewhere
    • This also makes it possible to have different implied default values, as each system can choose how to interpret it
  2. It forces archetype moves when changing to a non-default value
  3. It makes it hard to query for things (ex: give me everything with a transparent background) because now you need to check both Option<BackgroundColor> and BackgroundColor(Color::NONE), and it means you need to know to do both.
  4. It makes it harder to discover functionality, as the "optional" component is now floating / decoupled
#

For truly optional functionality, I'm still down for optional components

#

But imo it is best to consider all UI Nodes to have a BackgroundColor, a FocusPolicy, etc

rare whale
tired topaz
#

The style component has to many values, that are actually optional or only does things depending on other members on style. and its parents and children.

which is also a problem

native mesa
magic belfry
# split harness I would (personally) like to move away from "implied default values": 1. It mak...

Hmm, I can see the utility of this for UI, but would you consider this to be a "best practice" that the ecosystem as a whole should generally follow? ๐Ÿค”

For example, in Avian, I have implicit defaults for things like:

  • CollisionLayers (which layers colliders belong to, and what they can interact with)
  • Dominance (allows bodies with a higher relative dominance to act like they have infinite mass in interactions, 0 by default, can be positive or negative)
  • GravityScale (scales how strong gravity is for a body, 1.0 by default)
  • SpeculativeMargin (affects speculative CCD, f32::MAX by default)
  • Etc. etc.

I feel like if every default like this was made explicit by always requiring the component, you would end up with a ton of unnecessary data and increased memory usage. And as a library author, I'm not sure if I'd still be comfortable not handling the cases where components are missing, since users/plugins could still remove the components.

Imo physics should work without a GravityScale on every entity, and if it doesn't, then I feel like you lose one of the big reasons for using an ECS and end up with a ton of unnecessary data on entities.

rare whale
#

If you recall early unix desktop GUIs (Sun Microsystems, X11) there was a user preference called "focus follows mouse", which would cause whichever window the user moved the mouse over to gain focus.

native mesa
#

yeah, it's all mixed together. needs a full review. I think picking only makes this more complex, rather than simpler.

#

i think of picking as providing "hover" information rather than "focus"

rare whale
native mesa
#

I've added a basic proposal to those that where missing one.

native mesa
# magic belfry Hmm, I can see the utility of this for UI, but would you consider this to be a "...

I think I'm with Jondolf here. I am sympathetic to all four of these points. But I would say to (4) I don't see how this is discoverable in a way that docs are not, and to (3) it feels philosophically to me like if the behavior is optional then the component that encodes that behavior should also be optional. Lack of component = lack of behavior is core to the ecs design, and this could violate that.

#

But I also don't really see anything that in the UI proposal that violates this principle. BackgroundColor being set to clear by default makes sense, as does having a boarder with radius zero. The behavior is invisible, i guess.

grave pivot
#

what does "implied default value" mean in this context?

magic belfry
#

It's the default behavior or value used when the entity doesn't have the component. Like if BackgroundColor doesn't exist, you probably have an implicit default of a transparent color, or in my case with CollisionLayers, colliders assume a default layer 0b0001.

#

It's not something that "exists", it's just how systems should handle the case where the component doesn't exist

nocturne lotus
#

i dont see how it would be possible to not have implied defaults

#

if a component is missing, there will be a different behavior that happens

grave pivot
nocturne lotus
#

ig "no implied defaults" means "the systems that operate on this component just skip the entity instead"?

#

i feel like that should be w/e makes most sense on a case-by-case basis, which is why Option<Component> is a thing

grave pivot
nocturne lotus
#

like "no GravityScale => gravity systems don't affect that entity" vs "no GravityScale => gravity systems affect the entity with a scale of 1.0"

native mesa
#

I think, in this specific case, its a moot point. Since we already are going to represent clear as a possible background color, I think it's better to always have the background color component.

#

there might be other instances where it would make more sense to not have a default, but I think we've got to go case-by-case.

#

I agree with cart that it's better to have a required component when the default is trivial. Eg "a line with no width" or "a color that happens to be clear".

#

basically if there's a "does nothing" state in the component.

nocturne lotus
#

if you write a system that animates the BackgroundColor of a UI node when you hover over it, but entities spawned with Node don't get an implicit transparent BackgroundColor, you'd have to start explicitly adding it everywhere to make your system work

grave pivot
#

I don't really see a reason to discourage one or the other, either seems OK.

#

but yeah, entities aren't covered by GDPR, they don't get to opt out of behavior (unless entities can be hidden/disabled), a system can involve whoever it wants

native mesa
#

right but we're talking about api design principles.

#

not having a Transform component says something

nocturne lotus
#

is there a way to insert without required components? like an escape hatch

#

or is that planned if not

native mesa
nocturne lotus
#

ope

#

in that case i'll just say that IMO it should probably exist but no need to derail the conversation

native mesa
nocturne lotus
#

hm that's not exactly what i meant

#

not changing the required components tree, just having a .spawn_without_required(components) api

split harness
# rare whale Follow up questions, then: * Should nodes have a grid_start, grid_end etc. even ...

Should nodes have a grid_start, grid_end etc. even if they aren't in a grid layout?

Based on the proposed (admittedly not-yet-fully-thought-out) "style system" in my doc (styles do not add components, they just set them if they exist), I would assert that Nodes should unconditionally have grid_start and grid_end, to ensure that the style would be applied if someone defines Display::Grid in a style.

Alternatively, I think its worth trying to tie grid properties directly to the "uses grid layout" state, to ensure, this behaves as expected. For example, these could be fields on Display::Grid { start, end }.

Should nodes have a border color even if they have no border?

I'm thinking we should consider merging border properties into a single Border component. If a Node has a border, it has a radius and a color by definition.

#[derive(Component)]
struct Border {
    left: Val,
    right: Val,
    top: Val,
    bottom: Val,
    color: Color,
    radius: BorderRadius,
}

Is focus policy even meaningful anymore in an upstreamed mod_picking world?

I've sadly been out of this loop so I don't have a good answer here.

ZIndex has an unambiguous default (0), do we still need to include it?

In general I think if you ask yourself "does this Component have a X", then it should have the component. For example, the answer to the question "does this Node have a z index?" seems to be pretty clearly "yes it has a local z index of 0", so it should have a ZIndex component to reflect that.

split harness
# magic belfry Hmm, I can see the utility of this for UI, but would you consider this to be a "...

Imo in pretty much all of these cases, if you ask yourself the question "does this entity have this property", the answer is "yes". For the reasons stated above, I think they should be required.

I feel like if every default like this was made explicit by always requiring the component, you would end up with a ton of unnecessary data and increased memory usage.
I think this is the biggest downside to my proposal. But imo this is barely worth thinking about for roughly-single-primitive components like these. Memory isn't so constrained (or so slow) that I think we need to be this precious to this degree.

That being said, if in specific cases adding a component is proven to be problematic for scale, its worth considering making that component optional.

And as a library author, I'm not sure if I'd still be comfortable not handling the cases where components are missing, since users/plugins could still remove the components.
I do think core library authors should be defensive here / cover these cases. But I don't see it as an argument to encourage reliance on those cases being covered.

split harness
rare whale
# split harness > Should nodes have a grid_start, grid_end etc. even if they aren't in a grid la...

On styles, I've been going down the exact opposite path: all my styles are set via a helper (StyleBuilder) which offers a fluent API that automatically inserts (or removes) the components as needed - which means that the user doesn't even need to know which component a given property lives in. StyleBuilder is also an extensible trait, so for example even though mouse cursor shapes are not natively supported in Bevy (not as styles), you can can set the cursor shape for a node just like any other style property, and it automatically inserts a Cursor component.

#

Nico also has another idea for styles which is different than either of ours.

#

In any case, the mental model is similar to CSS, in which there's just one big bag of properties, and how it is broken up into components is an implementation detail.

split harness
# rare whale On styles, I've been going down the exact opposite path: all my styles are set v...

I see the appeal of this approach, as it gives styles the power to modify and extend the behavior of an entity. My primary counter argument is that it feels like styles shouldn't be responsible for changing the "shape" / "type" of an entity. The "shape" of the entity should be defined by logic and the style should just twiddle values on it. Not messing with the "shape" also seems important if we're going to be selecting styles based on entity shape (aka "apply this style to every entity with the shape [Button, CoolButton]"). The recursive behavior of allowing a style to change the shape, and thus select new styles, which can then change the shape, etc seems gnarly / hard to reason about.

#

However I'm not yet convinced that global "shape based" styles are the right move.

rare whale
split harness
rare whale
split harness
#

Converted to Bevy, that might be:

.my-list > ListItem {
  /* list item style here */
}

or

// only style selected list items
.my-list > (ListItem, SelectedItem) {
  /* list item style here */
}
rare whale
#

My read on the crowd is that people want to set styles explicitly on the node, and if they want inheritance or themes or whatever they will do it via another ECS mechanism.

split harness
rare whale
#

In my world, if you want to animate a background color, you have to explicitly set a background color

#

You can't animate a component that's not there, but it's your responsibility to make sure it's there when you set up the animation.

split harness
rare whale
#

To be more explicit: the animation curve component isn't going to automagically insert a background color for you.

split harness
#

I think thats the right way to do things, at least to start. I can see a world where people ultimately want to be able to animate the adds / removes of components, but I think that should be a separate feature / have explicit semantics

rare whale
#

The disabled component is removed when the condition is false.

split harness
rough cave
crisp garden
river geode
#

Can I add a required component at runtime in addition to dev time (macro)? I didn't see anything in the PR at a quick read.

Use case would be making my first party component a requirement of some third party component.

glossy holly
crisp garden
#

It's mentioned as part of https://github.com/bevyengine/bevy/issues/14927
And Jondolf also brought up a usecase where this would be helpful (an optional SleepingPlugin for physics, where only when it's added are the components required).
I don't remember actually seeing cart comment on this specific thing so I'm not sure how easy/hard this feature is ๐Ÿค”

magic belfry
#

FYI, I'm aware there's no official consensus/approval on these proposals yet, but I did an initial required components migration for the following things listed in the HackMD:

#

These are all on separate independent branches, and would become even nicer once required components ports for transform and visibility are merged. You can see the diffs for each of these behind the links.

#

Are these something we'd want PRs for already? If so, I could improve the docs and make proper PRs later today / soonโ„ข. I know things like meshes, text, and UI might require a bit more design work, which is why I didn't port them yet, but the ones I did shouldn't be too controversial imo (except maybe audio).

river geode
#

If it helps fuel the discussion, the use case I was thinking of was something like a PreviousInteraction(Interaction) component added to everything with an Interaction, adding a system to update it with mut Query<PreviousInteraction, Changed<Interaction>>, and triggering events when transitioning from pressed to hovered (sort of a pseudo mouse-up event)

native mesa
#

Interaction is getting yeet in 0.15

thick slate
#

See #1236111180624297984

thick slate
#

@magic belfry I think hold off on PRs until Cart is back from vacation: I'm not comfortable merging any of them until he's around

magic belfry
#

Yup, will do! In the meanwhile, I'll probably try to migrate (some of) the rest of the bundles to required components as well. No need to use any of this of course, just wanted to help this progress and see what it'd looks like in practice instead of letting things stagnate in the design/proposal phase
-# Really I just want to work on something useful that isn't related to physics or math for a couple of days ๐Ÿ˜›

native mesa
#

the proposals in the doc have not been evaluated yet

#

you may have to redo stuff, just so you're aware

magic belfry
#

yes I'm aware, and I'm fine with throwing things out and redoing things

#

I would expect a lot of the components like visibility, lights, and fog to be pretty safe though, there's not much open-endedness in terms of what the end API is like imo (i.e. just add PointLight) apart from maybe the details of which components are required

#

the main pain is updating all the examples to yeet bundles, it took me like two hours yesterday for all the components

native mesa
#

i really wonder if there's anything an auto-migrator could do

#

this is going to be a huge pain at work, when we eventually update to 0.15

thick slate
#

Well, we can / should keep the bundles around for at least a cycle as deprecated

#

Which should help

wooden vine
crisp garden
split harness
dark ocean
#

Can't seem to find this but am really curious: what is the current planned timeline for BSN? Is it meant to be implemented soon, or what are the blockers (if any)?

native mesa
#

Work is progressing on carts side to complete and submit reviewable chunks. The first chunk was required components. We will probably have to complete the migration before anything else.

fervent kindle
fallow cloak
#

but we're waiting for consensus on the overall situation currently I think

slate pewter
thick slate
native mesa
#

could probably be worked on in parallel though, if they are interested?

slate pewter
#

I'm poking at the macro rn and it seems like there isn't an easy way to differentiate a function path or value path

frosty shell
#

you probably want to disambiguate it with a different syntax, like

#[derive(Component)]
#[require(
    FocusPolicy = FocusPolicy::Block
)]
struct SomeComponent;
#

or some other syntax

slate pewter
#

ya thats what i was going to try next. I assume though that passing a constructor function was the way it was setup up purposefully to prevent big defaults from cluttering the Component definition

frosty shell
#

might be able to use closure syntax:

#[derive(Component)]
#[require(
    FocusPolicy(|| FocusPolicy::Block)
)]
struct SomeComponent;
copper dragon
fallow cloak
#

Theyโ€™re still needed for actually adding components to entities, so the mechanism isnโ€™t going away

#

Just most or all engine bundles

tired topaz
#

at least for user and library code. For example creating a bundle, with many different "default values"

copper dragon
#

Like, any component with a enum that has the None setting shouldn't be included as "required" since obviously they aren't required if there's a literal "None" on it

frosty shell
#

you probably want a requirement in the opposite direction in that case

copper dragon
#

Yea

crisp garden
#

I'm also not sure if "everywhere" is possible yet. There are some parts of bevy that have very suboptimal designs for the planned required components & BSN world so there might be some cases where it needs to be reworked first

magic belfry
#

I'll probably just open PRs this week anyway though, since I want to see actual progress here, and I feel like I'd be able to better give context and explore different approaches in PR form

wind dock
#

The push for required components was driven by the needs of BSN. So if a component is expected to be used in BSN (especially hand written BSN) then a required component will likely need to be considered

crisp garden
#

Not necessarily just by the needs of BSN. Anything that doesn't need bundles for some edgecase will likely become required components and have any bundle version of it deprecated (with removal being a version later I'd imagine)

split harness
#

I'll try to have strong opinions on that soon. Sadly lots on the plate right now

#

I've gotta frontload some foundation work this week

thick robin
crisp garden
copper dragon
crisp garden
#

That's sadly not the case since some of the example bsn! features are only possible because it is inside rust code, while your running bevy app has no rust compiler nor enough debug info to compile callbacks in a .bsn file. Of course bsn could internally turn the inlined data in your macro into a list of inputs, and allow bsn files to similarly accept inputs, just by names rather than inlining rust code. I just haven't seen anything about input to bsn files

#

Passing callbacks as input might however be less flexible and benefit less from hot reloading than accessing registered callbacks by name/path

thick slate
rare whale
#

Although my game isn't currently using BSN, I have similar challenges around exemplars and aspects, which are assets that (among other things) influence the behavior of scenery and actors. The key design problem is how to encode behavior in a way that is serializable. There are two approaches: behavioral components that have tweakable knobs, and scripting languages. I plan to use both of these approaches - for example, you could envision a "Goal" component that contains a reference to a LUA or Rhai script module which is also an asset. So for example, the goal "Territorial" adds a set of prioritized goals to the actor's goal list, which causes them to aggro when the player gets too close to their spawn point.

#

The sweet spot here is being able to edit assets where various behaviors are built up by composition, by adding reusable behavior modules to an entity.

thick robin
#

A lot of games aiming for moddability will definitely want a way to link a behavior defined in a scripting language to an entity in a BSN asset file.

crisp garden
thick robin
#

Script as an asset type could be constructed using the Construct::Prop syntax described in the proposal. Past that it comes down to language bindings which I don't think need special syntax for BSN

fallow sinew
#

Scripting would be awesome but I feel like it should be considered beyond the scope of BSN for now

crisp garden
#

Scripting is out of scope, referring to reusable behavior from a scene file should be in-scope tho

#

Doesn't really matter if it comes from a script or rust code

thick robin
#

I don't think anything specific is needed to support scripting

#[derive(Component)]
struct Behavior(Handle<LuaScript>);

impl Behavior {
    fn update(...) { // call lua script
}

fn aggro(
    player_q: Query<(&Player, &GlobalTransform)>,
    enemies: Query<(Entity, &Behavior, &GlobalTransform)>,
) {
    for enemy in enemies.iter() {
        let player = player_q.single();
        behavior.update(player, enemy);
    }
}

bsn! {
    (
        Enemy,
        Behavior(@"my_behavior.lua"),
    )
}
rare whale
#

It is absolutely out of scope for now, the reason I brought it up was to illustrate an alternative to the BSN callback problem, which is also out of scope ๐Ÿ™‚

tight marten
# fallow cloak Just most or all engine bundles

This is a mistake. I understand that they cover a use case pretty well (UI/Scenes) but bundles are fine for most cases and provide a useful structured way to manage components. Don't replace everything for something that that isn't well supported yet (required macro type definitions don't work on RR) when both can coexist.

thick slate
copper dragon
thick robin
#

Bundles themselves being just tuples of components right? And the current usage being named bundles with constructors as the blessed way to create a thing that has required components?

thick slate
thick robin
#

No more collisions between bundles with duplicate components zelda

crisp garden
#

The main one being "I need to construct multiple components from a value that isn't in a format I store it" ... Like say calculating the mass and inertia of an entity by density and a shape

thick robin
#

I was going to ask how required components are going to tackle things like SceneBundle that have spawning logics built in

crisp garden
#

I'm not sure if any first party bundles actually have this issue, but some end user bundles and crates have this issue (though there's also just as many crates that don't use named bundles at all, like avian)

magic belfry
crisp garden
#

Replacing the usage of first party bundles, and throwing things out that never had much use should be easy, and bundles don't conflict with required components in any way. Inserting (Transform, GlobalTransform) does not conflict with either of them requiring the other, which means bundles can coexist with required components nicely

thick robin
fallow cloak
crisp garden
thick robin
crisp garden
#

I also like how I had to dig trough code to find out how it's ordered now, because the function doesn't mention it, the plugin talks about SpawnScene, the docs on that refer to Main which doesn't mention it all, but luckily I happen to know it's defined in MainScheduleOrder (something the linked Main doesn't mention either)

tight marten
#

Are required components dependencies overwritten or only missing components are added?

native mesa
#

Missing components are added

magic belfry
#

Only missing components are added. If a mesh requires Transform, but the user spawns the entity with a specified Transform, it won't be overwritten

#

Similar to specifying component values for a bundle and using default values for the rest with ..default()

tight marten
magic belfry
#

Okay yeah in that sense it is different. But no, required components don't overwrite

native mesa
tight marten
#

Nice. Thanks a lot!

slate pewter
#

@thick slate Can you direct me to where the documentation on required components is so i can unblock the closure PR

thick slate
# slate pewter <@159873981174906880> Can you direct me to where the documentation on required c...
GitHub

Introduction
This is the first step in my Next Generation Scene / UI Proposal.
Fixes #7272 #14800.
Bevy's current Bundles as the "unit of construction" hamstring the UI us...

slate pewter
#

thank you ๐Ÿ˜Š

magic belfry
#

Dropping this โš”๏ธ-Controversial (or X-Contentious according to Alice) issue here. I know the related issue on overriding required components is heavily controversial, and I agree that being able to remove requirements arbitrarily is bad, but I think purely adding requirements in plugins is needed and valuable.
https://github.com/bevyengine/bevy/issues/15367

GitHub

This is similar to #14927, but more scoped, and with a slightly more flexible API. What problem does this solve or what need does it fill? Currently, required components work only through the requi...

thick slate
#

Yeah, I'm close to saying that this is uncontroversial, but your two requests there can be split apart :p

#

The conditional requirements is more contentious due to the need for careful API design

#

But just slapping more requirements on at runtime via App / plugin code is totally consistent with how we do scheduling constraints

#

And should be pretty easy

magic belfry
#

Yeah, agreed. Should've probably split it into two separate issues, but the conditional requirement thing doesn't work without being able to define requirements externally :P (at least with this API)

#

I guess the alternative there is something like

#[derive(Component)]
#[require(
    PhysicsTransform,
    if(without(Static), Mass)
)]
pub struct RigidBody;
thick slate
#

๐Ÿฅฒ

magic belfry
#

But yeah, we should first add App::add_require that takes just a single component for the first type param, and add conditional requires in a follow-up

#

Oh right, we also need to consider how to do custom constructors... it probably needs a separate App::add_require_with that takes a method similar to the require attribute's syntax

app.add_require_with::<RigidBody, SleepTimer>(my_constructor);

I'll add that to the issue briefly

queen oak
#

Made a comment

#

it's a great idea

#

the conditional requirements are probably a good idea but I haven't thought about all the edge cases hard enough yet

#

I love the plugin required component thing

crisp garden
crisp garden
#

What exactly are the plans for how/when bsn scenes would be spawned? We had some examples of scenes being spawned immediately from the bsn macro, but what about bsn from assets? Would it happen immediately unless the asset is unavailable, in which case it would happen after the asset is loaded?
Mostly curious since the current bevy_scene spawns things at this weird timing between Update and PostUpdate which works for visual stuff, but bsn would probably be used for a wide range of things within the same app, and I can't find anything about it in the proposal nor do I remember reading about that ๐Ÿค”

fluid dirge
#

Question going off of the above that may have already been addressed, but it would be cool to be able to preload bsn asset dependencies so that you can quickly stamp out copies of the scene when needed (I'm thinking for using them as prefabs)

wind dock
#

The question is, which assets do you preload or do you preload all of them? Seems like there are challenges with both. A reasonable alternative is the first time you add a prefab to a scene it gets loaded and subsequent copies are fast.

fluid dirge
#

I'm fine with preloading all of them, not as a default though

#

But essentially an asset server function like, preload_all(bsn_here)

#

So you would explicitly opt in on a scene by scene basis

wind dock
#

Yeah from an editor perspective this would definitely need to be an opt-in setting. Iโ€™d probably enable it too because all my assets fit in memory.

fluid dirge
#

Hrm from an editor perspective it's interesting, my thought process was, "if I'm going to shoot a bullet prefab, I don't want to wait to load the sprite on the first shot"

#

I could almost see a "dependent scene" resource or something that stores preloaded scenes you can opt into

#

Maybe not a resource

#

But basically if you load a scene, it can automatically preload prefabs for it

magic belfry
# split harness Responded!

Thanks! Yeah, I agree conditional requirements are probably much more controversial and require thorough consideration and design work.

#

I started working on a PR for runtime requires already. Got this working:

#[derive(Component)]
struct Bevy;

#[derive(Component, Default)]
struct FirstPartyPhysics;

struct MyBavyPlugin;

impl Plugin for MyBavyPlugin {
    fn build(&self, app: &mut App) {
        // Make `Bevy` require `FirstPartyPhysics`
        app.register_component_require::<Bevy, FirstPartyPhysics>();
    }
}

and register_component_require_with that takes a custom constructor like the require API

#

(names up for bikeshedding, requirement instead of require might read better here)

#

I'll probably have a PR tomorrow, mainly need to add tests and more docs

crisp garden
magic belfry
#

hmm this will be trickier than I thought because of recursive requires and ordering stuff

#

If I'm understanding correctly how required components work, a basic edge case here might be:

  • Plugin 1 adds requirement X -> Y
  • Plugin 2 adds requirement Y -> Z
    In this case, adding X should also add Z, but Z isn't in the list of required components for X since plugin 2 was built later. I think I need some required_by hash set or vec in ComponentInfo to propagate requirements up the tree as well
split harness
vast relic
#

would be nice to have async plugin init, then they could all register their requirements, and wait for every one of them to be finished with that part to continue ๐Ÿฅท

magic belfry
#

I think I might have it working now with recursive requires and everything... One of the trickier parts is handling different importance levels correctly, like if X -> Y and Y -> Z and you add X, then a separate X -> Z should be "more specific" than Y -> Z. The macro version handles this with just ordering and recursion, but at runtime there's no distinction between "direct" and "indirect" requires or priority levels. The way I'm currently handling this is by just tracking depths for the "requirement inheritance tree", which does add a bit of complexity, but it seems to work so far

#

(need to do a lot more testing tho, there are very likely edge cases to iron out still)

magic belfry
#

my first time really touching ECS internals so lmk if I'm doing something dumb anywhere lol

#

(cc @tribal yacht, I think you wanted this for automatically adding SyncToRenderWorld for retained rendering world stuff)

tribal yacht
#

Yes, I do want to use it that way

#

A small use, but maybe a nice bit of motivation for your PR

split harness
fallow cloak
#

@magic belfry I forget which of the items you made progress on, are there any others I could take?

magic belfry
magic belfry
timid leaf
thick slate
#

FYI @magic belfry

magic belfry
#

I'll open a PR for Visibility in a bit, it'll make a lot of the other migrations nicer too since they don't need to require the other visibility components separately

#

I'll also deprecate SpatialBundle in the same PR if that's fine

#

Or actually I'll leave that to a follow-up, deprecating SpatialBundle will be nicer once sprites, meshes, lights, etc. have been migrated since I wouldn't need to manually add Visibility everywhere ๐Ÿค”

thick slate
#

Yeah, that's a good order

magic belfry
#

Should we add C-Needs-Release-Note to all of these PRs? I'm assuming these will be combined into one or two sections in the post

thick slate
#

There'll be a section on Required Components already

#

Which will get into the end user changes

split harness
thick slate
#

Awesome ๐Ÿ˜„ Those are the two most important required components PRs: should make cleaning up the rest easier

split harness
#

Currently ruminating on the Material and Mesh port

split harness
#

I think both are pretty satisfying answers

magic belfry
#

Personally, I don't think bundles are a good option for it at least (worse ergonomics + inconsistency since we won't use bundles much elsewhere), and the combined Mesh2d/Mesh3d proposal with the mesh and material in the same component has the query problem, so I landed on proposal 2, with Mesh2d/Mesh3d and MeshMaterial2d/MeshMaterial3d in separate components. It also produced the nicest diff in my experiments (note: the branch isn't polished but the core migration is largely done iirc)

#

And yes, my idea was also to display a default material when the material is missing (I don't do this yet)

#

So I like proposal 3 is what I'm saying

split harness
#

Cool cool. Proposal 3 also has my preference. I suspect we might want "unrendered material-less meshes" at some point, but those should probably have new components anyway

#

Lets select Proposal 3 (modified to account for Material2d and Material).

I kind of want us to re-unify 2D and 3D meshes and materials, but thats a separate conversation

magic belfry
#

@split harness Did you have thoughts on the camera proposal? One thing I found to be kind of confusing in practice is that you'd expect to only need to add e.g. Camera3d, but quite often you'll also want to configure Camera, which is the core camera definition. So you end up adding two different camera components that look very similar based on the name.

Or more importantly, maybe you forget that Camera3d even exists, and assume that Camera is the 3D camera, especially since we drop the 3d postfix for many 3D types like Transform. And if I understand correctly, cameras without Camera2d/Camera3d don't do anything. I expect this to be a very common footgun with the current naming.

An example from my migration:

commands.spawn((
    // Forgot Camera3d? Too bad!
    Camera3d::default(),
    Camera {
        hdr: true,
        ..default()
    },
    Transform::from_xyz(-4.0, 5.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
));

I would be inclined to rename Camera to CameraConfig or similar to make it clearer that it's not the true "defining component" here, but I'm not sure if that's entirely accurate either, since according to the docs it literally is the defining component currently, and it has most of the data (even though the proposal doesn't show it). I think we could also split it into several smaller components, but that'll quickly expand the scope of the refactor here.

#

Also re: audio, we can't call it AudioSource since it conflicts with the actual AudioSource data. We could do just Audio, or something like AudioHandle or even AudioPlayer

thick slate
#

I like AudioPlayer

crisp garden
fallow cloak
#

From what I remember

#

Theyโ€™re basically configs for that

fallow cloak
crisp garden
#

Even Camera doesn't really define a camera well since it's split up into so many pieces, Projection being a pretty major one. Camera2d/Camera3d are the only ones that are really in a position to be able to require the rest tho ... It's kind of weird how Camera2d is a ZST, while Camera3d has data baked in tho ๐Ÿ˜‚

split harness
split harness
fallow cloak
split harness
fallow cloak
#

they're not the entry points for 2d/3d cameras, but 2d/3d cameras for the default render graph specifically

split harness
tidal hill
split harness
magic belfry
split harness
#

Worth discussing though. Definitely not saying we can't change things

golden notch
fallow cloak
golden notch
#

like ExtractedCamera == Camera, so it's kinda weird to have it be CameraSettings -> ExtractedCamera

fallow cloak
#

at least regarding my thoughts in #1262090782211309629

golden notch
#

imo

crisp garden
split harness
golden notch
#

yeah, i think that makes sense, relative to the idioms of required components favoring nice marker components even if you don't require specific extra config e.g. for your graph

split harness
split harness
#

Feel free to come up with proposals though for whatever you think should happen next

crisp garden
split harness
#

Or we could just move the Core2d label out of bevy_core_pipeline (and maybe rename it)

#

And same with the Camera2d / Camera3d components

cobalt stone
crisp garden
#

The main usecase would be the ability to disable pbr shading or swap out the renderer entirely without losing half of the engine and the ecosystem, and needing to update all your scene files, because everything is coupled to the renderer or bevy_pbr in one way or another for common concepts like a mesh, light sources, cameras, etc ... But I do agree that we shouldn't be adding on to the already confusing boundaries of the rendering crates, and probably have this be a part of efforts to improve it ๐Ÿค”

fallow cloak
#

this PR easily doubled my speed with vim ferris_spooky

magic belfry
#

@split harness fyi

golden notch
#

ah i see you want to do it in 0.15

thick slate
#

I remember seeing a ticket but it's a long weekend today ๐Ÿ˜‰

golden notch
#

i agree with the rationale in the pr that the bandaid should be ripped off if the desire is to move in that direction

#

that was my concern ๐Ÿ™‚

magic belfry
golden notch
#

nice that inventory is helpful to see

magic belfry
#

I also had this related comment #1282366304057036891 message

buoyant venture
#

Do we need an SME review for the mesh/material required component PR? It's mostly an ECS api change IMO and there's a ton of rendering PR that I need to get to so I'm trying to figure out the priority list for myself

buoyant venture
#

Welp, I couldn't help myself. I looked at it and I have some opinions so I'll leave a comment ๐Ÿ˜…

golden notch
# buoyant venture Welp, I couldn't help myself. I looked at it and I have some opinions so I'll le...

i totally agree with the 3d suffix bikeshed but didn't want to say anything lol. i also have been a bit confused about plans for the 2d vs 3d split, because as you mention it mostly seems like a question for higher level apis. like it's really more a split between pbr and non-pbr render graphs in that sense. for example, in nannou, which is mostly a 2d api with an ortho camera, we use the the 3d render graph even though it doesn't really make sense relative to our use of pbr features, i'd like to move to the 2d graph, but it feels too coupled to sprite stuff right now

buoyant venture
#

Yeah, other than sprites, 2d should essentially be 3d with orthographic projection (at least at the renderer level). At least that's what I want but I don't really have a super clear path forward. I'm mostly annoyed at how much code I copy from the 3d pipeline every time I try to improve 2d stuff.

magic belfry
#

Personally I feel the opposite way about the 3D suffix for APIs. Viewing 3D as "the default" at the API-level seems wrong to me, since it makes 2D feel like a second-class citizen in comparison. I like Godot's consistency here, like how it has Transform2D/Transform3D, Sprite2D/Sprite3D and so on. Leaving the suffix out also implies that it's a sub-type and not its own thing, for example if there were RigidBody2d and RigidBody types, then it sounds like RigidBody2d is just a kind of RigidBody, which isn't necessarily accurate imo.

#

Bevy itself is also wildly inconsistent in its use of suffixes at the moment

#

Also we do suffix tons of things with 3D already: Camera3d, many primitive shapes, 3D AABBs, numerous helpers...

buoyant venture
#

My point wasn't to say that the 3d suffix is bad. Just that introducing it here now also introduces an inconsistency. Bevy is inconsistent with many suffix, but AFAIK we don't suffix 3d anywhere currently

#

Oh, right, camera3d

#

To be clear I also don't like things that are suffixed with 2d. To me rendering is always 3d anyway. 2d is just 3d with an axis we try to ignore sometimes.

golden notch
# buoyant venture Oh, right, camera3d

i feel like in a perfect world we wouldn't even have camera2d/3d, since it's really just a convenience to help figure out what view bindings should be used and whether to do lights, which we could also determine based on whether any entities with a given pbr/sprite material share a render layer with that camera

fallow cloak
#

Camera2d/3d are used in a lot of places as filters for preparing pbr resources

golden notch
#

right, but that's mostly a performance thing, it's an implementation detail

fallow cloak
#

I mean Camera2d/3d aren't the defining camera type anyways (at least not what specifies the actual camera parameters)

#

they're markers for the rendering path to use

#

agreed that they're not necessary, or at least need a rename

golden notch
#

right, which is more a function of the entities being rendered than the camera. like there's no intrinsic reason that you couldn't render a pbr material and a color material using the same ortho projection

#

not saying we should refactor this or anything but i think speaks to some of the ambiguity here of 2d vs 3d

fallow cloak
#

we agree here ๐Ÿ˜…

I misunderstood

golden notch
#

it comes to mind, because in creative code, we actually often will do things like use a "constant" (color) material in a 3d space, which wouldn't make any sense for games but does for creative uses

buoyant venture
#

I don't want to derail this thread too much. I wanted to voice my opinion just in case someone comes up with something better, but I'd still prefer seeing required components with 3d suffix than sticking to bundles. This can always change in the future if we ever find something better but this will likely be part of a bigger refactor.

golden notch
#

yes, sorry for getting too off topic

fallow cloak
golden notch
buoyant venture
#

(just a guess to be clear)

fallow cloak
#

though I guess you want to skip a lot of the prep work in MaterialPlugin, etc.

golden notch
#

hence why all our stuff is like queue_material_meshes

#

in that sense, the api is the "mesh-material" api, not just the "material" api

magic belfry
golden notch
#

although it sounds like per consistentency the material trait should also eventually be Material3d

magic belfry
#

Yup, assuming it can't be reused for 2D (which currently it isn't)

cobalt stone
magic belfry
#

I can probably prep one in a bit, although I'm not sure what naming to go for ๐Ÿค”

#

Since MeshletMesh is the actual asset type

#

I guess MeshletMesh3d to be consistent with Mesh3d, but there's no 2D version so idk

cobalt stone
#

Ignore 3d, just MeshletMesh imo

magic belfry
#

so the component can be MeshletMesh

cobalt stone
#

I haven't kept up with the other PRs in this area, but when you have something request my review and I'll take a look

magic belfry
split harness
magic belfry
split harness
split harness
#

So excited for the improved clarity / terseness of bevy code. Once everything is ported everything is going to be so beautifully simple

crisp garden
#

The reduction in bundle clutter and improved performance characteristics make me want to port my game to main ๐Ÿ˜‚

quartz sleet
crisp garden
# thick slate Give us like... 5 days?

I would need to get DQF merged before I can port to main anyway ferris_sob
Not to mention remove that one bit of really awful code that would block the single biggest gain from required components my codebase could get thonk

magic belfry
magic belfry
#

(also I guess the problem could be something else entirely, it just happens specifically when I use different vertex color formats so I'm assuming it's related :P)

magic belfry
magic lava
#

@magic belfry I left some feedback on the mesh/material migration PR
Also, can I do the scenes migration PR? Or do you already have a bunch of PRs cooked up locally :o

magic belfry
magic belfry
magic belfry
crisp garden
#

Required components train ๐Ÿš…

fallow cloak
#

sprites as well once I fix merge conflicts ๐Ÿฅฒ

magic belfry
#

oh and render probes too

#

I had them in the light PR originally, but cut them out since there's no chosen API for it

#

After those, we'd only be missing sprites, scenes, text, picking, and UI. And the first three are being worked on by people

#

picking should be a quick and simple PR at least

fallow cloak
#

after I fix sprites I can pick up picking, though I don't have a ton of experience with that side of bevy

#

ah ok

magic belfry
#

I could probably do UI without the text part and hope #1248074018612051978 gets that part done to some extent with the text rework

native mesa
#

plan for the text refactor not being ready

#

is my advice

crisp garden
magic belfry
#

I think so

magic lava
magic belfry
fallow cloak
#

UI mostly (texture atlases), I cleared it out of sprites

crisp garden
#

Should be easy to find them once the PRs are done and we try to remove it ๐Ÿ˜‚

magic belfry
#

yup

magic lava
#

@magic belfry If the PR description looks familiar at all then you must have imagined it c:

split harness
magic lava
thick slate
#

FYI @ebon river

split harness
#

Definitely worth thinking about the removal logic. The naive "remove all requires" feels like a tool we want, even if it has footguns (given that it is a direct replacement for the bundle equivalent, which also suffers from that problem).

We may be able to build a smarter solution that handles most cases "safely" but I'm dubious

#

At first glance it looks like this PR tries to tackle both problems?

magic lava
ebon river
split harness
ebon river
#

The safe solution is indeed costly, and I didn't dare to implement caching, as it would go beyond the ะกommands struct.

crisp garden
#

Cached solution as in keep track of what components on an archetype aren't required by other components, then only removing those?

crisp garden
#

That would be a pretty useful tool then yea, there's a few examples with some ugly code that could've been avoided with a decently performing "safe" solution

#

But yea I do agree that having the "footgun" version is necessary for feature parity and a decent migration

thick slate
magic lava
#

Haha, nevermind

thick slate
split harness
# crisp garden Cached solution as in keep track of what components on an archetype aren't requi...

Yeah storing computed work in the archetype so we aren't doing expensive computation / allocation per entity. However before moving forward with any solution I think this needs more thought (see the "alternatives" section of this issue: https://github.com/bevyengine/bevy/issues/15580)

GitHub

A refreshingly simple data-driven game engine built in Rust - Issues ยท bevyengine/bevy

split harness
#

As a heads up to everyone else, I'm spending most of this week reviewing @rare whale's reactivity work, with the goal of establishing how to best integrate those ideas into BSN

#

My initial plan was to focus on getting the BSN baseline impl ready for people to look at, but Dreamer has been waiting long enough that I'd prefer to make some forward progress there first, in the interest of hopefully unblocking the ability to work in parallel toward a common result

crisp garden
ebon river
magic belfry
#

Now that the RC is delayed, I'm feeling a bit more experimental;

So, for the camera required components migration, we still have the issue of Camera sounding too similar to Camera2d and Camera3d. I imagine many might just use Camera on its own, especially as the docs state that it is "the defining component", which will be a huge footgun since it won't do anything without Camera2d or Camera3d afaik.

One option I proposed was that we could rename Camera to CameraSettings to make it clearer that its not the primary component for adding a camera. However, I don't think this is entirely accurate either. Overall, the component is currently treated as the "core" camera component, and even still, there's a lot of camera settings outside of the component as well.

I don't know how controversial this would be, but: could we just split Camera into several components? Instead of this:

pub struct Camera {
    pub viewport: Option<Viewport>,
    pub order: isize,
    pub is_active: bool,
    pub computed: ComputedCameraValues,
    pub target: RenderTarget,
    pub hdr: bool,
    pub output_mode: CameraOutputMode,
    pub msaa_writeback: bool,
    pub clear_color: ClearColorConfig,
}

There would be something like this:

#[derive(Component)]
#[require(RenderTarget)]
pub struct CameraViewport {/* ... */}
#[derive(Component)]
pub enum CameraOrder {/* ... */}
#[derive(Component)]
pub struct ComputedCameraValues {/* ... */}
#[derive(Component)]
pub enum RenderTarget {/* ... */}
#[derive(Component)]
pub struct Hdr;
#[derive(Component)]
pub enum CameraOutputMode {/* ... */}
#[derive(Component)]
pub struct MsaaWriteback;
#[derive(Component)]
#[require(RenderTarget)]
pub enum ClearColorSettings {/* ... */}

If we wanted, a CameraMarker component could still require most of these components, and then Camera2d and Camera3d could require that. A CameraQuery world query could help keep large queries manageable, if there are any.

#

In my opinion, this is more ECS-like and consistent with how we generally compose features and configuration. It makes queries more granular, moves the camera definition away from a central component, and fixes the original issue of there being a confusing Camera component.

thick slate
magic belfry
#

We probably need approval from Cart and rendering people for something like this, but I'll start working on an implementation to test it in practice

buoyant venture
#

I'm not sure how I feel about things like Hdr. It would make it a bit harder to discover, but I guess that's true for anything optional. Other than that the idea seems good

#

And it's nice to have more things in the ECS

#

the queries in the RenderWorld are gonna be massive though ๐Ÿ˜…

magic lava
#

Splitting viewport from computed values will make the world_to_viewport methods trickier to place

buoyant venture
#

Also, how would the is_active thing work? Would it be a component to make it active or inactive?

magic belfry
split harness
#

Ex:
"where does this 'common' camera property exist?"
"Oh yeah thats on the Camera component"

magic belfry
split harness
#

A CameraQuery world query could help keep large queries manageable, if there are any.
Imo any API that needs a custom query to make it manageable should be rethought

thick slate
#

I don't think we ever want all of the camera fields at once ๐Ÿค”

split harness
magic belfry
split harness
magic belfry
#

I intended that it would be mainly for internals, not public APIs

#

I can't think of when users would need more than three of the components for common use cases

split harness
#

Ah gotcha. Better, but imo still undesirable for complexity reasons. It should always be a last resort to eliminate large unwieldy queries. Imo it is (often) better to build an API where that isn't necessary in the first place

rare whale
#

Would a better name help? CameraOptions or CameraConfig or CameraParameters?

magic belfry
#

That's what my earlier proposal was, but I'm currently unsure if that's the right direction

split harness
#

In general I think the "API design rule of thumb" should be:

  1. Start by identifying a "core concept" (ex: in this case, a Camera)
  2. For all properties common to that "core concept", add them to a component of that name.
  3. For "optional" opt-in functionality, consider using a separate component (but in some cases it may still be preferable to use an Option<T> field)
magic belfry
#

Worth mentioning that there's three or four optional/boolean properties in Camera

split harness
#

Yeah we can definitely rethink whats in there currently

tired topaz
#

Whatever the final solution is, renaming the Camera to something like CameraParameters is nice.

And splitting the things up in multiple Components will be very detrimental in terms of discoverability, and even more so with the required component thing.

Since that eliminates any kind of discoverability from LSPs

#

That was previously provided through bundles

split harness
tired topaz
#

CameraCapabilities?

#

CameraFeatures?

rare whale
#

Another name CameraBase - because it's the base of both Camera3d and Camera2d

split harness
#

Camera2d "is a" Camera

#

Camera2d "requires" Camera

#

Camera2d: Camera

#

Etc

rare whale
#

In the C++ or Python world, Camera would be an "abstract base class", and have a name like "AbstractCamera".

split harness
#

I think the difference here is that Camera is not abstract. It is a concrete type with "driving" functionality

tired topaz
#

Yeah, I have definitely reached for camera, when I wanted camera3d

rare whale
#

Of course, the nerd in me wants to point out that cameras are just a metaphor anyway, it's really just a set of constraints on rendering, there's no lens or image sensor ๐Ÿ™‚

split harness
tired topaz
#

Maybe HDR and such are the lenses?

buoyant venture
rare whale
buoyant venture
#

Disabled by default fortunately

split harness
#

Perhaps we just need to provide a warning when someone spawns a standalone Camera?

#

Functionally that would amount to "you spawned a camera that doesn't have a render graph configured"

#

Ex: "Entity {entity} has a Camera component, but it doesn't have a render graph configured. Consider adding a Camera2d or Camera3d component, or manually adding a CameraRenderGraph component if you need a custom render graph".

#

I'm pretty against the concept rename, as it feels like a rejection of the idea that "Camera2d is a Camera". We should have a Camera concept

#

We've built a system that operates under the assumption that Cameras exist. And game developers expect a system where Cameras exist

magic belfry
#

mm I don't love it but I can't really verbalize why, it just doesn't feel ideal to me... but I could make a PR with that to get the initial required components migration going at least

#

feels wrong to configure both Camera and Camera3d :P

commands.spawn((
    Camera3d::default(),
    Camera {
        hdr: true,
        ..default()
    },
));

There are like 50 instances of this in Bevy's repo. For both clarity and ergonomics I'd prefer something like this

commands.spawn((Camera3d::default(), Hdr));
#

Which is why I suggested splitting Camera into several components

fallow cloak
#

hdr I can imagine being split

split harness
fallow cloak
#

but the rest feels like it might make things in the render world painful

split harness
fallow cloak
#

yeah

magic lava
#

I don't like the situation with Camera and Camera3d/Camera2d, but I don't think splitting things to this extreme improves things

fallow cloak
#

I can imagine a world where it's instead handled by Camera2d/3d since it's part of the render graph config, but that's not how things work currently

split harness
#

Ideally the vast majority of cases look like this:

commands.spawn((
  Camera3d::default(),
  Transform::from_xyz(0., 0., 0.),
))
fallow cloak
timid leaf
magic belfry
split harness
fallow cloak
split harness
#

The X requires Y "inheritance pattern" (aka "X is a Y") is something that we will see increasingly. This conversation kind of feels like a rejection of that concept.

#

(one of the reasons im holding this line so hard)

magic belfry
#

I agree in theory but I see it as pretty footgunny and implicit in cases like this where the names are so close

frosty shell
#

Transform isn't a GlobalTransform

fallow cloak
split harness
#

Feels like "RedPlayer is a Player / RedPlayer requires Player" is the exact same category of thing / suffers from the same "problem"

#

But its also a pattern I think we should encourage

split harness
timid leaf
#

I'll happily reject inheritance. Required components looks more like composition than inheritance. You are collecting components and their behaviors into your final 'thing'. So Camera3d is your 'camera thing', and CameraConfig or CameraBase is gathered as part of your final (conceptual) object.

split harness
#

(aka this case)

timid leaf
fallow cloak
split harness
#

In both of your cases, talking about spawning a CameraConfigor a CameraBase as the "top level concept" is pretty unsatisfying

#

You aren't spawning a CameraConfig. You're spawning a Camera

timid leaf
fallow cloak
#

if a name change is in order I don't think it should be for Camera

split harness
rare whale
tired topaz
timid leaf
tired topaz
#

its a matter of perspective

#

looking from inside the "Game Engine" and out on the application. Tends to give quite a different perspective as to looking into the "Game Engine" from the application

fallow cloak
magic belfry
#

What I imagine a user would want (and what I would want) is to just spawn a Camera2d and then add optional components to configure that camera. They shouldn't need to care that rendering actually uses a Camera, and that Camera2d really just enables some rendering pipelines to facilitate 2D

tired topaz
#

I believe this entire discussion forum is by right mostly composed of people being inside the "Game Engine" looking out onto applications, since the actual Game developers seems to be a minority, and not very vocal

tired topaz
fallow cloak
tired topaz
#

Imho, this would be where bundles would still make some sense, because Camera3D without the Camera is... nothing?

#

hence the requires I assume

fallow cloak
tired topaz
#

PBRCamera and then every user would be confused ๐Ÿ˜„

fallow cloak
native mesa
#

or a world where Camera3d is optionally less of a hook into the built-in pbr stuff

fallow cloak
native mesa
#

yep, reasonable. i feel like the way to do that might be to add a runtime required component to Camera3d in the PbrPlugin

#

idk

#

would prefer if it was explicitly tied to pbr

magic belfry
# magic belfry What I imagine a user would want (and what I would want) is to just spawn a `Cam...

Again in my mind there shouldn't necessarily be just a Camera component, but rather different components that describe a camera in a way that doesn't have the confusing semantics. I.e. split out the viewport stuff, render target, camera order, and so on in some form (where possible). Then to define "a camera", you compose it out of those components, or in the case of Camera2d and Camera3d, you just require them.

#

I don't think a camera should necessarily be described by "this has Camera" but rather "this has the components that make up a camera, driven by CameraX".

fallow cloak
#

I think down that path lies pain for the rendering devs

#

also, if this is mostly about specification from a user perspective, doesn't the fancy bsn patch stuff avoid that entirely? (misunderstood earlier point about (Camera3d, Camera { hdr: true } )

native mesa
#

the key difference is, i think, that game engine systems don't need to update the camera data.

#

users configure the camera data, and that causes various other engine systems to run.

#

this is a pretty different control pattern, compared to say Node where user and engine systems are going to be updating the state all the time, or GlobalTransform where it's an 'output' of the engine.

#

We are planning to do basically exactly what he is proposing with transforms, i think.

magic belfry
#

I'll make a PR for the approach Cart suggested, simply leaving things as is but emitting warnings when a Camera is inserted without Camera2d / Camera3d / some other pipeline. I still don't love the approach though, so I'll probably experiment with what I'm personally imagining later.

crisp garden
granite otter
#

what if there was a with_hdr() method on Camera3d that set hdr to true on the Camera using a custom constructor on the require? (which iirc is a thing) ๐Ÿค”

fallow cloak
granite otter
#

I'm not sure. I think they only allow for deriving the value from the world

#

unless you could pass an In to it

#

ah, they're simple argumentless functions actually (at least in the required components PR example), nevermind

thick slate
split harness
magic belfry
#

the diff is pretty nice (but I still dislike having Camera and Camera2d/Camera3d in the same spawn ferris_sob)

#

the earlier example of "RedPlayer is a Player" makes sense, and the same logic works for cameras, but I would also find it weird if I had to add both RedPlayer and Playercomponents manually to configure something

#

and not just add RedPlayer that requires a Player marker, and have config in separate components

#

anyway, I'll stop arguing about this for now and get some sleep

split harness
split harness
# magic belfry the earlier example of "`RedPlayer` is a `Player`" makes sense, and the same log...

Imo this is just a downside of implementing inheritance patterns on top of composition. It has pretty significant benefits (especially in languages like Rust without traditional inheritance), but it also means people need to address multiple levels of the "inheritance hierarchy" at the same time.

If someone creates some new:

#[derive(Component)]
#[require(Camera3d)]
pub struct MyCamera3d {
}

They will also encounter the MyCamera3d, Camera3d, Camera "conceptual stutter". Imo its just something people will need to get used to (and using the pattern internally for things like Camera3d will help normalize it).

#

It has pretty significant benefits
Ex: even if Rust supported "traditional inheritance", it would still probably make sense to implement this with "compositional inheritance" for queryability and memory layout reasons

rough cave
#

I'm a bit nervous about the amount of discussion orienting around inheritance, it feels like the use of inheritance increasingly comes under scrutiny these days, to the point where the language we are using has opted to omit it entirely. Some, including me, generally encourage the avoidance of all behaviour & data inheritance (at least in public APIs), only encouraging interface inheritance. Are we potentially going down a dangerous road by trying to introduce inheritance concepts into Bevy design/discourse (discussing "is-a" relationships?), e.g. worrying about "RedPlayer is a Player", "BaseCamera", etc.?

crisp garden
#

I don't think inheriting data (like what BSN would support) is as much as an issue, but I think it's less about "focusing on inheritance" here, but rather "The API we now have resembles inheritance, which isn't great with our current pattern"

#

Or well, it works fine, it just looks stupid ... Which is probably a good thing, because it isn't the ideal pattern

fallow sinew
#

I feel this kind of inheritance is acceptable. You can reskin it a different way but at the end of the day itโ€™s just a format to define entity structure. Whether you โ€œinherit RedPlayer.bsnโ€ or โ€œadd RedPlayer.bsnโ€ via a component/strategy/other pattern, it still has to figure out how to apply those templates, allow overrides, etc.

#

And it all still flattens out to just components once spawned

#

And Iโ€™d rather reduce duplication across BSN files than have to re-define components multiple times

crisp garden
#

Yea as long as we're still doing composition it shouldn't really matter, all it is is components with slightly ugly stuttering names if they all get listed

#

Like MyCamera3d, Camera3d, Camera looks bad but it doesn't really matter

native mesa
#

there is a very natural link between ecs composition and inheritance: if one component requires another component, then it's very similar to a multiple-inheritance system.

#

what we don't have are interfaces, abstract classes, or mixins, as far as I can see.

dapper sky
#

A lot of the problems with "inheritance" are its relationship with wider OOP patterns, in this situation it's a looks-like-oop-inheritance behaves-like-composition thing, or am I wrong?

native mesa
#

i think that's it. it is just composition when it comes down to it, but it's composition which does lend itself to the "parent/child" or "is a" semantics. and because OOP has been around for a while, I think it's natural to use the language it introduces for dealing with "requirement relations".

#

trait queries, or required trait components would start to push us down the actual OOP path, but there's not much interest in those (and the latter may be impossible).

hybrid bloom
#

the requirement relationships between components are actual data dependencies, so I don't think it's really the bad part of OOP inheritance

dapper sky
#

instead of a behaviour-that-overrides-behaviour-that-overrides-behaviour approach, it's behaviour-that-sits-beside-behaviour-that-sits-beside-behaviour

#

(apologies for the semantic satiation)

dapper sky
fallow sinew
#

Sits beside or replaces

fallow cloak
#

It worked before the changes to texture atlases though, which is strange. I'm not the most familiar with sprite code but I feel like I should be able to spot this ๐Ÿ˜…

fervent rock
fallow cloak
fallow cloak
fallow cloak
#

Oops, fixed

fallow cloak
#

so much easier to migrate a bundle with less than dozens of uses lmao

thick slate
cobalt stone
#

@fallow cloak do you mind taking a look at porting meshlets, and figuring out why they're not rendering on main ATM?

fallow cloak
#

I could take a look yeah

#

Canโ€™t promise anything though, starting tomorrow my week is incredibly busy

cobalt stone
#

Np

fallow cloak
# cobalt stone Np

ok yeah this is strange. They're getting rasterized and written to depth properly, but getting completely clipped from actual rendering?

cobalt stone
#

Maybe try bisecting to find the commit that broke it

fallow cloak
cobalt stone
#

My beatiful bunnies, like what they've done to them D:

fallow cloak
#

reviews for sprites pls? ๐Ÿฅบ trying to avoid more merge conflicts if possible ferris_sob

royal python
#

There are 2 different sprite PRs, is there consensus about which one we're going for?

fallow cloak
#

I like the way I implemented it though, splitting Sprite up into two components feels weird

royal python
fallow cloak
#

naurrrr there's already more conflicts ๐Ÿ˜ญ

#

ok that wasn't too bad. fixed!

fallow cloak
#

what's left before we can remove impl Component for Handle<T>?

royal python
#

Try it and see what breaks lol

crisp garden
#

Yea remove it and check the errors

magic belfry
#

meshlet meshes and materials at least, and sprites (which you have a PR for)

#

meshlets might not give errors in editor since they're behind a non-default feature flag

fallow cloak
#

I think UI used it as well, though I forget if that's been migrated

magic belfry
#

it hasn't, I was told to wait for text rework + Interaction yeet

#

but I might do it tomorrow or on wednesday anyway even without those

fallow cloak
#

meshlets slughollow

magic lava
#

Looks like the query_gltf_primitives example somehow made it in without being ported to the new materials/meshes rework

#

I'm making a PR to remove Handle component usage from inside bevy_gizmos, will take a look at animation after

crisp garden
magic lava
#

Yeah, almost forgot to remove the line where the handle was being inserted in my PR just now ๐Ÿ˜…

magic lava
queen oak
#

Why is handle as component considered an antipattern btw?

fallow cloak
#

they don't indicate what functionality they enable usually

magic belfry
#

look at the billion bugs it has caused us during this migration ferris_spooky

magic lava
#

Or -- for most assets -- they don't have any functionality to begin with

fallow cloak
#

in some places adding a handle component will do something, other places it's a requirement that other components have implicitly

#

you also shouldn't really ever have a system that queries all handles of a certain type, since they're probably used in different contexts

crisp garden
#

The scariest one I've seen is when plugin A exposes an asset but no functionality, and then there are two separately developed plugins (B and C) that both do something with Handle<AssetA>

#

"Oh you didn't want this mesh to be a collider AND rendered? Well that's unfortunate"

#

Not to mention the issue of not being able to define required components on them (tho at least Jondolf's PR added a way to do that anyway, even if it is extremely hard to discover)

magic lava
magic belfry
#

And then ignoring the inherent issues with handles as components; specifically in the context of this migration, previously you could have a Handle<Mesh>, but now it must be wrapped in a Mesh3d because of required components (meshes must require e.g. transforms and visibility, and you can't do that with handles, unless adding runtime requirements). This change is a huge footgun and migration pain as long as handles are components, since all queries and inserts that use the handle are now implicitly broken with no warnings whatsoever. We've already had like 3-5 bugs merged into main because of this

thick slate
nocturne lotus
queen oak
#

i see

magic belfry
#

I mean it's not exactly the same, like if we had f32<Speed> (similar to Handle<Mesh>) then it does have some associated semantics given by the type argument. But yeah it's still not good either, and like Nise said, you could want e.g. both meshes and colliders to use mesh handles, but different ones, which requires wrapper components

nocturne lotus
#

ig with Handle<T>, the T could itself be labeled data. but it could also be unlabeled data like f32, so the blanket impl is problematic

hybrid bloom
#

You might want someone else to double check this, but I suspect that in the case of AnimationGraph, the handle could just become a field of AnimationPlayer

magic lava
magic belfry
magic belfry
slate pewter
#

what change made it so that Handle<T> components break everything?

magic belfry
#

required components

magic belfry
magic belfry
#

we can easily replace that logic I imagine

#

and yeet the plugin maybe

magic lava
#

Oh, yeah. It doesn't look too bad

#

I'm hitting errors from the UiMaterialPlugin so that will have to come first then :u

quartz meteor
#

working off bevy main and noticed Observer is no longer generic which breaks queries like this:
Query<(), With<Observer<MyEvent, ()>>>
is there a new equivelant to querying for observers of specific events?

thick slate
#

moved to #ecs-dev