#Next Generation Scenes

11848 messages · Page 12 of 12 (latest)

vapid forge
#

much nicer tho IMO

split harness
#

Its just sugar for what I was expressing

vapid forge
#

anyways. I sense you're pretty set on @SceneComponent and not my *SceneComponent idea?

split harness
#

But yeah I agree its much nicer. That has always been the dream. Glad we finally have it

vapid forge
#

Allright, should i see how hard that is to get working right smack-dab in the middle of my docs and tests changes?

#

make it a proper "a lot of bsn changes" PR instead of just docs/tests?

#

or rather split it out?

split harness
vapid forge
#

what about * for those? we kinda need some new symbol no?

split harness
vapid forge
#

that was why i thought it fit...

#

hm

#

what about just .?

#

tho that can read as a call chain

#

# isn't ideal because attribute macro. or maybe that works as attribute macro requires #[

#
$Template
%Template
>Template
~Template
=Template
split harness
#

Kind of weirdly ambiguous:

bsn! {
  Foo
  .Bar
}

vs

bsn! {
  Foo.Bar
}

Foo.bar vs Foo.Bar isn't actually ambiguous if we don't want it to be. But its a weird distinction imo

vapid forge
#

yeee

vapid forge
split harness
#

Perhaps we should just cut template patching for now. I think it will come up eventually, but its niche

vapid forge
#

perhaps. we could also just change the prefix to something but leave it undocumented in case it does come up?

split harness
#

I want to save -Thing for "removal patches"

vapid forge
#

from the options i listed i like + and ~

#

+ probably more

vapid forge
frosty shell
#

If template patching is cut I'd like to make sure one-shot system templating is in 0.19 (I have both a prequel PR posted and the actual PR ready to be updated once the prequel is in)

vapid forge
#

thats always gonna be a (ugly) escape hatch i think

frosty shell
#

yea I don't like that

vapid forge
#

tho tbf we're specifically talking about the feature which currently uses the @ operator as a template prefix

#

is that something you have a usecase for @frosty shell?

split harness
#

I'm going to break for lunch!

frosty shell
#

yea if one-shot system templating isn't part of 0.19 then I would be using @SystemIdTemplate { ... }

vapid forge
#

ahh, gotcha

#

do you have a preference out of these?

frosty shell
#

not really glajj

split harness
#

! is "not" in Rust and should probably be axed

#

+ is semantically "add" pretty much everywhere and should probably be axed

frosty shell
#

whats the issue with @?

split harness
vapid forge
split harness
#

As they already use @prop for their "prop fields"

frosty shell
#

ah ok

#

$Template {} feels sufficient to me then

vapid forge
#
$Template
%Template
>Template
~Template
=Template
#

slowly but surely whittling down the options

split harness
#

Yeah $ is really the only one that doesn't have existing semantics in Rust

vapid forge
#

does ~?

frosty shell
#

could also consider a custom keyword

split harness
#

It used to 🙂

vapid forge
split harness
#

Earlier

vapid forge
#

ah

frosty shell
#

~T became Box<T> i think, pre 1.0

vapid forge
#

i'd say thats squarely in the "its fine to use it then" range

split harness
#

Yeah I don't think its a big deal

vapid forge
split harness
#

~ does feel slightly less gross to me

#

Its all "gross" at the end of the day

vapid forge
#

yeaaahh $ invokes associations with bash for me

frosty shell
#

the latter, but it also matches the "magical" feeling of patching via template rather than component

#

whether that's a good feeling or not, shrujj lol

vapid forge
#

i vote for "we go with ~ for now and see if during PR/review anyone has a good argument against it"

split harness
#

(now im really breaking for lunch)

frosty shell
#

would be nice to get a visual comparison of the two in a decently sized bsn! invocation

#

if someone happens to have one they can edit on hand

vapid forge
#
let scene = bsn! {
   :some_scene()
   #SomeName 
   ComponentA 
   @Template
   ComponentB(0.0)
   @Template
   Node {
       height: px(0.1)
   }
   on(|evt: On<MyEntityEvent>, mut query: Query<&mut ComponentB>| {
       let mut b = query.get_mut(evt.entity).unwrap();
       b.0 += evt.value;
   })
   Children [
       #Child1 ComponentA 
       ,
       (:other_scene() #Child3),
       Link(#SomeName),
       ~Template
       @MySceneComponent {
           @some_prop: 3,
           normal_field: 5
       }
       ~Template
       Node {
        width: some_variable
       }
       ComponentB({some_variable + 3.})
       $Template
       :Container {
           @items: {
               bsn_list![
                   #item1 SomeComponent,
                   :some_scene()
                   #item2
                   $Template
               ]
           }
       }
   ]
};
#

perhaps my commented 'showcase everything' one wasnt the way to go...

frosty shell
#

yea sure ~ seems fine

vapid forge
#

sprinkled in some $ versions

#

yeah i prefer ~, its way simpler. $ is very "noisy"

#

@ is also "noisy" buuut eh

#

okay, so to recap:

  • : will not be called "inheritance" anymore, but instead "cacheable" (name not final)
  • the Template patching prefix changes @ -> ~
  • the SceneComponent prefix changes : -> @
  • the : prefix is allowed in front of @SceneComponent as well, marking it as being cached

open questions:

  • should : be allowed multiple times now? Is there a reason to still enforce this if it just means cacheing?
  • what happens with scene expressions: { bsn!{ #Foo } } in scene entry position? Do we allow : prefix?
  • do we forbid caching of functions which take an argument? I think no, now that its explicitly just "cacheable"
  • can we standardize on a term for the scenes which are merged here? maybe "base"?
topaz ginkgo
# vapid forge ```rs let scene = bsn! { :some_scene() #SomeName ComponentA @Templ...

My opinion might not be worth much here - but I’ll just say i am personally not a fan of how this is looking. I feel this is not particularly readable, nor user-friendly. Might just be a skill issue my side, but there are just way too many “special characters” here doing specific things. Perhaps I am over complicating things or just missing something very basic

vapid forge
#

for the one i linked, these planned changes would not change a single thing

vapid forge
frosty shell
vapid forge
frosty shell
#

the ugly one

vapid forge
# frosty shell the ugly one

like this

let scene = bsn! {
   :some_scene()
   #SomeName 
   ComponentA 
   ~Template
   ComponentB(0.0)
   ~Template
   Node {
       height: px(0.1)
   }
   on(|evt: On<MyEntityEvent>, mut query: Query<&mut ComponentB>| {
       let mut b = query.get_mut(evt.entity).unwrap();
       b.0 += evt.value;
   })
   Children [
       #Child1 ComponentA 
       ,
       (:other_scene() #Child3),
       Link(#SomeName),
       ~Template
       @MySceneComponent {
           @some_prop: 3,
           normal_field: 5
       }
       ~Template
       Node {
        width: some_variable
       }
       ComponentB({some_variable + 3.})
       ~Template
       @Container {
           @items: {
               bsn_list![
                   #item1 SomeComponent,
                   :some_scene()
                   #item2
                   ~Template
               ]
           }
       }
   ]
};
frosty shell
#

yea that seems manageable

vapid forge
#

tho note i'm really pushing it here

#

also not using consistent formatting etc

frosty shell
#

in a real world situation i would probably break out the children into separate bsn! invocations

vapid forge
#

yup

#

i would probably not have almost every concept in a single macro in the first place

topaz ginkgo
#

Appreciate this is an extreme scenario

vapid forge
#

this is a pretty reasonable bsn! scene function, one which i would wager is clear enough if you've spawned bundles in bevy before

topaz ginkgo
vapid forge
#

theres definitely still ways to make it look very ugly in "normal" usage, like, just look at the feathers_gallery example... but thats more a case of "nobodys bothered to split that into functions

frosty shell
#

yea ~Template { ... } isn't expected to be a commonly used construct, but is still necessary to support as an extension point

vapid forge
#

I do think overall these changes will make it way less confusing to newcomers, especially as they allow docs to be far less confusing

vapid forge
white lichen
#

~Template looks like a destructor

frosty shell
#

c++ user spotted

topaz ginkgo
#

Just a cautionary tale from my end 🙂

frosty shell
#

what would you suggest as an alternative?

#

keywords?

vapid forge
split harness
# vapid forge okay, so to recap: - `:` will not be called "inheritance" anymore, but instead ...

should : be allowed multiple times now? Is there a reason to still enforce this if it just means cacheing?
No: this limitation was always motivated by the fact that caching requires it.

what happens with scene expressions: { bsn!{ #Foo } } in scene entry position? Do we allow : prefix?
In theory we could, but id prefer to punt this until it comes up

do we forbid caching of functions which take an argument?
We should forbid it until we support it, and I don't plan on supporting this in the short term, as it adds new controversial design aspects to the system (building a mapping from parameters to cached scenes, ensuring the parameters are all hashable, etc).

#

can we standardize on a term for the scenes which are merged here? maybe "base"?
Wht do you mean by "merged" here? Like :scene?

#

An alternative name for "cached" or "inherited"?

vapid forge
#

well, inherited, yes

split harness
#

I think "cached" is probably the best / most descriptive term for now, if we aren't using "inherited"

vapid forge
#

oh no thats not what i meant, thats clear to me

#

i'm probably being a bit tooo tired

vapid forge
#

thats not what i was trying to ask

#

like, we have a bunch of scenes which get patched on top of the previous ones. What do we call the scene that is in relation to the current one the source of a list of patches?

#

idk if that makes sense

#

I'm going to sleep for the night, if anyone wants to try and help me by finding a spurious macro parsing failure, here ya go: https://github.com/laundmo/bevy/tree/bsn-prefix-shuffle
just look at the tests in bevy_scene/src/lib.rs for "expected identifier". Best i can tell that error shouldn't be showing up and it should parse fine

jaunty pewter
viral roost
vapid forge
lime veldt
#

just want to chime in with - always has a NOT meaning in my head so unless this is what it would do if it was a valid bsn token, I'd rather not have it included

leaden dew
#

are scene props going to be usable in contexts other than scene components in the future? if so, it feels very strange to be unifying them syntactically under the @ character

#

i like it if it means i can glance over any cluster of @s and quickly understand "this is shaped like a scene component" but only if that's consistently true

bitter patrol
#

I just love that what started as a little rust engine is now heavily entangled in a DSL design discussion

#

I wonder whether we will end up (in quite some years) with a DSL akin to SQL that also ends up covering queries, spawn/mutability semantics and/or maybe even simple functionality that ends up superseeding this current bsn!

#

all this given that we went down the path of a DSL for bsn while for queries we're still using plain rust

jaunty pewter
jaunty pewter
#

If you squint hard enough you can sort of argue that they're similar to the $ token used in other templating languages (maybe a bit reaching though)

jaunty pewter
jaunty pewter
vapid forge
#

specifically, it somehow thinks the : should be a Identifier. My guess is that theres an error in the actual scene component branch which maked the parser back off and try the next branch which fails on the ident, but i'm struggling to debug it

vapid forge
karmic rock
#

All things that have been discussed in the past, but looks like bevy is taking a very different route (a scene representation that exists outside of the ECS)

vapid forge
vapid forge
#

What does it mean then for the scene representation to exist within/outside of the ECS?

karmic rock
#

It means that when you load a scene file, its entire output is ECS primitives (like entities & components). The ECS has native support for things like prefab inheritance, property overriding, variants etc. Flecs script is just an object notation frontend for the ECS.

vapid forge
#

Ah, hmm. Then i suppose the question is what it means for the ECS to have native support for that

karmic rock
#

Yes, and it looks like bevy is not going that route. With BSN, an editor will be modifying the BSN AST which exists adjacent to the ECS.

vapid forge
#

I suppose the difficulty i have with this is differentiating betwen "ECS has native support" and "ECS just happens to be storing this"

#

as in: if the BSN AST happens to be stored in a component, does that mean the ECS has native support for it?

karmic rock
#

No, because applications would still need to read the BSN AST in order to make modifications to the scene

vapid forge
#

hmm, and i suppose in flecs the API to interact with the scene representation is the ECS?

karmic rock
#

Yeah, and "scenes" (prefabs in flecs) are just plain entities with components + a feature called inheritance (that does actual inheritance)

vapid forge
#

i am so glad i managed to convince cart to rename bsn "inheritance" to something more sensible

karmic rock
#

So you can do things like

prefab Unit {
  Health: {50}
  Attack: {10}
}

prefab MeleeUnit : Unit {
  Attack: {100} // override
}

my_unit : Unit { } // instance
#

Unit / MeleeUnit are plain entities with a Prefab tag

vapid forge
#

gotcha, and "spawning" the prefab means copying/cloning the entities and removing the tag?

karmic rock
vapid forge
#

ah, so scenes/prefabs aren't technically "spawnable" in that sense

karmic rock
#

In code it looks like this:

entity Unit = world.prefab(); // same as world.entity().add(flecs::Prefab);
entity MeleeUnit = world.prefab().is_a(Unit);
entity my_unit = world.entity().is_a(MeleeUnit);
karmic rock
#

(which also spawns children etc)

vapid forge
#

yea but at the root there has to be a non-prefab entity?

#

(if you want to actually use the created structure for application logic, i mean)

karmic rock
topaz ginkgo
karmic rock
topaz ginkgo
#

That has felt easier to me when editing the AST

vapid forge
karmic rock
# vapid forge would this be the point at which property overrides are applied/flattened?

Overrides are at the component level. What happens is that you can mark a component inheritable like this:

world.component<Attack>().add(OnInstantiate, Inherit);

When a component is inheritable, it's not copied to the instance when instantiated. Instead it'll be shared across instances. When a component is not inheritable (the default behavior) it's copied to the instance. Functions like e.get<Attack>() and queries automatically resolve inherited components.

#

So when you have a 1000 instances of a sword, you're not copying the same static data 1000 times. Better for caching, and also speeds up spawning (because no need to clone values)

vapid forge
#

Is that technically resolved every time e.get<Attack>() is called?

karmic rock
#

No that'd be slow

#

What happens is:

  • get tries to find the component on the entity
  • if it doesn't find the component, check if component is inheritable
  • if component is inheritable, traverse IsA relationship until you find a base entity (prefab or not) that has it
#

On queries this is amortized (stored in the cache), so you don't do the lookup each time you iterate the query

#

Say that Attack is inherited, and Health is not. What you'd see if you were to inspect the components of an entity is something like:

Health, (IsA, Unit)

and if you looked at the components of Unit, you'd see

Attack
vapid forge
#

i gtg, but this was very informative, thank you

karmic rock
karmic rock
#

It's harder to do a good integration, but the end result is simpler (as evidenced by the confusion around the new terminology etc)

vapid forge
# split harness > should : be allowed multiple times now? Is there a reason to still enforce thi...

re: forbidding caching of scenes with arguments. In the SceneComponent case, theres no syntactic way to differentiate between a SceneComponent with default props or a SceneComponent with no props.

This means with the current design, the SceneComponent when called with default props can be cached. I dont think this is an issue, since default props and no arguments acts the same.

But it does bring up an interesting idea: If someone wants to cache a scene(component) with arguments, they could define a new scene which just specifies the arguments they want to cache and doesn't itself take any.

fn uncacheable(arg: u8) -> impl Scene {
    bsn!{
        Foo(arg)
    }
}

// user code:
fn make_cacheable() -> impl Scene {
    bsn! {
        uncacheable(8)
    }
}

fn use_cached() -> impl Scene {
    bsn! {
        :make_cacheable()
    }
}

is this a pattern we want to document/talk about?

vapid forge
# split harness I think "cached" is probably the best / most descriptive term for now, if we are...

After sleeping on it, i'm able to hopefully more clearly communicate what i was trying to ask here:
being "cached" is an adjective, its something a scene can be. But i'm looking for a term which describes any scene who's patches are applied to the current one.

Example sentences, with <base?> as the placeholder:

A Scene can contain many <base?> scenes, but only the first can be cached.

The cached <base?> scene needs to be the first scene entry.

When the first <base?> scene isn't cached, its patches are applied to an empty ResolvedScene. If its cached, the cached ResolvedScene with those patched applied is used instead of re-applying patches from the first <base?> scene

#

Another important quality for the ideal terminology here is that it supports sensible verbification (the process of creating a verb from another word class).

#

I think composition, with the verb being "composed", works independently of the other term, in case theres no better idea

rare whale
vapid forge
scarlet gazelle
#

Part of me wants to suggest "root", but I'm not sure that works well as a verb...

vapid forge
#

i mean, root isn't bad, the downsides are similar to base

scarlet gazelle
#

I'm not sure if I saw it earlier, but what are the downsides of base exactly?

vapid forge
#

well, it kinda implies theres only one, and it still has connotations of inheritance

scarlet gazelle
#

Maybe fragment? Although I think that has the opposite issue of 'base'.

vapid forge
#

yea

#

i might go with base but only when its absolutely necessary, working around mentioning it by name otherwise

scarlet gazelle
#

attach maybe?

#

But yeah, maybe base is just the best for now...

jaunty pewter
# karmic rock All things that have been discussed in the past, but looks like bevy is taking a...

sigh I wonder if Bevy would be much better off if it takes lessons from Flecs from the start instead of re-inventing things.

Things like relationships and X-as-entities took so long to get off the ground. And yet the former is still very incomplete and the latter still feels janky and tacked-on-at-the-last-minute. I can imagine if they were designed together from the start, it would feel so much more coherent and elegant.

And now it seems that the tradition is once again repeated for the scene system.

Sorry for the offtopic negative rant... I still very much would like to believe in the possibility that all of this will turn out better than Flecs.

vapid forge
#

For the term for what happens when a scene is referenced in another scene:

I just had an idea. Well, kinda, my dad prompted me to re-consider something i'd instinctively dismissed: "include"

I'd dismissed it because i've always seen "include" mechanisms as simple "insert the other file here" mechanisms.

But doesn't "include" fit basically perfectly? Its close to what happens on a syntax level as well as the mental model. "included scenes" and "scene include" i think work pretty well. The "primitiveness" it implies actually matches BSN surpridingly well.

vapid forge
split harness
# jaunty pewter *sigh* I wonder if Bevy would be much better off if it takes lessons from Flecs ...

I don't really want to re-defend design decisions every time @karmic rock decides to drive by with "things are better in Flecs land" posts (which we've already discussed at length).

In short:

  • The scene represenation being outside of the ECS vs "in" the ECS is an open question. We aren't "ignoring" the Flecs approach, its been a constant part of the discussion. Especially once "Assets as entities" lands, I suspect we will partially or fully move things into the ECS.
  • Not treating components as the "source of truth" for Scenes is intentional, as they cannot retain the full expressive power of a scene system like BSN on their own (Scene -> Component is a "lossy conversion"). Put another way, dynamic scenes aren't always round-trip-able. Bevy chooses to embrace this throughout the system, which makes everything "cross compatible" with itself. Flecs chooses to have two separate systems (prefabs and templates), where prefabs are "component driven", roundtrip-able, and less flexible and templates are closer to the AST approach (slightly reductive but my time is limited). We are still discussing how to go about this for known-to-be-fully-static things on the Bevy side. We may very well go for "roundtrippable component hierarchies", but that comes with its own sets of tradeoffs. Both Bevy and Flecs are tackling the same problems, we're just drawing the boundaries slightly differently (its kind of "inside out" vs "outside in").
  • We are exploring Flecs-like "entity inheritance". I'm not yet convinced this is the right move for Bevy, but it is on the table.
  • Flecs uses component-level granularity for patching whereas Bevy uses field-level granularity. This approach results in a variety of tradeoffs on both sides (#1264881140007702558 message)
rare whale
vapid forge
rare whale
vapid forge
#

i have proposed a term after considering quite a lot of them and being left unsatisfied with any of them but least with "included". I dont need tips on researching, i'm asking for feedback on my proposal

rare whale
split harness
#

"scenes can include other scenes"

vapid forge
#

yup!

rare whale
#

For example, if the word "layer" wasn't already taken, that would be one I would pick

split harness
#

Especially for the purposes of writing docs, that is more than enough. I'm not sure we need to make "include" a "capital I" Include concept.

#

I think its equally fine to say "scenes can extend other scenes" and "scenes can pull in other scenes"

vapid forge
vapid forge
#

as for "pull" that feels too active, like a scene is explicitly requesting things, when "include" generally means "literally just copy paste the other thing here pls" which fits the behaviour pretty well

#

anyways, i think i'll go with include in the places where i struggled in the pr

split harness
vapid forge
#

example: The error when a SceneComponent doesn't have @ (previously :) used to read Scene components should be inherited using @MySceneComponent

#

i'd change that to 'included' and keep it the same, instead of having to rewrite the whole message

karmic rock
#

I'm also not saying that things are better in flecs land

#

I essentially summarized the discussion we had a while back about the different approaches

vapid forge
#

i think the nature of these kinds of conversations is such that the main topic is the advantages, not disadvantages

rare whale
#

@vapid forge I had considered also using the word "foundation" to describe the first inherited scene, since it is special

vapid forge
bitter nymph
#

Base/Root?

vapid forge
#

i have used base in the docs once or twice

rare whale
#

Traditionally, a root is defined by the absence of a parent

vapid forge
#

but the important part for me is that the first scene, if it has : prefix, only differs in that its cached and with how the system is built, caching can only work up to the first potentially dynamic change. Which, for simplicity sake, we limit to the first scene.

#

At least thats my interpretation from looking at how the caching is going to work.

vapid forge
# split harness "Include" is fine

aaand ofc i pretty much immediately find a method which could use this language: The one which used to be called ResolvedScene::inherit

#

i initially called it ResolvedScene::use_cached but it would make sense as ResovledScene::include_cached

split harness
# karmic rock > every time @Sander decides to drive by with "things are better in Flecs land"...

Flecs was referenced by you, incorrectly, which I replied to
This was two days ago, and a completely different conversation.

That's not entirely fair
I'll concede that this wasn't an entirely fair way to characterize your engagement. However you also conveniently omitted most of the nuance that justifies our position, while describing a ton of the benefits of your approach, which caused someone in the conversation to spin out, and I then needed to stop what I was doing to provide the missing nuance. Forgive me ... I was frustrated.

lone sleet
karmic rock
# split harness > Flecs was referenced by you, incorrectly, which I replied to This was two days...

This was two days ago, and a completely different conversation.
It was, but your comment suggested that this is not an isolated instance (I'm randomly driving by), and since you mentioned flecs a few days ago I thought that was relevant to call out.

However you also conveniently omitted most of the nuance
Sure I wasn't here defending bevy's position. That's a bit unreasonable to expect.

while describing a ton of the benefits of your approach
I didn't do that either though. @vapid forge asked questions, and I answered how it worked. If people conclude that they like the way flecs works better, that's not my fault.

karmic rock
lone sleet
#

Would be interesting to see some BSN side by side with flecs script. I think both from "which is better" perspective but also to better understand BSN/flecs script. Contrasting and comparing is one of the best ways to learn something new IME.

vapid forge
#

I'd be willing to write the bsn side if i could find a decent prefabs-based flecs script. I haven't looked too long, but googling "flecs script prefab examples" didn't find much that wasn't either too long or too simple

vapid forge
karmic rock
vapid forge
split harness
# karmic rock > This was two days ago, and a completely different conversation. It was, but y...

Sure I wasn't here defending bevy's position. That's a bit unreasonable to expect.
Perhaps generally, but this is explicitly a place where we are trying to build the best scene system for Bevy. The purpose of this chat is not to be a general-purpose platform for discussing ECS scene systems. Part of accomplishing the goal of building the best scene system for Bevy is comparing to what is out there, and I appreciate both having Flecs as a thing to compare to and your good-faith participation in the discussions.

However another important part of accomplishing the goal of building the best scene system for Bevy is establishing a shared consensus on direction. This is the one place we have to do that. Unlike pretty much everyone else here, your primary motivation is not that. I hope you can understand why choosing to ignore the body of decision making / consensus building / nuance that has led up to this point might be unproductive for us.

vapid forge
#

i think your long messages about this are also a bit unproductive, ngl

split harness
karmic rock
# split harness > Sure I wasn't here defending bevy's position. That's a bit unreasonable to exp...

Unlike pretty much everyone else here, your primary motivation is not that
My motivation for being on the bevy discord is to follow topics I'm interested in (like these) and engage if I think I have something to add. I don't think it's that meaningfully different from others. The only meaningful difference is that I have actual experience building a different solution, which in most cases people would consider a plus. That does mean I'm going to be more contrarian than others*

If you're saying that this working group is past the point of discussing/iterating on ideas, and is more about evangelizing BSN, then maybe it's time for me to leave this thread.

vapid forge
#

I appreciated the knowledge of how flecs does it, but cart does have a point that if we have random people dropping in here to express disappointment bevy didnt follow flecs more closely then maybe that was caused by something

split harness
# karmic rock > Unlike pretty much everyone else here, your primary motivation is not that My ...

Thats not what I'm saying. Very open to discussing and iterating on ideas. I'd just prefer to spend as little time as possible re-discussing the same conversations because someone (who notably isn't building or using Bevy or actively invested in the consensus building process) decided to only present one side of the argument / ignore the results of the process. Imagine how chaotic it would be here if there were 10 different projects doing that.

lone sleet
# karmic rock > Unlike pretty much everyone else here, your primary motivation is not that My ...

Sorry for throwing gasoline on the flame here but from where I'm standing you've been continually disrespected told at least twice by Bevy maintainers assuming you have bad intentions and are trying to hijack the threads you are in. It's not a good look in my opinion. Makes the Bevy community seem quite hostile towards differing opinions. Lots of people who are maybe not actively participating in development are watching threads like these.

white lichen
#

are these choices/discussions/design decisions documented in some doc somewhere, that we can point users to?

#

like a comparison vs the flecs way

karmic rock
#

I don't want to start more drama here so let's just leave it at this. I don't think I was representing Bevy badly here (certainly wasn't trying to), or presenting just one side of the argument, but if that's how it came across then apologies. I like most discussions here as long as they're on topic and not ad hominem

vapid forge
split harness
lone sleet
#

Disrespectful might be too strong of a word. The times I've seen this happen it has been walked back pretty fast and I don't think any large damage has been done.

#

And it's not that I disagree with cart either about the purpose of this kind of group. It's just something I've noted happening a few times and it doesn't sit right with me.

vapid forge
white lichen
#

if we want to avoid retreading ground we probably need to be better about documenting the decisions. something like ADRs (Architecture Decision Records) dont have to be very in depth or complicated or formal, but they should probably live in the repo somewhere so when someone asks "why not X?" we can just link the relevant one

vapid forge
split harness
#

When a given topic is "opened"

split harness
white lichen
#

is the most complete design doc of BSN the original RFC? or is there something more complete/up to date?

vapid forge
split harness
vapid forge
#

not the bevy_scene module docs tho, those are pretty flawed

karmic rock
vapid forge
#

(i really need to at least make a draft PR for my docs changes at this point)

#

(but i dont wanna deal with the constant CI emails)

wooden vine
# vapid forge I dont think its a matter of "we've fully decided we won't do X" more of "we don...

But don't all the discussions (which I currently understand to be the best collection of the design decisions) getting outdated similarly fast? (Some of them are over 1000 days old, all of them are at least 6 months)
https://github.com/bevyengine/bevy/discussions/9538
https://github.com/bevyengine/bevy/discussions/14437
https://github.com/bevyengine/bevy/discussions/21431
If anything I would expect a more centralised design system to be easier to keep up-to-date

split harness
karmic rock
#

It's ok, I'm fine. Many people aren't tho

vapid forge
vapid forge
#

anyways, this has gotten awfully offtopic

wooden vine
# vapid forge and yes a central system might be easier to update, but do you want to spend hou...

Do we produce hours of architectural design decisions each day? I believe we would need many more Working Groups and C-Goals and SME's to staff those. And even then the time to update these docs would probably be similar to the time spent on design docs for those working groups.

I just want to say that this process doesn't seem to be untenable, at least not for major contested topics, not every single decision would be logged ofc.

white lichen
#

imo at the very least we should have clear documentation of the constraints of the problem space we are solving within, im not sure ive seen a comprehensive list

wooden vine
#

Ofc this is up to maintainers to decide if the benefits of such a system make sense compared to the costs, I'm not saying they should or shouldn't do it, just trying to avoid being dismissive of it.

vapid forge
#

I dont know if removing the word "inheritance" from bsn would qualify for needing a design record under such a system, but i can tell you i would be far less willing to seriously engage in such a topic or contribute to it if i had to write such a document alongside my PR

#

i'm already pretty damn glad i don't have to write a migration note since this is the first release with bsn

raven ginkgo
split harness
# raven ginkgo <:plus:843757376950501396> Is this all because of a strict design constraint to ...

Yeah this conversation also brought me here / this is where my mind went the second ~ entered the equation. We aren't explicitly anti-keyword, its just that up until this point, we haven't been super "syntaxsymbol-ey", as we're largely leaning on Rust syntax / slightly tweaking the semantics of the standard syntax.

The "problem" with using keywords is that they're kind of ambiguous:

// template keyword
bsn! {
  template MyTemplate {
  }
}

// template is a "scene variable"
let template = bsn! {};
bsn! {
  template
  MyTemplate {
  }
}
#

Now they can be reserved / take precedence. It just introduces an arbitrary, potentially confusing limitation on variable names

#

Although thats also true for Rust keywords (ex: you can't have a variable named const or async)

split harness
#

But I agree that we could have special "keyword syntax" that unambiguously says "we're about to specify a keyword"

#

However I think the ambiguity is probably "better" from a legibility perspective

frosty shell
#

the r#ident is a real thing supported by rust

rare whale
#

Yes, I've used it for r#type

split harness
#

Ah thats new to me 🙂

#

Thanks!

split harness
#

(I initially interpreted it as the reverse)

rare whale
split harness
rare whale
#

People don't normally name variables after reserved words

split harness
#

@vapid forge I'm reasonably convinced that a template keyword is preferable to ~

rare whale
split harness
rare whale
split harness
leaden dew
vapid forge
#

i think that ship has sailed

#

at least im out if we change that at this point

split harness
split harness
rare whale
#

We need to get past the "kicking the tires" stage on BSN and take it on a major cross-country road trip

split harness
#

Truth!

rare whale
#

Specifically, some of the strengths and weaknesses of a design are only revealed at scale

silk lava
#

Also ideally, UI isn't the only design-space tested/as-example.

vapid forge
#

I do think getting rid of "inheritance" was worth it, but yea, whether we use ~ or template doesn't really seem like something which matters that much. If people don't like a syntax detail for something this rare, theres always the option of hiding it in a scene function

split harness
vapid forge
#

I think its completely fine to stick with ~ for now.
I think a lot of the plus reacts on the comment expressing a dislike for the number of prefixes are because nobody read the fact that its trying out the old and 2 alternative prefixes in a single macro invocation

split harness
#

I do think that any new "symbol" addition (especially things in the category of ~) is worth significant scrutiny. It should definitely be a path of last resort

#

People are understandably allergic to them

vapid forge
#

sure, but the fact that all the plus happen on that specific example is something to keep in mind. And its an example where i tried to condense all possible syntax into as few as reasonable lines before i added the stuff to test the different prefixes

split harness
#

Just wrapped up my review @vapid forge

vapid forge
#

neat!

vapid forge
#

the "cached multiple times" one is... ugh, how'd i miss that? i was trying to make sure to carefully read through each docstring twice

#

Anyways, i'm gonna go sleep, i likely won't be able to get the docs PR into a useable state till weekend, the next 2 days are busy for me

magic belfry
#

this was mentioned before, but ~ does feel odd to me considering it's the bitwise NOT operation in C, C++, C#, Java, JavaScript, Python, Go...

#

and in C++, ~ is also used for destructors

#

in Rust it's not used, but in so many other contexts (and specifically, in programming languages) it carries significant semantics

#

it also looks a lot like - to me unless I look very closely

split harness
#

Yeah ~ is not ideal, although in the world of "one character symbols" its maybe the least worse option. I think its maybe worth trying to make something like the template keyword work

leaden dew
#

it being rare/niche also i think exacerbates the confusion it will cause when people see it for the first time - and individual symbols like these are more difficult to search the meaning of (e.g. on google)

viral roost
leaden dew
#

now that i'm looking for it, i don't see the current @ template patching syntax documented in those tables, nor do i see a single usage of ~ in the PR

#

is it theoretical/not yet implemented?

dusk aurora
#

Why is there a need for that many custom symbols anyway? I am pretty confident at this point that we don't need extra Symbols but I might be missing a long term vision for them.

Considering they are changing at the moment or at the very least it is discussed - that is hard to believe though tbh. Is the vision outlined somewhere? I think it would be valuable to align the community here or is bevy set on not doing sth like this?

#

To take it one step further, I think some of the syntax decisions are actually not ideal (commas, names) and might even be limiting

#

Or require a lot of jumping through hoops

#

Or complicate parsing

dusk aurora
silk lava
#

Is it necessary for FromTemplate::Template to require Output = Self? If not, then you could just impl FromTemplate for your custom Templates, and then you don't need another syntax.

vapid forge
vapid forge
# dusk aurora Why is there a need for that many custom symbols anyway? I am pretty confident a...

pretty much the only reason they're needed is to disambiguate things which need different generated code but look the same.

~Foo means "use <Foo as Template> directly instead of going through <Foo as FromTemplate>::Template"
@Foo means "Use <Foo as SceneComponent>::scene instead of FromTemplate"
#Foo means "This is actually a string Name("Foo")"
:bar() means "Cache this scene" and only allows the first scene to be cached per entity, only if it doesn't take any arguments

I hope this helps for understanding why different syntax is necessary.

vapid forge
silk lava
frosty shell
#

the latter

dusk aurora
frosty shell
silk lava
# frosty shell the latter

If that is the case, then besides for the loosening of semantics, removing the bound and have templates use themselves via FromTemplate should work no?

frosty shell
#

you're welcome to prototype it lol, i dont have enough info to know if that would just work right off the bat

vapid forge
silk lava
#

With the bound removed, you could also do the same thing with SceneComponents, but have them return an generic SceneTemplate<C> or somethiong.

#

Then no special syntax 🙂 (Except name, we like name)

dusk aurora
#

And not doing the important things well

frosty shell
#

link? I didn't see it

dusk aurora
#

Its not public yet

vapid forge
frosty shell
#

oh wait i thought you were replying to my other msg lol

silk lava
dusk aurora
vapid forge
vapid forge
vapid forge
dusk aurora
dusk aurora
#

Ill write more about this at some point, I promise

vapid forge
dusk aurora
#

I actually went through quite similar stages and thought processes as you outlined the last few days, it was very interesting to follow

vapid forge
#

a lot of things which want a scene notation are not things which bevy itself does or needs to do. And while a bunch of examples could likely be updated, thats work someone has to do

dusk aurora
#

But that could change or improve

vapid forge
split harness
rare whale
viscid cradle
wooden vine
#

We need symbols that are easy to write on a keyboard

#

if it doesn't have a single key on standard layouts, then it's easier to use a multichar identifier

viscid cradle
#

idk which encodage is supported for compiling macro, so just asking which table

#

cause the non reserved standard ascii characters are
@ _ ~ ` \

#

and that it

#

but we use ":" in bsn, so idk what the actual rules that limit our set

vapid forge
frosty shell
#

what if we use patch as a keyword for it

#
bsn! {
    MyComponent { ... }
    patch Template { ... }
}
silk lava
#

The only keyword and for something we dont expect users to use often kek

viscid cradle
#

I see what should be the rule for keyword vs symbol, we could look at how rust decides?

dusk lynx
#

Hmm is it just me or has IntellISense stopped working within the context of template in bsn!? On main

vapid forge
dusk lynx
#

And only after finishing something once.

split harness
vapid forge
#

alas, we've had a power outage and internet hasn't come back for a few hours now

split harness
#

I'm guessing we recently switched to strict parsing somewhere, rather than just grabbing the contents of the {} block

vapid forge
#

ahhh, it needs one of those extra thingies

split harness
vapid forge
split harness
#

I'll try before the cached scene PR next

split harness
#

Yup its 24174

split harness
vapid forge
split harness
#

If you're doing Expr parsing, you've already lost unless you provide a fallback

vapid forge
#

ah hmm. That's... annoying

split harness
#

I should have applied more scrutiny. I avoided trying to solve this problem earlier because I knew #Name parsing would be hard in this context

vapid forge
#

I don't think its that bad tho, the Expr isn't something thats explicitly required so it should be fine to swap it out

split harness
#

The commas are the main problem: you can either skip parsing them entirely and parse to the next ), or you can "consume" the tokens via something like parse::<Expr> ()

#

I think the ideal solution is probably either a scan + swap approach (ex: look for #Name locally as you scan through the parenthesized content token stream) or a "grab tokens to next comma or end of content" approach

vapid forge
#

Is the reason why Expr doesn't autocomplete understood?

split harness
#

Whenever we parse Expr, we're assuming the content is fully valid rust. But something like context. is not valid rust on its own, so it fails to parse, and we don't emit the tokens

vapid forge
split harness
#

Correct. Whenever you parse something in syn it expects it to follow the Rust rules for that thing

#

(which is as it should be)

#

Its just that macro code generally doesn't actually want to follow a strict Rust grammar when generating an intermediate representation

#

My parse_closure_loose function exists to solve this exact problem for closures

#

Which is where this is breaking

vapid forge
#

right so we'd need to store something which allows any invalid code as an argument as a fallback to the arguments we care about

#

but only up to the next meaningful comma, which makes this hard

split harness
#

And for each argument outputs an enum that is either a raw TokenStream or a Name ident

#

Or alternatively, just output the raw token stream and try to do a scan-and-replace for every #Name found

vapid forge
#

well, i'd make it just output a list of split TokenStream if possible, then we can test if each is something we know like #Name

split harness
split harness
#

Basically just:

  • Copy the internals of parenthesized_tokens
  • remove the context.parse::<TokenStream>
  • Use the cursor strategy used in parse_closure_loose to scan the stream for commas and break it into smaller streams
vapid forge
#

there might be a simpler way

#

what if, on any failure, we make the whole function args return the input as-is?

split harness
vapid forge
split harness
#

The less we have to parse, the better

#

Parsing an Expr isn't free

vapid forge
#

ahh

split harness
#

Yup yup. This is one of the ways unsynn is "faster" ... it just skips the hard problem of parsing real rust

vapid forge
#

i thought you meant the returning of input as is is slower

split harness
#

/ do the impl?

#

(@vapid forge )

vapid forge
# split harness (<@151347084602245120> )

It certainly is more interesting than writing docs. (I really should make a draft PR for the docs changes i have tho i'm well aware some of them aren't ideal. I just wish there was an option to disable C in draft PRs...)

Alas, i'd currently have to use my phone hotspot to work since the internet outage is still ongoing, which i've taken as a sign to go to bed at a reasonable time today and hope its back to working tomorrow.

log story short: if you want it done before the weekend, probably no

split harness
#

I'll focus on IRS annual report stuff for now. We can see where we're at on monday

vapid forge
#

before that, got an idea for an example for ~Template?

split harness
#

Not actually a good example. Not very practical

#

A more practical, but "larger" example would be a Mesh3dPrimitive template, which is an enum (ex: Mesh3dPrimitive::Cube) that produces a Mesh3d with the appropriate cube handle

frosty shell
split harness
split harness
#

It has to be “scope aware” for all possible things in rust that could have commas

silk lava
#

Maybe templates shouldn't be supported in struct form, just function form?
When you see an Component or SceneComponent patch you know what will be added(roughly), but that isn't the case with templates. (This is a similar concern in other areas of the engine as well)

dusk lynx
#

Is it possible to dynamically create #Name? And also what is now the correct name for those, at some point I thought they were EntityReference?
For example

let scenes = (0..6)
    .map(|i| {
        bsn! { #Name{i}}
    })
    .collect::<Vec<_>>();
dusk aurora
split harness
split harness
dusk aurora
split harness
#

Currently yes. If we really want to come up with something like #"Arbitrary $tring Here" we could

#

I don't think some standardization is a bad idea. Godot has "standard name formatting" too

#

Although that might just be a covention / auto-generated thing

dusk aurora
#

Yes, I think it's very valuable in a context like this, and somewhat expected behavior imo. I think we avoid accidentally parsing the name, but that ship might have sailed. Afaik a space or custom symbols would force using quotes basically.

dusk lynx
#

But that's a good point that each #Name would be valid only within the bsn! context so that might complicate what I had in mind

vapid forge
slender lion
#

@vapid forge it seems like there's some bsn_list errors happening that might be related to the reference work

#

(this is on main right now)

#

its the 3d_scene example

#

it compiles and runs fine. rust-analyzer is the only aspect showing issues

dusk lynx
#

I experienced the exact same error when I was developing against the RC from crates.io until I realized that laund's stuff weren't on there. So maybe rust-analyzer is just stuck on some old dependency version?

vapid forge
vapid forge
#

not just reloading workspace

slender lion
nova bridge
#

not sure if this goes in here or in #1019697973933899910 , but I've hit a possibly related regression in rc2 in some of my own bsn + SceneList code. I haven't yet managed to figure out exactly what the cause is - it is very possibly PEBCAK, since I currently have a lot of entities sharing the same name, and while that previously worked in a pre-bsn world the most recent changes have made names somewhat more important in a bsn setting!

the stuff I've got looks like this

bsn! {
  // ...
  RelationTargetName [
    {function_returning_bsn_list()},
    {another_function_returning_bsn_list()}
  ]
}

// ...

fn function_returning_bsn_list() -> impl SceneList + use<> {
  something.iter().map(move |(position, item)|
    Box::new(
      bsn! {
        :{ item.scene() }
        template_value(position)
      }
      // where item.scene() may very well introduce a #Name, and that #Name might not be unique
    )
  ).collect() // and the other function is very similar
}

on rc1, every scene returned by the two functions was correctly assigned to RelationTargetName's relation; on rc2, only a seemingly arbitrary subset of them is related properly. 😅

vapid forge
nova bridge
#

Eek, apologies! I am awful at scrollback reading sometimes :(

vapid forge
#

I might need to convince Francois to release rc3 soon with this fix, i suspect a few people will run into it

nova bridge
#

I’ll hold on rc1 for now, thankfully there doesn’t seem to be anything broken or missing in rc1 that I need rc2 for c: thanks for the quick catch on it though!

vapid forge
#

yuuup

let scenes = (0..6).map(|_: u32| bsn! { #Name }).collect::<Vec<_>>();
world.spawn_scene_list(scenes).unwrap();
world.query::<&Name>().len() == 1
nova bridge
#

I should probably move off using Name for what I'm using it for, in honesty. I think in 0.18 it was just a handy pre-existing bevy thing that I could use to assign names to things and at no point did I enforce the invariant that each name was unique (in fact, there's some places where I'm directly assuming that multiple things answer to the same name 😱 ). Of course, now names do have semantic weight, and if they're all being spawned into a BSN list at the same time they're expected to be useful cross-references :D

slender lion
vapid forge
slender lion
vast relic
#

docs are now built for the rc.2, issue was the builder limits

#

but no problem pushing a rc.3 if needed

lime veldt
#

did they permanently raise the limits for bevy?

vast relic
#

yup

vapid forge
#

okay, i got a hacky fix for multiple calls to the same scene using #Name

vapid forge
#

ugh, i had to introduce a from/into, but if a #{name} expr doesn't implement the trait the error shows up as affecting the entire macro

#

somewhere along the way, span information is lost

split harness
rare whale
# split harness The old scope system would solve this, so we could also revert back at the cost ...

If I wanted to dynamically create entity names, the first thing I would ask myself is whether I'm doing this to create Name components or whether I am doing this to create names in bsn scope. Although BSN #name does both of these things, I'm not sure it's the right tool for algorithmic names:

  • If the goal is to create name components based on a formula, then just use the Name(format!(...)) component constructor and don't bother with the BSN syntax
  • If the goal is to create an array of similar scoped names in bsn - Ummm, I'm not sure how that is useful
vapid forge
#

the less hacky one i've almost got finished is to use a per-macro Atomic counter to distinguish calls. Its incremented once every time the scope containing the generated code is executed. Its basically done, i'm just working on making it work nicely with #{expr} names

#

mostly making errors due to the expressions actually show for that expr, and not for the whole macro

vapid forge
#

honestly i probably spent way more time on trying to fix the trait error span than anything else

vapid forge
#

AHAHAHAHA

#

ITS SO FUCKED

#

i got trait errors working without drawbacks!

#
let span = proc_macro2::Span::from(value.span().unwrap().start());
let name_expr = quote_spanned! {span=>
    __Name::from(#value)
};

this awful bullshit

#

To make trait errors show up not as errors for the whole macro invocation but instead errors of the part which caused it i have to

  1. get the span of the part which caused it
  2. convert it from a proc_macro2::Span to a proc_macro::Span
  3. use the proc_macro::Span::start() method to get a 0-length span just at the start of this span
  4. convert it back to a proc_macro2::Span
  5. apply this new 0 length span to the function call causing the trait error, in this case __Name::from

Things which do not work:

  • Apply the span of the entire value expression to the function call: This either fails, or if forced by looping over the tokens and calling .set_span(span) on each, causes R-A to show the docs for all types on hover.
  • Any sort of nesting of the value in a block or similar things, all cause the error to be shown for the entire macro invocation
  • Any combination of quote_spanned! with the original span simply does not work
  • Any force applying the original span causes the R-A issues
#

this has taken... WAY too long

vapid forge
nova bridge
slender lion
nova bridge
#

ahhh 😅 much looking at the lockfile in my future then :)

slender lion
dusk lynx
vapid forge
#

just pushed a change to https://github.com/bevyengine/bevy/pull/24402 to use a continuation of the compile-time entity name counter at runtime for name exprs, resolving the concerns @beicause had for using a hashmap key itself as a unique value

nova bridge
#

hmm, it looks like I'm going to need to try to work out how to test that. I've reached a point where my code isn't working in rc1 (because I want to make one child reference another child) and if I upgrade to rc2 that'll work but the aforementioned'll break

vapid forge
vapid forge
#

i keep thinking "today i'm gonna work on docs" and then getting pulled into other interesting topics and end up nowt working on docs :/

vapid forge
#

new PR https://github.com/bevyengine/bevy/pull/24443
td;dr:
:scene was allowed but :scene() threw a "Cannot cache scene function with arguments"

even tho :scene just gets turned into scene() in the macro. This PR allows :scene() again, since it also has no arguments

vapid forge
#

@split harness i just noticed something potentially bad: Cached (previously inherited) scenes can come after component patches in a scenes entries, but they're not automatically hoisted to the top. That means, from my understanding, the behaviour would be different between caching and non-cached usage.

#[derive(Component, FromTemplate)]
struct Position {
    x: f32,
    y: f32,
    z: f32,
}

fn a() -> impl Scene {
    bsn! {
        Position { x: 2. }
    }
}

fn b() -> impl Scene {
    bsn! {
        Position { x: 1., y: 1., z: 1. }
        :a
    }
}
world.spawn_scene(b())

Currently, without caching, this becomes:

let p = Position::default()
p.x = 1.;
p.y = 1.;
p.z = 1.; // end of Position from scene b
p.x = 2.; // scene a

but from my understanding, with caching implemented, it would become something like:

let cached_p = { // assume cached_p is loaded from the cache
  let p = Position::default(); 
  p.x = 2.;
};
cached_p.x = 1.;
cached_p.y = 1.;
cached_p.z = 1.;

because the cached a() is the ResolvedScene of just a() which would be the base ResolvedScene on which b() builds.

In other words: I think we should disallow caching :a() syntax if its not the first scene entry.

#

Note: the code blocks above are very stripped down to show only the order of operations which is relevant

#

Going through the kinds of SceneEntry we have, the only ones which would be "safe" above a cached scene are:

  • Name/NameExpression
  • RelatedSceneList
  • Templates which only set Default (unsure)
vapid forge
#

Okay, i've implemented the "can only use caching syntax as the first item" and its not a big change. Essentially, instead of found_cached_scene = false being set to true if we fined a CachedScene entry, i've replaced it with is_first = true which is set to false after the first entry unconditionally.

This does bring up another idea: If we go this route, is there even any need for the caching syntax anymore? It'd be relatively easy to just treat the first scene as cached if it doesn't have arguments, and if it does, not cache it. That does make behaviour a bit more implicit, and removes the easy way to look at a bsn call and say "oh, you're not caching that", but it also frees up the : prefix, simplifying the syntax.

vapid forge
split harness
vapid forge
#

I'll get my current docs PR out as a draft then

vapid forge
split harness
vapid forge
vapid forge
split harness
vapid forge
#

Plus, theres the whol "do we even need a syntax anymore" question

split harness
#

(and differences in performance)

#

I think the distinction is especially important if / when we add cached parameterized scenes

#

(ex: scene functions with arguments)

vapid forge
#

Okay, fair, i wanted to bring it up because right now its very possible to infer it

split harness
vapid forge
#

Leave it as a, to users, entirely new concept to be introduced in 0.20

split harness
#

We do support scene assets in the new scene system, we just haven't added an impl yet. I don't want to artificially hobble that use case because we don't want to write error messsages for the other cases 🙂

vapid forge
#

oh yeah, its made in a way users can implement it, forgot about that

vapid forge
#

that feels... pedagogically flawed

#

teach people they can't use this, then turn around and teach them they should use it very shortly after

split harness
#

(the history of it)

vapid forge
#

i feel thats a bit different

split harness
#

"caching is only supported for scene assets" is a very easy sentence to write/understand in docs and in error messages

split harness
split harness
vapid forge
#

Ugh, i suppose i'll just have to not think of the many people who will see that error once after 0.19 and never realize it was enabled for those cases in an update

split harness
vapid forge
#

theres no way to show a warning/hint from a macro is there?

split harness
#

And if we manage to implement caching for these cases before the release (which is low hanging fruit), then we can remove the failure

split harness
vapid forge
vapid forge
#

in the future i mean

split harness
# vapid forge no i meant the inverse: warn that it could be cached

In my mind these are our two best options:

  1. Produce a proc macro compile error which fails compilation, explains why and says that this will be supported in the future
  2. (maybe possible) Produce a proc macro compile warning which says that this will be cached in the future, but do the uncached behavior instead.
vapid forge
vapid forge
#

if we can warn in the future

split harness
#

I believe (1) is better, as the final bsn is more self documenting. People reviewing code on github won't necessarily know about the compile warning or the fallback beahvior,

vapid forge
#

my idea is to, if we can, warn on cases which are trivially cache-able once caching is there

#

that also annoying tho

#

anyways

#

wayyy more important

#

fixes that issue with looping the same scene as parts of another scene

#

that would spawn 1 entity instead of N

split harness
#

Is that something I should hop on?

vapid forge
vapid forge
split harness
#

Maybe worth seeing if anyone else can think of a use case first

#

(that doesn't have a good workaround)

vapid forge
#

but i do think its just... way simpler

vapid forge
split harness
vapid forge
split harness
#

We can always re-add it later if we decide it is necessary

vapid forge
#

okay, so, marking that as decided

fervent oyster
#

Hi guys, im sorry to ask questions about bsn here (im new, not sure where to ask questions about bsn).

I noticed that bsn does not support recursive caching of scene right now, is this the intention or a limitation?

#

If understands the current ResolvedScene impl right

fn scn0() -> impl Scene {
  bsn! { SomeComponent } 
}

fn scn1() -> impl Scene {
  bsn! { 
    :scn0
    Foo
 }
}

fn player() -> impl Scene {
  bsn! {
    :scn1
    Player
  }
}

this code snippet does not equals to

fn scn0() -> impl Scene {
  bsn! { SomeComponent } 
}

fn scn1() -> impl Scene {
  bsn! { 
    Foo
 }
}

fn player() -> impl Scene {
  bsn! {
    scn0
    scn1
    Player
  }
}
vapid forge
vapid forge
#

in the new docs i talk about scenes being "included", which hopefully makes the behaviour somewhat more obvious:
In your first case, scn1 includes scn0, and player includes scn1, becoming something like this

bsn! {
    SomeComponent //from scn0 
    Foo // from scn1
}

and then this is included in player

bsn! {
    SomeComponent // scn1 (originally scn0)
    Foo // scn1
    Player // player
}

With caching, when caching is implemented, the behaviour will be the same. But instead of having do do the "include scn0 in scn1" calculation every time, the result of scn1 would be cached and then Player added to it.

I hope that makes some sense

fervent oyster
vapid forge
#

@split harness
I'm running into an issue: scene_fn without () raises a trait error spanning the whole macro which is incredibly annoying. I have not managed to apply the span trick to this, because the issue is not related to macro spans. The error happens for the entire generated expression even after inlining the macro result - this is base rust behaviour apparently.
To resolve this: What do you think about disallowing non-expression inline scene variables?

let foo = bsn! { #Foo };
bsn! {
  Component
  foo // this here would need to become {foo}
}

This would allow us to catch foo without () at parse time and throw an error suggesting to call it if its a function or do {foo} if its a variable.

#

actually, i found another way this could potentially be fixed using codegen instead of parsing:

{
    fn _b() -> impl Scene {
        b
    }
    _b
}()

this limits the error to only that new _b function

#

wait no this doesn't work with variables because only closures can capture, duh

vapid forge
#

Okay i may have found a somewhat workable solution: If we have a trait which implements a method for T: Scene which does nothing but pass through the variable of type T (i'm calling it IsScene, we can get a somewhat related error message, but only if we use {#tokens}.is_scene(). If we use IsScene::is_scene(#tokens) the error escapes out again.

#

its probably the same issue why a function which takes impl Scene and returns impl Scene dosn't work

#

This is what it looks like. Dunno if thats acceptable or not, i couldn't figure out a better way

split harness
# vapid forge

Yeah this problem is nasty in general. Put out a draft PR and we can play with it. Might need to wait until after 0.19. I'm starting to feel the need to reel things in

vapid forge
split harness
#

yup

vapid forge
split harness
#

Just a few small tweaks

vapid forge
split harness
vapid forge
split harness
#

Might still be our best option, but I'd prefer to consider it on its own time

vapid forge
#

thats why i was careful to make it its own commit, i'll move it to a new branch

#

also, i just applied most of the fixes you asked for

#

besides that comment and another i was unsure about

split harness
vapid forge
#

ah

vapid forge
split harness
vapid forge
#

Aight, i'm going to bed, maybe i'll polish docs some more tomorrow

vapid forge
#

@split harness about enum VarianDefaults: should i mark an issue running into this as Docs+Wontfix and remove the bug label?

#

in other words: i assume VariantDefaults has to stay?

#

i went ahead and labelled it like this, if its wrong, oh well

rare whale
#

@split harness @vapid forge I'd like to re-raise the issue about atomic replacement of bsn scenes to ensure it doesn't get lost in the shuffle. (At the risk of being repetitive, I want to make sure that new readers get all the context, so I'll explain in detail).

bevy_reactor uses the following pattern ubiquitously:

entt.despawn_related::<Children>();
entt.queue_spawn_related_scenes::<Children>(...replacement_scene...);

...where entt is always a ghost node. Note that this isn't the only kind of dynamic replacement that bevy_reactor does, but it's the one used to make any sort of large-scale structural change (like an If or Switch statement).

The problem with this is that there is an undetermined length of time between the removal of the old children and the spawning of the new ones, creating an unsightly flicker or gap.

We have discussed several ways of addressing this, but none are workable in the current environment:

  • Using the non-queued version of spawn_related_scenes - this requires deeper knowledge of the child scene than is available to the reactive primitives
  • Somehow expressing the dependencies of the scene via type information - this seems like a major research project that is unlikely to bear fruit any time soon
    The simplest solution, in the short term, is some means to do the despawning of the old children in the same frame as the parenting of the new children.
rare whale
#

Unrelated to this, I just patched in the latest Bevy mainline in the bevy_reactor, and I'm having difficulty using the #name syntax, I get rust-analyzer errors like this:

no such field
missing structure fields:
- reference
split harness
# rare whale <@153249376947535872> <@151347084602245120> I'd like to re-raise the issue about...

Makes sense. While I still think ultimately we should be making the reactive primitives dependency aware so we can make these types of reactions "immediate", even with that feature I can see this being desirable for some use cases.

I believe I have something that will work for you without needing new features:

fn queue_replace_children(&self, scene_list: impl SceneList) {
    self.queue_apply_scene(bsn! {
        bundle_template(|context| {
            context.entity.despawn_children();
            Ok(())
        })
        Children [
            {scene_list}
        ]
    })
}

You would run queue_replace_children on the ghost node entity.

This (should) work because templates are applied before children are spawned when applying scenes, so the old children will be cleared out right before spawning the new children.

rare whale
split harness
split harness
#

one sec

split harness
# rare whale Error: ``` `()` is not a `Component` ```

Alrighty this should really be upstreamed, but heres the bundle_template impl:

fn bundle_template<
    F: Fn(&mut TemplateContext) -> Result<B> + Clone + Send + Sync + 'static,
    B: Bundle,
>(
    func: F,
) -> impl Scene {
    SceneFunction(move |_context, resolved| {
        resolved.push_bundle_template(template(func));
    })
}
#

@rare whale I've edited the example above to use it instead of template

rare whale
vapid forge
split harness
split harness
#

We need a static distinction between a "bundle template" and a "component template" now (at the scene level). This could ultimately be lifted if we sort out nested dynamic bundles, but thats a harder problem to solve

#

(See the new BundleWriter)

dusk lynx
split harness
#

If it keeps coming up. It would make sense if this happened after updating to a new version of Bevy with different bsn! code

vapid forge
dusk lynx
#

More like the latter. Sorry for not being precise enough!

slender lion
#

I am personally only aware of the one case per person, personally

vapid forge
#

because working on this, lemme tell ya, R-A does not properly recompile proc macros when their code changes

#

i have to restart R-A for basically every change i make to the macros

dusk lynx
#

Sounds lovely 🤐

vapid forge
#

Honestly, i'd be fine, if rust-analyzer allowed its lints to disappear if clippy doesn't find them

#

but i can't live without R-A completions and go-to-source, so i have to keep using it, which means i have to keep restarting it

split harness
rare whale
split harness
rare whale
# split harness Thats good news 🙂

BTW, here's what my code looks like now:

/// Trait that represents a function that can produce a [`SceneList`]. Used for conditional
/// blocks in control-flow templates.
pub trait SceneListFn: Send + Sync {
    fn spawn(&self, parent: EntityCommands);
}

impl<S: SceneList, F: Fn() -> S + Send + Sync + 'static> SceneListFn for F {
    fn spawn(&self, mut parent: EntityCommands) {
        parent.queue_apply_scene(bsn! {
            bundle_template(|context| {
                context.entity.despawn_children();
                Ok(())
            })
            Children [
                {(self)()}
            ]
        });
    }
}

Then, elsewhere:

/// Conditional control-flow node that implements a C-like "if" statement.
struct IfReaction<ConditionFn: Lens<bool>> {
    state: IfState,
    condition_fn: ConditionFn,
    then_branch: Arc<dyn SceneListFn + Send + Sync>,
    else_branch: Option<Arc<dyn SceneListFn + Send + Sync>>,
}
split harness
rare whale
# split harness Can I see it in context / a usage example 🙂
commands.spawn_scene(bsn!(
    Node {
        left: ui::Val::Px(0.),
        top: ui::Val::Px(0.),
        right: ui::Val::Px(0.),
        position_type: ui::PositionType::Absolute,
        display: ui::Display::Flex,
        flex_direction: ui::FlexDirection::Column,
        border: ui::UiRect::all(ui::Val::Px(3.)),
    }
    BorderColor::all(css::ALICE_BLUE)
    Children [
        Text("State: "),
        switch(|cx: &Cx| *cx.resource::<State<GameState>>().get(), |cases| {
            cases
                .case(GameState::Play, || bsn_list![Text("Playing")])
                .fallback(|| bsn_list![Text("Not Playing")]);
        }),
        Text(" - "),
        if_then_else(
            |cx: &Cx| *cx.resource::<State<GameState>>().get() == GameState::Play,
            || bsn_list![Text("Yes: Playing")],
            || bsn_list![Text("No: Not Playing")]
        )
    ]
));
split harness
rare whale
#

But yes, that would likely be quite doable

split harness
rare whale
#

Not sure how you would do the switch cases structurally, since the number of cases is variable

#

Also, there are many other design variables which we have discussed

#

Like whether the then/else block should be closures or just straight up bsn literals; whether the If reaction should use dyn functions or generics; and so on.

#

Main reason for using closures is that the path not taken has zero cost

rare whale
split harness
split harness
#

bsn! on its own is generally just some some functions on the stack in practice

#

(with some data captured in closures and sometimes a full component template here and there)

rare whale
# split harness Yeah I see the appeal. The theory is: generating the _description_ of every case...

Another option is to make the "lazy reveal" an explicit wrapper: say you have something like a tab deck or dropdown menu, where one tab panel is expensive to maintain - you want to despawn the contents while its invisible, because otherwise you have to spend cpu keeping the contents (tree view, font list, whatever) up to date with the game state. The wrapper would only auto-spawn its children when visible.

split harness
split harness
#

@vapid forge is your bsn doc pr still a "draft"? let me know if / when I should review it

split harness
#

Thanks!

#

@rare whale ultimately the :pane syntax will be supported again, once we add function-scene caching

rare whale
vapid forge
rare whale
#

@split harness Another thing I have been mulling over a lot recently is the BYOA (Bring Your Own Artwork) widget collection idea and how that fits into the BSN vision. I have a prototype but I don't like it very much - the code is too clunky and inflexible.

The problem I am trying to solve - associating different style parameters with different states - is fairly trivial with a reactive solution. However, not only do we not have consensus on what a reactive solution looks like, it's worse: none of the proposed reactive solutions will work with asset BSN. Everything that's been done so far involves writing Rust code that lives inside a BSN macro.

My goal with the BYOA prototype was to encode all of the visual dynamicis in an entirely no-code, declarative fashion. This would be done using bitmasks to represent the various states such as pressed, hovered, disabled and so on. Since this is just data and not code, it could be serialized easily. However, the resulting widget design is more complex than I'd like.

A different approach which I have also prototyped was to build a simple interpreter for embedded expressions - not trying to re-implement Rust or even Lua, but just enough to be able to write simple formula in a BSN asset and have it be compiled when loaded. I got pretty far along this path - I was able to call simple functions and run them, I had a working type inference solver - but the complexities really start to snowball once you start letting scripts access ECS data structures.

#

Unfortunately, I lately have been feeling burned out by the lack of progress, and had difficulty with motivating myself to work on this stuff.

queen oak
#

Yeah, i am pretty concerned about trying to actually implementing anything like dynamic scripting, I think focusing in on hot-reloading with the dioxus crew, and trying to work harder on integrating that more closely with bevy, and making it an easier option to use, making it work better with all parts of the bevy ecosystem, is something of less maintenance cost ( not that it will be small but the cost of our own language is large ) and also just integrates better with the whole ecosystem of bevy and rust.

#

We can get easily editable, dynamic re loadable ui without it being in asset files, if we lean really hard into optimizing stuff for working well with hotpatching.

heady latch
#

Probably overkill, but I have to mention that you can JIT Rust (and own languages) with cranelift

rare whale
rare whale
queen oak
#

but with a real phone

rare whale
#

The thing to understand is that all of these JITs - WASM, Cranelift, Rust, etc. - are just performance optimizations. You can do exactly the same thing, albeit slower, by implementing your own stack-based interpreter. A JIT makes your code run faster, but it doesn't solve any other problem - particularly it doesn't address issues of garbage collection, lifetime management, or reactivity.

queen oak
#

not developers?

rare whale
#

The typical division of labor between script and engine is that scripts provide command-and-control duties, while the engine does all the heavy lifting. So the speed at which the script interpreter runs is only important if it's being used for CPU-intensive parts of gameplay.

rare whale
#

Anyway, building a simple VM is not that hard - managing access to the ECS world with lifetimes is hard.

queen oak
#

Well, if you're just doing observers or systems, it's not that difficult, because you just have no state persist ( aside from Local in system params ) so all other state just gets wiped out after your frame ends. https://vxtwitter.com/MalekiRe/status/1903903164010471577
Lifetimes are just for the length of the system, or for the length of the function call, and that's it

I'm trying nodegraph scripting again. Already more progress than I made last time. The goal is to snarf all of rust's features using bevy reflection for functions and values. The idea is to create these node graphs and they will run as systems, as a way to do modding for bevy.

▶ Play video
#

I've done several different kinds of ecs integrated nodegraph and lexical scripting with bevy where i keep everything ephemeral

#

( this doesn't work if you start to allow complex rust things like borrowing, but you wouldn't need to for UI stuff )

#

( but this is different than real rust )

rare whale
#

Here's an example where I run into trouble: say I have a script that contains a foreach loop, and inside that loop we do something with a Vec3. Well, we can't store a Vec3 on the stack because the interpreter stack can only store scalars - so we have to allocate heap space for it. But unless we do some kind of GC, each time we go through the loop another Vec3 is going to be allocated, so now you have all these temporaries. Sure, we can store them all in an arena and free them at the end of the script, but we can't know how big the heap is going to grow during execution.

#

You might be able to solve this with lifetime analysis in the script language, but that's something I haven't been successful with.

queen oak
#

You can totally store Vec3 on the stack!

rare whale
queen oak
#

In the vm as well

#

just store Box<dyn Reflect>

dapper sky
#

Box is a pointer, that isn't the stack :p

queen oak
#

I thought we were talking about the VM stack not the native stack, please correct me if this was incorrect @rare whale

queen oak
#

But, going back to your original point

#

already in rust, you do not know how many Vec3 you might store in a Vec in a for loop

#

before a function calls and they all drop

#

OOM errors are a problem you can solve by canceling scripts that grow too large, but it's not something generally solveable

#

but in your case where we ephemerially allocate it

#

we can just put it on a Box<dyn Reflect>

rare whale
#

I don't want to get this channel too far off topic

queen oak
#

We can move to #modding-and-scripting if you prefer

rare whale
#

I brought all this up because it relates to BSN, specifically embedding logic in BSN assets

queen oak
#

Yeah, i'm still on the boat that logic itself shouldn't live in BSN assets, we should just make hotpatching really good and first-class

rare whale
queen oak
#

could you elaborate on the difference? I'm not getting it yet*

#

what properties do bsn assets* have, that rust files don't, if we have good hotpatching?

karmic rock
#

Expressing “I want this rect to be half the width of the parent” is not something you want to put in hot reloadable code I think

rare whale
# queen oak what properties do bsn assets* have, that rust files don't, if we have good hotp...

Trying to think of the right words to express this. OK let's try this. Before I started working on Bevy, I spent two years building a game engine in JavaScript based on three.js. Since I was using JS, I had hot patching capabilities that Rust programmers could only dream of. I could modify anything in the engine and instantly see the results. However, this did not eliminate the need to be able to put custom logic within assets for characters, dialogue trees, scenery, quests, and so on.

#

Because this was a large open-world game, I didn't want to have to keep in memory all the time the logic for every character in the world, particularly logic for characters that were currently "off-stage". So some kind of dynamic loading and unloading of behavior was required. Fortunately, this was easy to do in JS.

queen oak
#

I see, that makes sense, you don't want to have the entire game itself stored in ram

rare whale
#

To be fair, most of the loadable game logic was in .ts files in the assets folder, which could be loaded and then eval()'d as needed. But that's harder to do with Rust since any .so file or DLL is going to be target-specific.

queen oak
#

yeah, but also shipping anything to deal with ECS that is rust-like is going to end up a huge undertaking. Relatively complex ide extensions will need to be maintained to support debugging, subtle differences between what we support and what rust supports, it's massive, and doing a non-rust like integration is also quite sad, because we opt out of the ecosystem and start building our own. It's a whole mess either way.

#

We could ship something like the gLTF interactivity spec, but that is visual not textual ( not easily textual ) and also doesn't fit our domain

rare whale
#

What this all boils down to is that I don't know what the right answer is

queen oak
#

Honestly, out of all the options presented here, pre-processing individual rust files as their own dynamic libraries per platform, and then dynamically loading and unloading them just to call the function that creates whatever scene feels the least janky, which is crazy

#

i might try a PoC of that, see how it goes

karmic rock
#

At the end of the day you can’t ignore the non functionals of rust

#

A scripting environment just provides better UX for the end user

#

Theres a reason people use gdscript

#

Not because it’s their favorite language. It’s just the path with least friction

queen oak
#

I'm greedy, the best option would be it has all the benefits of a scripting language, but still be rust: ( I disagree with the commonly held notion that dynamic typing is a benefit of scripting languages ) but the hot-reloadability, the speed of iteration, the ability to load it dynamically. These are things I would want to work towards providing in rust. I want the path of least friction to be just writing rust files, the idea that i could pull in some iroh p2p networking code directly into my bsn asset logic if need be is awesome to me. That i could use someone's color calculation library they wrote in rust anywhere in bevy is awesome, because all of bevy is rust. I am fearful of losing that capability. Broad ecosystem support of rust means i can just grab libraries from wherever and use them everywhere.

A scripting language would necessarily lose out on that. There would have to be some form of FFI.

#

maybe it's not possible

karmic rock
#

I understand the appeal, there just isn’t a lot of empirical evidence to support it’ll work. There’s overwhelming empirical evidence to the contrary as virtually all game engines have their own scripting environments

#

It’ll be an uphill battle whether it’ll work or not

lone sleet
#

Going off topic... but I sometimes wonder what Bevy but in C# would have been like considering it solves these issues already.

queen oak
#

Moving this over to #modding-and-scripting but i might be cooking?

vapid forge
#

could someone tell me if anything of relevance to bsn! was said since talin started this?

queen oak
#

i don't think so

#

nothing other about bsn was said during the convo except talking about scripting stuff

shell dragon
shell dragon
# karmic rock Theres a reason people use gdscript

People only use gdscript because it's basically the only choice for Godot. Despite being advertised as having "first-class" support, C# support in Godot is absolutely terrible and got borderline unusable with Godot 4.

#

If you're experienced with C# and love it enough to ignore the jank, you can kinda wrangle it together. But beginners who hypothetically would've been fine with C# in say Unity, will inevitably pick GDScript for Godot because the out-of-the-box experience is just terrible.

shell dragon
#

oops sorry

tawdry owl
#

Is it a known issue that bsn! blocks seem to significantly slow down rust-analyzer's code analysis/completion proportionally to how many of them there are in the same function?

vapid forge
# tawdry owl

No, and thats strange, afaik the macro isn't doing that much work

leaden dew
#

could it be related to the huge error messages generated in that example? does it happen even in the absence of any errors?

tawdry owl
thick slate
rare whale
# vapid forge could someone tell me if *anything* of relevance to bsn! was said since talin st...

Apologies; it wasn't really my intention to get into the weeds on scripting languages. Really what I wanted to talk about was the high-level strategy for specifying behavior and game logic within BSN assets. I wanted to compare general approaches, not get into low-level details; I wanted to know whether I should abandon lines of research, or whether there are avenues that I had not considered, and whether other people had done anything substantive in this area yet.

The BYOA widget problem is only interesting in this case because it's a small-scale problem that has crisp boundaries. There are many other possible use cases; I can see for example using BSN with custom relations to model hierarchical character goal trees, with components representing specific behavior types - essentially using entities to represent a serialized expression graph, but with backtracking evaluation.

somber rivet
# rare whale Apologies; it wasn't really my intention to get into the weeds on scripting lang...

I've mentioned it before but bevy_gearbox is all about defining statecharts in entity hierarchies. I haven't been using it with bsn since I'd like to wait for release, but bsn will massively improve gearbox. In fact I would say that without it gearbox is barely usable.

Some things that stick out as far as "high level" stuff:

  • When a state machine is spawned it needs to be initialized. I do this by detecting the insertion of a component on the root and assuming everything is ready to go. So that initialization component needs to be inserted last, after the entire hierarchy is built. This is a huge painpoint. It's a massive footgun that's very challenging to signal to users. This is specific to gearbox but I imagine this kind of insertion order sensitivity will be a general bsn issue if it's not somehow solve implicitly by bsn.
  • Theoretically, an entities behavior is defined by it's current state. My goal is to be able to query on that state, meaning that state is ultimately represented as a component on the root entity. But in the actual state machine, state is represented by active state entities which are children/grandchildren of the root. Bridging this gap has been awkward. Right now I have the notion of a "StateComponent" which is inserted into the root and removed when its state entity activates. Though this is somewhat awkward I'm not really sure how else to do it. I imagine most behavior-as-entity-hierarchy systems would run into this. Maybe you just put state components on the state entities, query on those + an "Active" marker component, and get the root? Maybe a query parameter that lets me do something like WithState<MyStateComponent> where WithState automatically resolves state entities to their root? Idk
GitHub

Bevy state machine. Contribute to DEMIURGE-studio/bevy_gearbox development by creating an account on GitHub.

#

To be clear the WithState would basically be "Does a child have the given component." With the little fiddling I've done with query filters this would be quite the hack.

vapid forge
# somber rivet I've mentioned it before but [bevy_gearbox](https://github.com/demiurge-studio/b...

For your first point: I don't think its inherently solved by bsn but there are potentially ways to work around it or even solve it. If you just need to insert the initialization component last and its okay if theres other commands in between, you could use template() which gives you access to the world, allowing you to queue a insert command to be run at the end of this commands flush. This was already possible before sith lfiecycle hooks/observers btw, with the same drawbacks: The command ia queued to the end of this flush, meaning many user commands might run in between.

I'm pretty sure lifecycle observers run during scene spawning directly when each component is inserted, but thats something that would need to be checked (not sure how this behaves with BundleWriter). If it already runs them after the full scene spawn, great! I don't think so tho. I think its plausible to potentially delay them to the end of the scene spawn, or otherwise provide a mechanism for running something directly after a scene is spawned. Triggering a EntityEvent after the scene has spawned would actually be pretty reasonable to implement.

Regarding your second point, i think its not very relevant to bsn, its more about querying. I think its possible a custom QueryData could do this, or otherwise a custom SystemParam definitely could (with enough generics fuckery, it could even do this while acting like a Query)

karmic rock
somber rivet
#

Point 1: I'll have to look into this! Definitely would like to make this something users don't have to think about.

Point 2: Yeah definitely not a bsn thing but it was a difficulty I'd run into trying to encode behaviors into trees so I thought it was worth a mention. After seeing your message I was looking at a QueryState system param that gets the query data from the root entity but which lets you apply the query filter to the state entity (or some arrangement like that) and I think I like the pattern! So thank you 🙂

vapid forge
vapid forge
split harness
#

(all of the blocks except the last one, which is returned as the impl Scene)

tawdry owl
#

I'm testing this on scene/bsn.rs example, it's easy to reproduce there

split harness
tawdry owl
#

I think it's related to on templates. When I comment them out it doesn't slow down nearly as much.

split harness
split harness
tawdry owl
split harness
tawdry owl
split harness
split harness
tawdry owl
tawdry owl
#

I wonder if type-erasing/boxing can fix this?

split harness
#

Boxing a complicated type still requires the compiler to know that type

#

But thats a simplified view of the world. My answer is "I have no clue and testing that would be helpful" 🙂

tawdry owl
#

But yeah, this needs more investigation

split harness
thick slate
karmic rock
#

It's uncanny how close to Flecs the model he describes is

vapid forge
karmic rock
#

e.g. IsA inheritance is most similar to BSN scenes

#

(though I agree that it should be part of the ECS, but it's not)

vapid forge
# karmic rock e.g. `IsA` inheritance is most similar to BSN scenes

Is it? Scenes are pretty distinctly a spawn-time thing, almost more of a fancy constructor syntax, than something which it makes sense to care about in systems, while from what i understand of IsA and the talks you linked, they're inherently meant for querying and systema to use.

#

like, maybe if you think of BSN as being more akin to a gltf file it makes more sense

karmic rock
#

The implementation is different, but the role it fulfills ("instantiate stuff of this kind") is similar

#

The question around "should this be part of the ECS" vs. "should this just be a fancy constructor" is exactly the discussion we've had in this thread, which is why I think this is the right place to discuss it. I'm fine with posting it in #ecs-dev, but it can't really be seen separately from BSN

#

At mimimum it's another reference to prior art that argues in favor of integrated support

vapid forge
#

yeah idk i really don't see how they're at all similar roles

#

or alternatives of each other

#

if we tried to do this with BSN it would change the very core of what its trying to become: serializable

karmic rock
#

If you listen to the talk you'll hear that they instantiate things like Warrior with an IsA relationship, and that they use this relationship to resolve which properties that entity should have ('walk up the hierarchy to find X'). I could be wrong, but I believe that property overriding is very much a thing that falls under the BSN umbrella

#

Also, if you scroll up (far), you'll see me and cart having this exact discussion around the IsA relationship and the flecs prefab model

#

Anyway I'm not really interested in having a discussion around where this should be discussed 😛 I think the talk itself is way more interesting

#

If a mod thinks this should be moved, I'll move it.

vapid forge
#

BSN ultimately generates this code:

component.field.nested_field = 5
component.field.nested_field = 8

when someone overrides the nested fields value to be 8

vapid forge
karmic rock
vapid forge
#

if anything, that last convo is why i'm so sure this isn't the right place (anymore, probably)

karmic rock
#

Last thing I heard cart say was that nothing’s been ruled out yet.

split harness
#

I do think this is a fundamental question that should still be on the table, but I'm not yet ready to engage further with it while we prep for release. Thanks for the link!

split harness
#

@vapid forge

#

Also @tawdry owl (in case this happens to improve the perf stuff you were talking about)

vapid forge
tawdry owl
split harness
#

_but I don't have it 😆 _

tawdry owl
split harness
#

Cutting down on that might also help with compile times generally