#bevy_enhanced_input

1 messages Β· Page 3 of 1

sharp warren
#

I use debug! or trace!.

native pendant
#

using action.state::<A>() shouldn't ActionState::Fired only be given once?

sharp warren
sharp warren
#

But for things like this I'd suggest to use an observer for a better API.

native pendant
#

when is Cancelled raised?

sharp warren
native pendant
#

cool

round portal
#

Am I right to assume that touchpad on sony gamepads is not supported yet?

outer wyvern
proud coral
#

I literally just came here to ask questions about the library being more component-y and just saw this

#

am I blessed?

#

I'm using components as states and so being able to have these components represent the input contexts too would be so cool

#

am I crazy if I literally start using this PR straight away @sharp warren? πŸ˜‚

outer wyvern
sharp warren
#

I'll draft a new release right after the merge.

proud coral
#

Let’s fking goooo

#

Im literally blessed

proud coral
#

first time I've opened local docs

outer wyvern
#

Man, I really like this design

#

Very clean

#

And trivially serializable and adjustable at runtime

#

Ugh lol, the Github website hangs for me trying to review this

#

I guess I'll check it out locally

proud coral
#

Okay, just set it up

#

this is SO MUCH BETTER

#

I'll find caveats thats for sure

#

but the way contexts are basically good old bevy components without anything special is just

#

πŸ§‘πŸ»β€πŸ³ πŸ’‹

sharp warren
#

Thanks! I'm glad you all like it πŸ™‚

outer wyvern
#

I have complaints about the docs though :p shocked_pikachu

sharp warren
outer wyvern
#

I also pushed a couple of tiny typo / grammar fixes to your branch

proud coral
#

Now this is tidy

#

the entity has it's own statemachine (where each state is a compoonent such as InLauncher) and now I can just insert actions and observers inline like this

#

no declaring contexts anywhere involved πŸ˜„

sharp warren
# proud coral

One tiny suggestion. If you just want to clear actions, you can do despawn_related πŸ™‚

sharp warren
#

I need some advice. To remove a context from an entity, users currently need to do the following:

entity.remove_with_requires::<Player>().despawn_related::<Actions<Player>>();

This feels a bit verbose. I'm thinking about marking Actions<C> as a required component for C and similar for Action<C> and Bindings. That way, despawning would be much simpler. What do you think?

sharp warren
proud coral
sharp warren
sharp warren
sharp warren
proud coral
sharp warren
#

Waiting for a final approval from @outer wyvern, then I address this PR and we are ready for a release πŸŽ‰

inner sky
#

@sharp warren we just had this talk in #1124043933886976171, #ecs-dev and #1278871953721262090, so let me throw something potentially annoying in the room:
does this rework work with disabled entities?

sharp warren
inner sky
sharp warren
#

Yeah, it's a very recent feature, need some time for the ecosystem to adapt.

I remember in early Bevy days people didn't even disable default features on Bevy, I had to patch a ton of third-party crates πŸ˜†

outer wyvern
#

So please merge without my formal approval

#

It really doesn't like the many files changed PRs

sharp warren
#

Looks like GitHub didn't pass our stress test πŸ˜…

#

Merged!

outer wyvern
#

Excellent!

sharp warren
#

Going to sleep right now, will address the remaining things tomorrow πŸ™‚

compact island
#

GitLab also doesn't like big merge requests...
once I reviewed +20k -19k merge request
much wow πŸ˜†
btw, i'm looking forward to test this all out upon release

native pendant
#

Actions dont have Reflect, which means that you cant use bevy-inspector-egui to verify its state

sharp warren
sharp warren
inner sky
#

If so: yes, #ecs-dev tells us there’s no better way atm

sharp warren
#

From what I remember, users can define their own disabled components

inner sky
#

Not really possible to support those atm πŸ™ˆ

sharp warren
#

I have only a single place when I need it 😒

#

We need a way to disable default filters, needed to uphold invariants.

inner sky
#

Pretty sure @edgy shuttle would like that as well

sharp warren
#

Damn, it's so annoying that I have to pull log directly.

#

Once again, I wrote a code that passes tests locally. I push it and on CI lib compilation fails because trace was pulled from the bevy::prelude::*, but bevy_log is a dev-dependency, which is unavailable when you compile the library, but present in the prelude when you run tests.

#

@kind summit by any chance we could have bevy_log with no_std in 0.17? Looks like tracing was released with your changes.

sharp warren
sharp warren
outer wyvern
proud coral
#

is there any example out there for touch input in BEI?

#

I'd love to be able to implement custom inputs from a touchscreen like pinch swipe press etc

#

or is it not even possible?

#

(without boilerplate I mean)

outer wyvern
#

Then exposed

lilac monolith
#

hello, i asked in general chat but ill check here also, is adding data to the InputAction possible? i mean something like this

#[derive(InputAction)]
#[action_output(bool)]
pub struct TestAction{
    pub value: f32
}

pub fn setup(mut cmd: Commands) {
    cmd.spawn(actions!(
        Context[
        (
            //HERE
            bevy_enhanced_input::prelude::Action::<TestAction>::new(TestAction{
                value: 0.
            }),
            bindings![KeyCode::Space, GamepadButton::South],
        ),]
sharp warren
lilac monolith
#

aww damn

#

but each action is its own entity? if i understand correctly

sharp warren
sharp warren
#

@quasi epoch published a patch release with your modifier πŸ™‚

quasi epoch
#

great

sharp warren
#

Thanks for the contribution!

atomic parcel
#

re: touch input
does bevy_enhanced_input support manually activating actions? is ActionMock good enough for that?

sharp warren
#

Yes, you need either to use mocking or intercept the value manually before the EnhancedInputSet::Apply system.

If its for touch, we better add a built-in option for it.

quasi epoch
#

@sharp warren have you put any more thought into an input buffer feature? i would open a pr but i think this is beyond my skill level

sharp warren
# quasi epoch <@243426730851696640> have you put any more thought into an input buffer feature...

Can't think of any compromise-free solution 😒 I think this requires changes on the Bevy side.
My up-to-date thoughts are in this message. If you have other ideas - feel free to suggest!

Is this a deal-breaker for you? It's triggered only if you activate and deactivate actions quicker then your fixed tickrate. If you press buttons that quick, you can just increase the tickrate temporarely as a workaround while waiting for a soluiton.

inner sky
#

huh looks like their Discord profile is having issues

#

Anyways, there is a concrete solution suggestion now. Someone just needs to implement it πŸ™‚

sharp warren
#

Cool! Yeah, that would be great.

inner sky
#

Ah, dug up the message

#

I won't be working on this, just posting it here in case a BEI user want to get nerdsniped into it broovy

sharp warren
#

Same, my current focus is on bevy_replicon, I need to implement a few important features πŸ™‚

thick kiln
#

After the refactor; how can i get the type of an InputAction if I know the Action entity?

#

Conversily, if I know the ActionType, how can i get the entity that holds the action value?

drifting pollen
#

Thank you for this. It helped me see what was going on in the background. Been trying to figure out how Fired are reported as Completed. I was trying to figure out how to read a field or something. Turns out I just needed to create another function with Completed. Awesome, thanks again.

sharp warren
sharp warren
thick kiln
#

I was thinking of trying to do the replication with entities, it might be doable with my current approach, not entirely sure yet. The main issue I have right now is that I expect a single ActionState component; which in your case is split between 4 components. For now i will just create my own component which will be a copy of your 4 components

sharp warren
thick kiln
#

The one component vs 4 components is independent from the previous question. It's because my API expects a single component https://github.com/cBournhonesque/lightyear/blob/main/lightyear_inputs/src/input_message.rs#L66 to query/update the state of the action.
It's used at various places like so: https://github.com/cBournhonesque/lightyear/blob/main/lightyear_inputs/src/client.rs#L307

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

GitHub

A networking library to make multiplayer games for the Bevy game engine - cBournhonesque/lightyear

sharp warren
#

So for a single component you would be able to define &A, for 2 it would be (&mut A, &mut B)

#

But yeah, a single component that copies the data is not a bad workaround for now πŸ€”

thick kiln
#

Yeah i thought about that, but it's not super straightforward actually, because for a component the query data is &A or &mut A, so i would need to have an ActionStateRef and and ActionStateMut for the equivalent (&A, &B) and (&mut A, &mut B) + there's other complications

sharp warren
sharp warren
#

Drafted a minor patch with a fix for Chord and more derives for ActionTime.

bitter crater
sharp warren
#

Try to enable logging and see what is happening.

#

You can send the logs here

bitter crater
sharp warren
bitter crater
#

but still the on_move observer doesn't seem to be working

sharp warren
#

But enable it only for BEI, otherwise it will be too noisy.

bitter crater
#

DefaultPlugins.set(LogPlugin {
filter: "bevy_enhanced_input=debug".into(),
..Default::default()
}

#

this is what i used for logs

sharp warren
sharp warren
# bitter crater

This line:

 updating `demon_goat_salon::engine::input_manager::Move`

indicates that Move is setup correctly. On the next line you can see it reads input for it, passes through modifiers and such.
But there are no input, so the triggers don't fire.

#

Wait a minute. Why it's Axis1D?

bitter crater
sharp warren
bitter crater
#
#[derive(InputAction)]
#[action_output(f32)]
pub struct Move;
#

ohh

#

I think i got it

#

maybe its using the Move from bevy

#

instead of the one i defined

#

leme try

sharp warren
#

If you need a 4-directional movement, you need Vec2 (which is Axis2D)

bitter crater
#

its 2d

sharp warren
#

Then it's fine. But you don't have any inputs from bevy_input.

#

At least from the logs

sharp warren
#

Maybe collect the logs again with any active input?

bitter crater
bitter crater
#

anyways thanks alot for this : its very helpful πŸ™‚

sharp warren
bitter crater
#
pub fn keyboard_input(
    keyboard_input: Res<ButtonInput<KeyCode>>,
) {
    if keyboard_input.just_pressed(KeyCode::KeyD) {
        info!("Key D Input Pressesd");
    }
    if keyboard_input.just_released(KeyCode::KeyD) {
        info!("Key D Input Released");
    }
}

Added this system in FixedUpdate Schedule and can see the "Input Pressed" and "Input Released" in the logs

bitter crater
#

Alright! So for now here the inputs work!
They started working when I removed DeltaScale : also worked when I removed DeadZone::default() - but dont work when i used them together

#

was just trying it out so i dont think i need deadZone anyways

#

thanks for your help @sharp warren !

sharp warren
bitter crater
sharp warren
# bitter crater

Ah, looks like you had inputs even in the first log. But DeadZone dropped the value:

2025-07-29T09:19:26.727484Z TRACE bevy_enhanced_input::context::trigger_tracker: `Negate { x: true, y: true, z: true }` changes `Bool(true)` to `Axis1D(-1.0)`
2025-07-29T09:19:26.727597Z TRACE bevy_enhanced_input::context: reading value `Axis1D(0.0)`
2025-07-29T09:19:26.727689Z TRACE bevy_enhanced_input::context::trigger_tracker: `DeltaScale` changes `Axis1D(-1.0)` to `Axis1D(-0.0168728)`
2025-07-29T09:19:26.727780Z TRACE bevy_enhanced_input::context::trigger_tracker: `DeadZone { kind: Radial, lower_threshold: 0.2, upper_threshold: 1.0 }` changes `Axis1D(-0.0168728)` to `Axis1D(-0.0)`     
#

For biderectional movement you don't need a DeadZone, yeah.

bitter crater
bitter crater
graceful tapir
#

Is it possible to use enums like in lwim?

#

I'm thinking the ability to have a clump of enums for each game mechanic as required would be suitable.

sharp warren
graceful tapir
sharp warren
graceful tapir
#

Maybe action bundles should work how bevy bundles work (if they don't already), where required defaults of components are already added if not edited.

#

Also, there seems to be no fmt implementations.

#

Also, can observers have all the operators as functions like run_if?

sharp warren
sharp warren
graceful tapir
graceful tapir
#

Should be Display::fmt

#

(I think)

sharp warren
sharp warren
graceful tapir
heady mauve
#

Since Actions are their own Component structs, wouldn't you have to derive Display or Debug on them yourself?

graceful tapir
#

Guess it's a thing for the future.

#

But anyway

sharp warren
sharp warren
graceful tapir
#

I don't seem to be able to apply run_ifs in observers

#

Nor Schedules

#

Do I have to use a resource or something and separate the function?

heady mauve
graceful tapir
sharp warren
#

No, it's not related to it

#

And you unlikely need to derive Display or Debug on actions. It's just unit structs.

sharp warren
sharp warren
#

It's all in the quick start guide.

graceful tapir
#

I see. But are observers more optimal?

#

Alice has mentioned that this is observer-first.

sharp warren
#

Yeah, it's a preferred way to run small logic.
But sometimes you need a system, so we support both ways.

graceful tapir
sharp warren
graceful tapir
sharp warren
# graceful tapir So no performance difference?

As I said, depends. If you have a heavy logic, a system is faster. For a small logic observers are beter because scheduling a system has its own cost, which might not outweight the logic inside it.

#

But realistically for an input handling you want to use an observer almost all the time.

graceful tapir
sharp warren
graceful tapir
sharp warren
graceful tapir
#

Is what I meant

sharp warren
#

I don't understand you πŸ™‚

heady mauve
#

@graceful tapir Just Query for the Action component you created.

sharp warren
#

Please, read the quick start guide first

graceful tapir
#

I thought it was one or the other is all

graceful tapir
#

Ah, Apologies. What I meant by resource is if you want to use the result of input handling in systems.

#

since an observer doesn't have run_if or schedules

sharp warren
graceful tapir
#

Would you need to make a resource

#

Since observers are best for inputhandling

sharp warren
heady mauve
#

I really need to update my project with the new component based model so that I have more experience with it.

sharp warren
#

Or if you already have a system that moves the character based on whether it’s jumping or its movement vector, just query for action values instead.

#

We need an example with a character controller πŸ€”
I were thinking about re-creating Mario controls from SMW.

#

But currently busy with other things

round portal
sharp warren
round portal
#

Am I doing something wrong? are Cardinal\Axial bindings not suitable for bindings! macro?..

        actions!(PlayerContext[(
            DeadZone::default(),
            Scale::splat(0.3),
            Action::<Move>::new(),
            bindings![ Cardinal::wasd_keys(), Axial::left_stick() ]
        )]


#

Ok, I yield - I need to figure out new component approach before I do an example.
IMO it's not really intuitive. For example if I had lots of bindings I have no idea where to put Cardinal, Axial and others

sharp warren
round portal
#

oh, ok, I'll take another shot at this

sharp warren
#

Made a small post about my project, which mentions this crate too πŸ™‚
#1264625779296174110 message

graceful tapir
#

I have a bit of an issue, in bevy_asset_loader, you can have loading screen via loading states that are attached to bevy states, in which you have to make sure a function runs only when it's in the after load state, meaning that currently input handling observers are seemingly impossible.

heady mauve
#

You may have to explain what you are trying to do. Why don't you hold off on creating the Input Context until the after load state is valid?

heady mauve
#

I haven't played with bevy_asset_loader yet. How does it inform you that an asset is loaded? Does an observer get triggered?

graceful tapir
heady mauve
graceful tapir
#

Do you have to spawn the input context with the player?

#

@heady mauve

#

For player input

heady mauve
#

No you don't have to, but it might be easier to do what you want to do if it is.

#

That way the input contexts are only valid while the player exists. But you might also have input contexts that are only valid for menus so those wouldn't be associated with the player but when the menu exists.

graceful tapir
#

Technically big_space root_grid is only for normal objects anyway

#

Spawning the player in it would be meaningless if it's the floating origin

graceful tapir
#

I just realized that my setup function only runs after everything is loaded

#

so issue solved

#

Basically anything spawned in the same funciton as the input creation doesn't need run_if(in_state())

#

But just one issue

#

run_if(not(egui_wants_any_keyboard_input)) is required for anythign keyboard

heady mauve
#

Observers ignore states, right? So if I have a Paused state but don't want player input to activate during an observer is the easiest way to accomplish that to remove and then readd the bindings when transitioning into and out of the Paused state?

sharp warren
heady mauve
#

Seems like a lot of code duplication if I have a lot of observers though.

sharp warren
brittle swallow
#

You can also remove observers, for example when you leave a state. If you abstract the details away (removing them is a little weird), then you can avoid a lot of boilerplate.

heady mauve
#

Hmmmm. Trying to use Cardinal::wasd_keys() and ran into an issue:

    Cardinal::wasd_keys().with(Negate::x())

will crash with the following error:

Bundle (bevy_enhanced_input::binding::relationship::BindingOf, (bevy_enhanced_input::binding::Binding, bevy_enhanced_input::modifier::negate::Negate), bevy_enhanced_input::modifier::negate::Negate) has duplicate components: bevy_enhanced_input::modifier::negate::Negate
#

Moving the Negate::x() to the Action level doesn't crash.

sharp warren
weary maple
# brittle swallow You _can_ also remove observers, for example when you leave a state. If you abst...

technically you don't even have to do that if you can use a Single in your observer.

fn spawn(mut commands: Commands) {
    commands.spawn((
        Player,
        OnFoot,
        actions!(OnFoot[(Action::<Jump>::new(),
                ActionSettings {consume_input: false, ..Default::default()},
                bindings![KeyCode::Space])]),
        actions!(MidAir[(Action::<Jump>::new(),
                ActionSettings {consume_input: false, ..Default::default()},
                bindings![KeyCode::Space])])
    ));
}

fn foot_jump(trigger: Trigger<Started<Jump>>, mut commands: Commands, player: Single<Player, With<OnFoot>>) {
    println!("Foot Jump triggered on {:?}", trigger.target());
    commands.entity(trigger.target()).remove::<OnFoot>();
}

fn air_jump(trigger: Trigger<Started<Jump>>, player: Single<Player, With<MidAir>>) {
    println!("Air Jump triggered on {:?}", trigger.target());
}

The above will only print the Foot Jump line (and more importantly it will only do it once, despite leaving the binds and actions active), even though theres no logic to make it not trigger the air jump, and i have ActionStates non consuming so its not just OnFoot consuming the jump action, just the fact that the Single is empty.

I don't know why it works instead of panic'ing, but it does.

brittle swallow
weary maple
#

so wed just be adding When<Context> on everything

brittle swallow
#

Don't you worry, I PRed in If ferrisHappy

#

which is a tiny bit nicer than When

weary maple
#

that issue just made me aware of Populated too, which i guess is more appropriate for the examples i used instead of Single LUL

quasi epoch
#

@sharp warren i've been thinking about an input buffer feature, i'm not sure how technically difficult it would be to implement, but a high level overview of how it would work in a basic form would be this. action bindings can optionally contain a run condition system (like the run_if() function) and maximum holding ms (or frames), and when the input is triggered that condition it checked for, and if it's not met the action is added to a vec of queued inputs. each frame all the timers are ticked, and then if completed the input is deleted, otherwise the run condition is checked again, and if true then the action event is sent like normal

#

idk how run conditions work under the hood, nor sending input actions, but apart from that it seems doable

#

i might even open a pr if i can figure out those two things

sharp warren
sharp warren
#

You just want to delay the input?

quasi epoch
quasi epoch
sharp warren
sharp warren
quasi epoch
#

ah

quasi epoch
sharp warren
#

What is your use case with the input delay? Just curious πŸ™‚

quasi epoch
cursive gorge
#

Not just platformers. Lots of action RPGs let you queue up the next attack in a similar way!

sharp warren
#

Makes sense, but I didn’t expect it to be handled on the BEI side πŸ€”
Feel free to experiment with it, though.

quasi epoch
#

and then triggering them

sharp warren
round portal
#

added simple character controller PR, let me know if you want to add anything

So far I have to say - there are quite a few rough edges with new component approach that can lead to a confusion. At least these two:

  • with Cardinal/Axial only spawnable like this, not in macro
  • if you add keys/buttons to bindings! in a way other than [btn, btn] it will error out with a non-clear message. f.e. [(KeyCode::Space, GamepadButton::South)] which is what I though should intuitively work from children macro
sharp warren
#

As for the second one, [(KeyCode::Space, GamepadButton::South)] won't work because you trying to spawn a single entity with 2 bindings, while it should be separate entities.
The reason the error is not super clear it's because unlike with children! I expect the first element to be Into<Binding>. Otherwise it would be inconvenient to write πŸ™‚

#

It will be much nicer when bsn comes.
Right now we are a little limited by the Bevy spawning ergonomics.

brittle swallow
#

Right? Like we lose the ability to provide people with compiler errors when we move towards a BSN-first approach.

sharp warren
brittle swallow
#

What I mean is that you can't guarantee people use the correct components in the correct places, just like oleks did with the bindings.

#

Oh but is your bindings! macro not a simple relationship like children!?

sharp warren
sharp warren
mystic torrent
#

mmh i must say the BEI as components has not clicked yet for me.

In the process of converting from the old way. I have optional (e.g. no binding for an empty slot) and bindings with dynamic modifiers (e.g. depends on an ability/item/... equipped), all in a particular order. Having to cramp them into impl bundles runs me into some ergonomic issues. E.g. i can use ActionSpawner to dynamically (if) spawn (sub)bundles but than it triggers closure lifetime issues which requires clones for things that should not need it etc. Nothing unsolvable just a bit un-ergonomic. Are these the kind of issue you expect to improve once BSN lands?

Or maybe my design needs to be revisited.

sharp warren
sharp warren
#

And I think you can replicate the old behavior by just spawning separate entities with ActionOf πŸ€”

limpid lake
#

I have to say I also stumbled upon the bindings![] error and I had to reread the docs (as I should have done before that πŸ˜ƒπŸ‘) but I like the new components system!

proud coral
#

Is it a problem to have two input contexts at the same time on an entity?

heady mauve
#

@proud coral You can stack input contexts, set the ContextPriority to determine which ones consume inputs first.

proud coral
#

oooh, it looks like I wanted to disable "consume_input"

#

for the way I'm using the lib

#

Because I have keys that trigger an Event depending on the State an entity is, and when it's on multiple layered states I want all actions to trigger, and then decide what I want to do with them based on the state/s I'm in

#

is there a way to make it a global default? Instead of having to disable it per action with

                ActionSettings {
                    consume_input: false,
                    ..Default::default()
                },
heady mauve
#

I don't think so with Actions holding their own state. I suppose to make it easier you could save it as a Resource and then use that to set all the actions using it.

quasi epoch
#

i've found out that bevy_tnua has a built-in input buffer, as well as a bunch of other cool features so i'm migrating to that

quasi epoch
#

is there a way of running a function every frame but still connecting to bei? i assume it wouldn't work but like an Option<Trigger<>>

sharp warren
sharp warren
sharp warren
sharp warren
#

And the same for #1090432346907492443

outer wyvern
sharp warren
#

Ah, right πŸ™‚
Thank you!

native pendant
#

project harmonya got a final name?

sharp warren
# native pendant project harmonya got a final name?

I hope so! But this time I used links to crates.io just in case πŸ˜…
I made a small post about it: https://lemmy.ml/post/34012299

Background For those who don’t know, I’m trying to create a FOSS life

simulation game β€” something similar to The Sims. I haven’t posted updates in
[email protected] [/c/[email protected]] about the project for a
while, only updates to the related crates I maintain. It’s just me and my wife
didn’t have enough motivat...

mystic torrent
# sharp warren And I think you can replicate the old behavior by just spawning separate entitie...

I have pretty much looked at every example of BEI at this point :p I indeed ended up manually spawing each action (+ ActionOf) . How my code is currently structured is the item/ability/... decides the settings/components of its action/binding (maybe item A needs a key be hold down x seconds, while B is only needs to trigger on key up, ... or maybe some items require no action/binding) hence it is dynamic and proves hard in practice to compose a single "final impl Bundle"; closures of ActionSpawner also have implications.

Once i let go of trying to create a single impl Bundle the problems also disappeared. It is a bit more verbose but not that bad.

Thanks!

weary maple
#

I should probably give manual creation of the entities a try.
I found the actions macro workflow "forcing" me to delete all the actions and bindings and remake them even if they are shared between contexts, when changing inputcontext to be... unsavory to put it bluntly.

it felt bad with the old way too, but atleast there since actions and contexts were coupled it was kind of ignorable.

But looking at the way the new api works, i guess theres no reason I couldn't just manually spawn an action, and then insert the ActionOf component for each context that uses it.

sharp warren
weary maple
#

monkaHmm what do you mean by compose contexts?

Ive been thinking of contexts as states in an FSM, so the behaviours are whats tied to the context not the actions. Then to change the resultant behaviour of an action, I change the "state" of the "fsm" by inserting the relevant context, and removing the now invalid context.

#

Genuinely might just be thinking about it wrong and having a stupid moment ngl LUL

That said, having a way to disable contexts would be pretty neat.
inb4 contexts are entities Kapp with a "ContextOf" component

sharp warren
#

Of course, you can also manage actions dynamically, but depending on your use case, managing only the contexts might be more convenient.

weary maple
#

Ah k yeah if thats the intended design I can see how that conflicts with the way I was trying to use it.
I was doing things like having a single Move action thats reused by any context that has some kind of movement behaviour, then writing systems/observers for each context

#

ContextPriorities I guess would be how I would get the behaviour im looking for, + making sure the binds are consuming

sharp warren
#

The advantage of managing actions is the ability to attach StateScoped to them to automatically delete the action when you leave the state.

sharp warren
graceful tapir
#

Is there anything for doing single axis input with a and d?

#

given that there's an f32 type for action_output.

heady mauve
weary maple
#

out of curiosity why not just pull the Vec2 and just grab the X value from it?
Saving a single f32 value isnt going to make a terribly large difference performance wise.
Unless you want to bind W and S to something else that is.

sharp warren
#

It just looks cleaner in the code as to me.

weary maple
#

valid tbh

#

I guess you could kind of jerry rig a franken action monkaHmm
like make two f32 binds, for a Left and Right action.

then have an unbound "1d move" action, and just combine the values of the left and right binds in a mock to get the final value.

its more janky but you end up with the same "I just want an f32" api at the edge
Atleast until bidirectional is merged i mean.

#

Oh wait bidirectional is already in 15.2.
so he can just copy paste that preset into his codebase LUL
ignore me im overthinking stuff

sharp warren
#

Yeah, the PR just added a few convenient helpers.

sharp warren
#

Thank you!

@weary maple @graceful tapir drafted a patch release with the mentioned methods.

glad bough
#

How do you capture mouse wheel input using the new api?

glad bough
#

Tried, but it panics saying output value should be axis 2D

#

Even without the action that is fired by the mousewheel

heady mauve
glad bough
#

That worked, thanks

glad bough
sharp warren
sharp warren
sharp warren
#

In my crates I use panics for things I expect to never happen.

glad bough
#

It's really weird, I don't know why but I can't reproduce it. Maybe it's something I did in my main repo. I'll keep trying to find the bug

#

In the meantime, I suggest that the panic message be like Output value should be axis 2D, got X

round portal
#

finally trying to move from older version and I have a question: any ideas how can I add actions to already spawned context?
for example before I was doing it with just a cfg(feature, but we cannot do that inside children! yet. Here is an example for older code:


     #[cfg(feature = "top_down")]
    {
        actions.bind::<ScrollZoom>().to(Input::mouse_wheel());
        actions.bind::<RotateToggle>().to(MouseButton::Right);
    }

but I cannot wrap my head around how to do it with newer approach

heady mauve
#

Is there a reason you don't want to have them as additional contexts you can layer on?

inner sky
#

Also updating to the new API, so far loving it πŸ™‚
One thing that I believe must have a better way is this:

(
  Action::<Rotate>::new(),
  Negate::all(),
  Scale::splat(DEFAULT_SENSITIVITY),
  Bindings::spawn((Spawn(Binding::mouse_motion()), Axial::right_stick()))
),

That last Bindings::spawn call looks very verbose for something that seems very usual to do. Is there a way to make this work with bindings!?

round portal
sharp warren
sharp warren
sharp warren
#

SpawnWith and presets like Axial are SpawnableList.

#

Interesting, I don't see a single issue about it in Bevy πŸ€”
I guess people rarely spawn related entities?

sharp warren
#

Even children, they have the same problem.

inner sky
#

I use SpawnWith to spawn children with observers on them

inner sky
inner sky
#

Oh, or the 16 children limit

#

I believe that one also requires SpawnWith?

sharp warren
#

I guess people rarely mix regular children and SpawnWidth πŸ€”

inner sky
#

Where button_widget internally calls SpawnWith

inner sky
sharp warren
sharp warren
inner sky
#

How to work around this? No clue :/

sharp warren
#

Ah, sorry - I read it wrong. I thought you had a little suggestion πŸ™‚

inner sky
#

Hehe

#

I wish

#

@jaunty niche do you have some cool ECS hack?

sharp warren
inner sky
inner sky
#

so that doesn't help in this case

#

At least, not without post-hoc adjusting the hierarchy

#

Then you would have some more freedom in applying children! multiple times

sharp warren
#

Ah, got it :(
I'll keep looking for a solution. BSN would probably help.
But I think we need to adjust the spawning API in general...

inner sky
inner sky
#

Seems like a requirement that would be best to catch early

sharp warren
#

Good idea!

inner sky
jaunty niche
#

other than abusing BundleEffect

inner sky
sharp warren
#

I starting to think we need to swap X and Y axes for the wheel πŸ€”

#

Who even use horizontal scrolling? πŸ˜…

#

Or provide a bundle

heady mauve
#

Maybe separate the axes? Most people use vertical scroll but still have a separate horizontal scroll binding? Like maybe mouse_wheel for regular and mouse_sidescroll for horizontal?

glad bough
#

I have never seen a mouse that scrolls sideways, so that might be a good idea

glad bough
#

Burn the heretic! πŸ”₯ πŸ”₯ πŸ”₯

inner sky
#

Also apple mice have omnidirectional scrolls

inner sky
#

Also, do laptop touchpad scrolls count as horizontal scrolls?

#

I think it’s more common than you'd think

heady mauve
#

Good question, they likely are seen as the same thing.

sharp warren
heady mauve
#

You probably want to use Binding::mouse_wheel().with(SwizzleAxis::YXZ)

glad bough
#

Ok now I'm starting to think the crate is just not on my side

heady mauve
#

That might be a my bad. I didn't go to the docs to double check it was right.

glad bough
#

Is fine, I'll try going ahead without this crate for now until I can really grok it

sharp warren
#

Just git apply <path/to/file.patch>

sharp warren
sharp warren
# glad bough

Ah, it's because of a comma after Swizzle! This is so weird πŸ€”
I will look into it. That's because bindings! are a bit special comparing to children!. In bindings! I try to apply Bindings::from for the first element to writing it for every binding. But it's quite hard to do with macro_rules correctly. Maybe I should switch to proc macro for this specific one. We have a macro crate anyway.

compact island
sharp warren
#

Don't worry, with the approach we planning, you will be able to use horizontal mouse scrolling too.
Although, I think it's cursed.

compact island
#

cursed? why? how? πŸ˜†

lilac monolith
#

Hello
What do i do if i have put too many actions in the actions! Macro? I try to nest some of them in () but that just causes a crash.

inner sky
lilac monolith
#

Oof

#

Ill try

sharp warren
#

Because there are no tuple impls, I woudn't expect any limits

brittle swallow
#

the problem was more the trait than the macro (fake variadics), but the macro could be adjusted to work better with the trait (oh sorry wrong context)

sharp warren
inner sky
sharp warren
#

Ah, it's because of the RelationshipTarget::spawn that accepts tuples. I think I can copy a fix from the main.

sharp warren
# sharp warren Ah, it's because of a comma after `Swizzle`! This is so weird πŸ€” I will look in...

Fixed it:
https://github.com/simgine/bevy_enhanced_input/pull/152

This also removes the need of wrapping single elements into braces when mixed with tuples.

GitHub

It&#39;s impossible to properly express &quot;convert first element into Binding&quot; with a macro_rules. But I realized that we can just move some of the things into a type system. Th...

sharp warren
sharp warren
#

We thinking about setting ActionSettings::require_reset to true by default. I would like to hear opinions from other users of the crate.

round portal
#

I am scratching my head on how to translate this way of getting value to a new approach

 let handle = if actions.value::<Crouch>()?.as_bool() {
sharp warren
#

If yes, then the most convenient is crouch: Single<&Action<Crouch>> and then let handle = **crouch;.

sharp warren
sharp warren
#

I'll draft a new release once Alice reviews them πŸ™‚

thick kiln
#

Hi, i haven't done extensive testing, but it seems like the Actions relationship target might be getting updated every frame?
(not necessarily modified, but changed detection is triggered on it).

I just noticed that a system that has Changed<Actions triggers every frame

sharp warren
thick kiln
#

I'm coming back to networking the new version of BEI; I got my problem of switching from one ActionState component to multiple components working (although it's a bit brutal https://github.com/cBournhonesque/lightyear/pull/1151/files#diff-ff31fe36f056472edc4156635f518657425cbbd635046c91818104db4d1302a0R60).

I have a couple of flows in mind:

  • user spawns Context + Actions entities on server, and replicates them to the client. On the client, the user adds Bindings (or an InputMarker) to the action entities. I think I need to replicate Action<A> so the user can identify which action entity corresponds to which action, so the user still has to register each action type to the registry.

    • one issue is that ideally the user wouldn't have to spawn Action entities on the server, since inputs are mostly a client side concern
  • user spawns Context + Actions entities on the client, and adds bindings to them. I send an InputMessage which holds something like Vec<(Entity, (ActionState, ActionValue, ...)) (the Entity is the ActionEntity, and the values are the snapshot needed by the server to reconstruct the actions).
    The issue is that with this design, the server doesn't know which Action entity corresponds to which InputAction, so I would also have to send some extra data like Action<A>, and have custom logic on the server to add the ActionOf + the Action<A> entity on the client. I cannot do that directly via replication because I don't want to add the Replicate component on the client entity

GitHub

Bevy_enhanced_input got updated recently and now stores its states in 4 components (ActionState, ActionValue, etc.) instead of a single component like ActionState.
This means that our lightyear_inp...

#

I guess I can have a special BEIInputMessage that is distinct from my normal InputMessage.
The InputMessage contains Vec<(Entity, ActionState)> and is used to transmit the steady-state stream of inputs.
The BEIInputMessage would be used to transmit the hierarchy of Context<>Actions from client to server + add the Action<A> component on the server action entities

sharp warren
sharp warren
outer wyvern
#

@sharp warren there's a couple more complex PRs in the BEI queue

#

I've seen them, but I'm not going to be able to dedicate time to them today

#

And may not be able to for a bit due to the 0.17 Bevy release

sharp warren
# outer wyvern I've seen them, but I'm not going to be able to dedicate time to them today

Didn't even expect to get reviews on weekends πŸ˜…
Sure, take your time!

The activation/deactivation PR may look big diff-wise, but the first commit contains a few relevant internal renames. The implementation itself is very straightforward.
The second PR just splits MouseWheel field into 2. But we can't decide on naming.
After that I'll draft a new release, no more changes planned.

sharp warren
thick kiln
thick kiln
thick kiln
#

Maybe that's niche, but should the update system use Option<InputReader> so that it would still run without InputPlugin? (and users would update inputs via mocking)

sharp warren
sharp warren
inner sky
#

Bit unfortunate to be forced to change another push-style to a pull-style

#

I realize there's nothing BEI can do about this until we have timestamps

#

Just a bit sad that the push-style is a bit of a footgun when working with character controllers right now :/

round portal
inner sky
#

In general, into_inner() is very useful when working with Single πŸ™‚

#

foo: Single<(&A, &B)>
then
let (a, b) = foo.into_inner();

inner sky
sharp warren
#

Yeah, I also prefer the push-style 😞

inner sky
#

One day I'll succumb to the temptation of writing a character controller that internally accumulates inputs so that users can just use BEI normally and don't need to know about this

#

But so far, I've successfully fended off that particular yak shave haha

sharp warren
#

Or we find a brave soul to implement timestamps for Bevy input πŸ™‚

inner sky
#

We just need someone to actually implement it

#

I don't feel qualified at all for this though, otherwise I'd have done it

sharp warren
#

Yeah, not an easy task...

cursive gorge
inner sky
#

should be doable-ish

sharp warren
sharp warren
thick kiln
#

Looks helpful to me. So for example you could build a Player entity with 2 contexts (InGame, InMenu) and swap between the two by selecting which one is active?

limpid lake
#

I would use it when merged as currently I have a context that I am cycling on/off quite fast based on inputs and this would probably be more effecient

vague temple
#

I would love that for when my player dies

sharp warren
#

Thank you all!

#

Will draft a release once Alice reviews πŸ™‚

thick kiln
#

While debugging I find that it would be helpful if I could instead ActionOf<C> in the egui inspector

#

Would you be ok with a PR that defines a trait Context: Component + Reflect? or (Component + TypePath)?

sharp warren
thick kiln
#

It doesn't work; compiler asks for TypePath to be implemented on C

#

oh you mean in my code?

#

yep, this works

sharp warren
thick kiln
#

I think automatic reflection doesn't work with generics; we'll see

sharp warren
#

I think you are right.
But I remember there was a suggestion to automatically register on use in a system, which would work for generics. But not sure if the team decided against.

outer wyvern
#

Reviewed all open PRs πŸ™‚

sharp warren
zinc cliff
#

any thoughts on a macro for defining a context + all of its actions more concisely?

#

something like:

input!(
  #[input_context(priority = 5)]
  context PlayerInput {
    Move(Vec2),
    Jump(bool),
    MouseAim(Vec2),
    Dig(bool),
    Interact(bool),
  }
);
// =>
#[derive(Component, InputContext)]
#[input_context(priority = 5)]
pub struct PlayerInput;

#[derive(Debug, InputAction)]
#[input_action(output = Vec2)]
pub struct Move;

#[derive(Debug, InputAction)]
#[input_action(output = bool)]
pub struct Jump;

#[derive(Debug, InputAction)]
#[input_action(output = Vec2)]
pub struct MouseAim;

#[derive(Debug, InputAction)]
#[input_action(output = bool)]
pub struct Dig;

#[derive(Debug, InputAction)]
#[input_action(output = bool)]
pub struct Interact;
#

the set up of the actions/context are prob the biggest friction point for me

heady mauve
zinc cliff
#

o no I probably haven't seen it, lemme check it out

#

ok ya this looks much nicer! ty @heady mauve πŸ™‚

vague temple
#

To grab an action value, for example the amount of mouse motion i had in that frame. I need to query &Action<CursorMovement> as per

fn apply_input(
    jump_events: Single<&ActionEvents, With<Action<Jump>>>,
    move_action: Single<&Action<Move>>,
    mut player_transform: Single<&mut Transform, With<Player>>,
) {
    // Jumped this frame
    if jump_events.contains(ActionEvents::STARTED) {
        // User logic...
    }

    // We defined the output of `Move` as `Vec2`,
    // but since translation expects `Vec3`, we extend it to 3 axes.
    player_transform.translation = move_action.extend(0.0);
} ```
Correct?
#

that will return the given vector

#

@sharp warren I made a TPS game camera if you want I can make an example displaying how to do it using your api

sharp warren
#

Definitely useful once we upstream the crate for bevy, just not sure about adding it to BEI

heady mauve
#

Is it a pull style using systems instead of push using observers? Having examples of both might be helpful in that case.

sharp warren
vague temple
# sharp warren Yep

Do you think the return type of the macro actions! is a little chonky. I have multiple times where I build my InputContext and I used to do a simple helper impl like this.
On 0.16 now it keeps returning the SpawnableRelatedBundle which is rough πŸ™ do you perhaps knwo any other way Mr Shatur

impl PlayerInputs {
    pub fn default_input_map() -> Actions<Self> {
        let mut actions = Actions::<Self>::default();

        actions
            .bind::<Move>()
            .to(Cardinal::wasd_keys())
            .with_modifiers((DeadZone::default(), SmoothNudge::default()));
        actions.bind::<Jump>().to(KeyCode::Space);
        actions.bind::<Dash>().to(KeyCode::ShiftLeft);
        actions.bind::<Interact>().to(KeyCode::KeyT);
        actions.bind::<Attack>().to(Input::MouseButton {
            button: MouseButton::Left,
            mod_keys: ModKeys::empty(),
        });
        actions.bind::<NextWeapon>().to(KeyCode::KeyE);
        actions.bind::<PreviousWeapon>().to(KeyCode::KeyQ);

        actions
    }
} ```
sharp warren
heady mauve
vague temple
#

and call it ah man i just learned something

heady mauve
vague temple
#

And I just found out that now

heady mauve
#

Darn. I was kinda hoping you had a unique use case that would have been interesting.

vague temple
#

no sir just good old avoid repetitive code

vague temple
#

@sharp warren I finished the example just let me know if you want it in. This is a sample in one of my game sub-crates

sharp warren
graceful tapir
#

I ran into a problem where I wanted to be able to press an action to interact with ui, an the ui element can't handle clicks on it's own, but I don't the player doing an ingame action while they're interacting with it, so I thought maybe something like action layers would be a good idea?

#

Because input handling libraries exist so that you don't have to do pressed() || pressed() && pressed() and then copy and paste it several times, however there doesn't seem to be a way to avoid it in this scenario.

heady mauve
# graceful tapir I ran into a problem where I wanted to be able to press an action to interact wi...

You can layer contexts on top of each other and @sharp warren recently added the ability to deactivate contexts so that you don't have to remove them. Can you describe what you are trying to do a little more?

For example, are you doing something like a quick time event where something pops up on the UI and you want the user input to do something during that but the input would otherwise be used for different actions? If so, adding another context layer specific for those events with a higher priority should consume those inputs if received. Although you could also inactivate the current context and activate the QTE context instead.

Perhaps look at the context layer and context switch examples.

graceful tapir
heady mauve
#

You can have multiple context layers, and the highest priority layer with a valid action binding for an input will consume the input (unless you set it not to).

heady mauve
#

Sure, look into the context layer example and if you have any questions about it, let us know.

graceful tapir
#

Has the bidirectional stuff earlier been added to crates.io yet?

#

ad_keys() etc

heady mauve
#

According to the docs, the bidirectional stuff (I searched for ad_keys specifically) is in 0.15.3 so if you are pulling at least that version you should have it.

graceful tapir
#

maybe I have to remove then add it

heady mauve
#

Have you tried cargo update after changing the version?

graceful tapir
heady mauve
#

Try specifying the package specifically you want to update:
cargo update --package bevy_enhanced_input

vague temple
#

I forgot to add tpscontext

#

spent 30 minutes trying to do layering

#

today is not my day

heady mauve
#

You mean registering the context?

vague temple
#

iit is alwayss that or plugins

graceful tapir
#

Is there any way to set a global bind without the need of an inputcontext?

#

I guess not, the context_switch example has the same binding for opposite actions.

#

Also in this case I just want to overlap one action of the player context on switch

heady mauve
#

A way you can have "global" binds is by layering contexts on each other and any input not consumed by contexts on higher priority layers will be available for lower layers. So you could have a Global context that uses the Escape key to show a pause menu and still have a player context with a priority above that which doesn't use the Escape key in any actions. Pressing Escape will still let you see the pause menu then.

See the context layers example for something like that.

graceful tapir
#

I'm spawning Bidirectional according to bidirectional.rs and it's not working
(Key_.into())

heady mauve
#

Try doing this instead and let me know if it works:

    Bidirectional {
        positive: Binding::from(KeyCode::KeyD),
        negative: Binding::from(KeyCode::KeyA),
    };

Replace the KeyCode::Key with whatever key you are trying to use.

#

@graceful tapir Did you have any luck or still working on it?

graceful tapir
#

Apparently 2 contexts can be active at the same time.

heady mauve
graceful tapir
#

Therefore I can just divide the needed inputs into one.

sharp warren
#

Yeah, you better use Binding::from.

graceful tapir
#

Apparently the compiler doesn't like this

Combat,
actions!(
    Combat[
        (Action::<Attack>::new(),bindings![MouseButton::Left, GamepadButton::West],),
    ]
),
sharp warren
graceful tapir
sharp warren
graceful tapir
sharp warren
vague temple
#

@sharp warren Here is the sample of the plugin I wrote, I think I will need to adjust from avian to meshcast but besides that is pretty much it. It does use the so called pull style

sharp warren
vague temple
#

I can make it shorter for sure could also make a simple character that is followed around your choice

sharp warren
sharp warren
#

One more thing: I think it would be nicer to apply smoothness using BEI instead of lerping manually.

#

@vague temple Also looks like your lerping is not quite right in general πŸ€”
You need to use half decay

#

That's what BEI uses

vague temple
#

Guess I could just do the shapecast chonkier hoho

graceful tapir
#

How do I get the entity target from bei without a trigger?

sharp warren
graceful tapir
#

Because I want to make certain contexts inactive based on conditions.

sharp warren
graceful tapir
sharp warren
graceful tapir
#

But if I wanted to set a context inactive without needing a trigger how would I do that?

#

ActionOf<Context>?

#

I'm not understanding how it's supposed to be used.

sharp warren
#

And insert ContextActivity<Context>::INACTIVE.

sharp warren
vague temple
#

@sharp warren Smooth nudge feels a little unresponsive

#

although it is smooth indeed

#

Pr on the way with finished sample

sharp warren
vague temple
#

yup

graceful tapir
#

I'm going according to context_switch.rs btw

#

to be exact:

if scrollvalues.hovered {
        commands.entity(*combat).insert(ContextActivity::<Combat>::INACTIVE);
        commands.entity(*scroll).insert(ContextActivity::<Scroll>::ACTIVE);
    } else {
        commands.entity(*combat).insert(ContextActivity::<Combat>::ACTIVE);
        commands.entity(*scroll).insert(ContextActivity::<Scroll>::INACTIVE);
    }
sharp warren
#

context_switch works just fine, so I assume something is wrong with your code

vague temple
#

@sharp warren pr inbound

sharp warren
#

Thank you, will take a look soon

graceful tapir
#

Yeah contextactivity is a little bugged, when inserted only Started<> will make the boolean true

sharp warren
#

I don't understand what you're saying.
We have tests for context toggling and the switching example works as expected.
But feel free to submit a minimal example to reproduce the issue.

graceful tapir
#

But i'll debug a little more

#

I also didn't find what was wrong with my code in regards to the previous issue

#

It seems the inputs are overlapping somehow

#

When I switch between fired and started for Attack, the other input for another thing is effected

#

keep in mind the trigger is just for a function that prints something

#

nvm

#

It still just has to do with switching activity

#

I'm aware that you said that the context_switch works, but in this case i'm using 2 entities grabbed from both input contexts

pub fn should_stop_attacking(
    scrollvalues: Single<&ScrollValues>,
    combat: Single<Entity, With<Combat>>,
    scroll: Single<Entity, With<Scroll>>,
    mut commands: Commands,
) {
    if scrollvalues.hovered {
        commands
            .entity(*combat)
            .insert(ContextActivity::<Combat>::INACTIVE);
        commands
            .entity(*scroll)
            .insert(ContextActivity::<Scroll>::ACTIVE);
    } else {
        commands
            .entity(*combat)
            .insert(ContextActivity::<Combat>::ACTIVE);
        commands
            .entity(*scroll)
            .insert(ContextActivity::<Scroll>::INACTIVE);
    }
}
sharp warren
#

I will need a full example with clear steps what to do in order to reproduce.
The best way would be to submit a failing test.

graceful tapir
#

I can give you a few functions just incase though

sharp warren
#

I will need a complete example, otherwise I won't be able to help.

graceful tapir
#

So i'm thinking it's a bug with ContextActivity.

#

Maybe it just doesn't like being inserted into inputcontexts.

sharp warren
sharp warren
graceful tapir
sharp warren
# graceful tapir https://pastebin.com/synqvTkg

Can you just upload in a form of archive here (including Cargo.toml), so I can just cargo run it?
Looks like you're using plenty of 3rd party libraries here.
And I will need steps to reproduce. Like "press here", "click there", etc.

graceful tapir
#

temp github page?

sharp warren
graceful tapir
#

Ah, that's what you meant.

sharp warren
#

This doesn't look like a stripped-down version of the game. It even contains assets. I need you to remove everything unrealted to BEI, so I can try to debug the problem on my side.

#

And I need steps to reproduce.

graceful tapir
#

Ah, sorry.

sharp warren
#

Going to sleep right now, will take a look tomorrow. Or maybe other folks will take a look earlier.

graceful tapir
sharp warren
# graceful tapir

Thanks! Now I need steps. I.e. instructions what do I need to do πŸ™‚

graceful tapir
#

This includes when the scroll is not present as well, "oof" should be printed.

sharp warren
#

Also, you run your should_stop_attacking every frame.

#

Which means it will reset the context

#

While I still not sure what is happening, I think it's the source of your problem.

graceful tapir
#

That could be btw.

#

That's probably why only a trigger is used in context_switch to insert the contextacitivity.

heady mauve
#

@graceful tapir You may want to look into the bevy::picking module. It would allow you to get the hover state with an observer so you aren't running a system every frame but using that observer to change the ContextActivity

sharp warren
graceful tapir
#

bevy::picking it is.

#

None the less that phenomenon needs to be looked into.

#

As to why it does that when contextactivities are inserted multiple times or inserted into contexts.

heady mauve
graceful tapir
#

Maybe a panic would do for that.

sharp warren
graceful tapir
#

Interesting.

sharp warren
#

I wonder if we can handle this πŸ€”
But I can't get the previous and current value to properly check it.

heady mauve
#

It is using hooks for OnInsert or OnReplace, right?

graceful tapir
sharp warren
heady mauve
graceful tapir
#

So that might be better than boolean spaghetti code.

heady mauve
#

Or does that happen after the ContextActivity is replaced?

sharp warren
graceful tapir
sharp warren
graceful tapir
#

The bevy rabbit hole is quite deep... I didn't even know those 2 schedules/queries existed.

#

I'm starting to think bevy is designed against any indirection.

heady mauve
graceful tapir
#

Should I spawn a marker component or insert it into the context?

#

probably insert

heady mauve
#

If the entity the context is on already exists you could just insert it on that entity. Although, if you are doing it based on the hover state of something you might want to put it on the entity that is hovered over in case you want to check for other things associated with that.

graceful tapir
#

So just to clarify, I need a marker component because of how the OnReplace and OnInsert schedules work for contextactivities?

heady mauve
#

Although Shatur might have a solution in process for the inputs being reset whenever an INACTIVE ContextActivity is inserted.

sharp warren
#

Still would recommend to avoid running such system every frame

#

You can also check if scrollvalues changes and then run the system via run condition.

sharp warren
graceful tapir
#

I'm guessing TrackedEntities isn't needed

sharp warren
graceful tapir
#

Not that i'm against using componenthooks.

heady mauve
#
graceful tapir
heady mauve
#

Those are the events that can be triggered in observers as an alternative to doing the lower level component hooks.

vague temple
#

@sharp warren Might I ask why does the macro actions, require the filepath bevy?

#
[{
    "resource": "/home/sirmadeira/Projects/psycho_duel/crates/psycho_core/src/player.rs",
    "owner": "rustc",
    "code": {
        "value": "Click for full compiler diagnostic",
        "target": {
            "$mid": 1,
            "path": "/diagnostic message [0]",
            "scheme": "rust-analyzer-diagnostics-view",
            "query": "0",
            "fragment": "file:///home/sirmadeira/Projects/psycho_duel/crates/psycho_core/src/player.rs"
        }
    },
    "severity": 8,
    "message": "failed to resolve: could not find `bevy` in the list of imported crates\ncould not find `bevy` in the list of imported crates",
    "source": "rustc",
    "startLineNumber": 43,
    "startColumn": 16,
    "endLineNumber": 43,
    "endColumn": 55,
    "relatedInformation": [
        {
            "startLineNumber": 169,
            "startColumn": 11,
            "endLineNumber": 169,
            "endColumn": 15,
            "message": "Actual error occurred here",
            "resource": "/home/sirmadeira/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_enhanced_input-0.16.0/src/action/relationship.rs"
        }
    ],
    "origin": "extHost1"
}]```
#

I have a modular style of imports

#

only grabing specific crates of bevy

graceful tapir
sharp warren
#

For more details, see: #engine-dev message

heady mauve
# graceful tapir does "lower level" imply faster?

I don't know enough about the engine to be able to say for sure. But lower level isn't always associated with faster. Sometimes it is something that is more complex to do but often in more powerful ways. If a Trigger<OnAdd> or Trigger<OnRemove> works in observers for your case so you don't have to learn how to use component hooks, then I'd say go with that. If you find you are having difficulty with accomplishing what you are trying to do, then you might need to look at other options like using a component hook directly.

graceful tapir
#

Or at least inline with one.

vague temple
#

hahahaha

graceful tapir
heady mauve
vague temple
#

I was doing 400 lines of code more because of compile time?

#

Yeah not worth it

sharp warren
graceful tapir
graceful tapir
sharp warren
#

Correct

#

But you also can't attach more then a single hook.

graceful tapir
sharp warren
#

Yep

heady mauve
vague temple
#

Another question: What is the advantage of using the conditions instead of doing the modification myself? Is there any perfomatic gain?

graceful tapir
#

Can you do queries in component hooks? I'm guessing not.

sharp warren
graceful tapir
#

What's the best way I would prevent a component from being added more than once since that's the issue with contextactivity?

sharp warren
heady mauve
#

Use an option style query:

    context: Option<Single<Entity, With<Scroll>>>,

If the query comes back as None, then there shouldn't be a component with it.

graceful tapir
#

Then does that solve the multiple contextactivity issue?

sharp warren
sharp warren
heady mauve
graceful tapir
heady mauve
#

It would still find ContextActivity whether it is set to ACTIVE or INACTIVE, right?

sharp warren
heady mauve
#

But if @graceful tapir is using a different marker component, then that would take care of the issue.

graceful tapir
#

Or rather, how would using component hooks fix that?

heady mauve
#

So instead of looking for the context, look for the marker:

    marker: Option<Single<MarkerComponent>>,
sharp warren
graceful tapir
sharp warren
graceful tapir
#

Then how would component hooks fix the issue?

sharp warren
#

What do you want to hook??

graceful tapir
#

I don't want contextactivity to be added every frame

sharp warren
#

The problem: you disable/enable the context every frame.
The solution: don't do this.

#

There are a ton of options how would you do that.

#

Pick whatever works for you

graceful tapir
#

I'm aware, but i'm not entirely sure how to go about this since there are many options.

sharp warren
#

Pick the easiest

#

Probably the simplest would be to check the current value. If the context is already active/inactive, don't insert active/inactive again.

heady mauve
#

@graceful tapir Have you tried doing something like this:


fn scroll_hovered(
    trigger: Trigger<OnAdd<ScrollHovered>>,
    scroll: Single<Entity, With<Scroll>>,
    mut commands: Commands,
) {
    if trigger.target() == scroll.entity() {
        commands.entity(trigger.target())
            .insert((
                ContextActivity::<Scroll>::ACTIVE,
                ContextActivity::<Combat>::INACTIVE,
            ));
    }
}

fn scroll_lost_hovered(
    trigger: Trigger<OnRemove<ScrollHovered>>,
    scroll: Single<Entity, With<Scroll>>,
    mut commands: Commands,
) {
    if trigger.target() == scroll.entity() {
        commands.entity(trigger.target())
            .insert((
                ContextActivity::<Scroll>::INACTIVE,
                ContextActivity::<Combat>::ACTIVE,
            ));
    }
}
#

Wait...I think I need the marker component in there. (Now added)

graceful tapir
heady mauve
#

Wherever you check egui for whether a scroll is hovered you will then add or remove the ScrollHovered component to the context entity you put the Scroll context on.

graceful tapir
#

Perfect. Just to clarify, triggers aren't duplicated in logic when 2 or more observers share the same trigger right?

heady mauve
#

What do you mean by duplicated in logic? As far as I know if multiple observers are looking for the same trigger event, they will all run. But you mentioned having different marker components for different contexts, so only the observers for the correct marker component would be triggered.

graceful tapir
heady mauve
#

I may have the order reversed. I typed it quick.

#

Ok, should be more like: trigger: Trigger<OnAdd, ScrollHovered>

graceful tapir
#

in regards to "try_remove"

vague temple
#

@sharp warren In your review you told me to make player look at where camera is pointing, a funny issue I ran intoo while doing this in multtiplayer is that in thesis server doesnt have a camera. So I need to buffer the input before hand. Any ideas on how to do that?

sharp warren
sharp warren
#

But honestly, I'd just check the status of activity in your case πŸ€”

#

I.e. without the trigger.

sharp warren
vague temple
sharp warren
vague temple
#

wait perhaps I can insert an action? an this is confusing

graceful tapir
vague temple
#
fn buffer_rotation(
    q_camera: Query<(&Transform, &CameraMode)>,
    mut players: Query<Entity, (With<PlayerMarker>, With<Predicted>)>,
    mut commands: Commands,
) {
    let (transform, camera_mode) = q_camera.single().expect("Camera to have a transform");
    // Only do this if in tps mode
    if camera_mode.ne(&CameraMode::Tps) {
        return;
    }

    let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
    for player in players.iter_mut() {
        commands.entity(player).insert(ActionMock::new(
            ActionState::Fired,
            Vec2::new(yaw, pitch),
            MockSpan::Manual,
        ));
    }
}```>
I think this works
graceful tapir
sharp warren
sharp warren
sharp warren
#

What is ScrollHovered in your case?

#

Is this a custom component you insert from a system you run every frame? In that case, I'd just directly work with context activity.

graceful tapir
#

I mean I could just use componenthooks if that's what you mean, if it's truly a concern.

vague temple
#

The solution I came up is not ideal, but I guess it will work. I made it so we have a empty Action, with an ActionMock. I later query that entity Action, and keep adding mock with the rotation value given by camera

sharp warren
graceful tapir
#

As my game will be quite performance sensitive.

sharp warren
graceful tapir
#

I will follow your advice.

vague temple
#

@sharp warren Gonna leave it here just for your design opinion, I convert my inputs to states and i utilize those states for physics and animation what do you say Master Shatur?

#

Ai says that is a good idea

glad hawk
#

I'm wondering what the best way for equipping items from a hotbar or something similar would be. Making an action for each slots sounds like a lot of code duplication

#

right now I just map each key to a different 1d scalar value, but it feels pretty hacky

sharp warren
sharp warren
sharp warren
sharp warren
#

I.e. create a single action and attach it multiple times to the same context.

#

This way you shouldn't have any duplicaton. And in order to detect which slot triggered, attach your own component on each of this action with slot index or something.

sharp warren
graceful tapir
#

This is my replacement for the trigger system tsudico thought of.

pub fn should_attack_setup(world: &mut World) {
    world
        .register_component_hooks::<ScrollHovered>()
        .on_add(|mut dw, context| {
            let combat = dw
                .query(&mut dw.try_query_filtered::<Entity, With<Combat>>().unwrap())
                .single_mut()
                .unwrap();
            let mut commands = dw.commands();
            commands.entity(combat).insert((
                ContextActivity::<Scroll>::ACTIVE,
                ContextActivity::<Combat>::INACTIVE,
            ));
        })
        .on_remove(|mut dw, context| {
            let combat = dw
                .query(&mut dw.try_query_filtered::<Entity, With<Combat>>().unwrap())
                .single_mut()
                .unwrap();
            let mut commands = dw.commands();
            commands.entity(combat).insert((
                ContextActivity::<Scroll>::INACTIVE,
                ContextActivity::<Combat>::ACTIVE,
            ));
        });
}

It apparently does nothing to solve the issue. I'll try his trigger system as well.

heady mauve
graceful tapir
#

Nonetheless it's on_remove and on_add

#

So I guess technically.

heady mauve
# graceful tapir No.

Could you add some logging to that? Either before or after you change the ContextActivity for both you might want to temporarily add an info!("ScrollHovered Added") and info!("ScrollHovered Removed") to check whether it occurs every frame or not.

heady mauve
#

What works? Does the log show it changing every frame or does the log show that it only changes when the hovered state changes?

graceful tapir
#

It doesn't do anything until you first hover over it

#

Then it adds ScrollHovered every frame when it is, and removes it when it isn't.

heady mauve
#

So I would definitely alter the place where you check egui hovered state to see if it is already hovered and only insert or remove the component when the hovered state actually changes instead of checking the state every frame and doing something depending on that state without keeping track of whether it changed or not.

Although if you don't want to do that, you could go with what @sharp warren suggested previously and just check to see:

  1. if the ContextActivity exists on the entity and if so
  2. what value it is set to so that you aren't changing it every frame but only when an actual change occurs
#

Whichever is better for you.

graceful tapir
#

How would I only check if it's been changed?

heady mauve
#

The egui hover state or the ContextActivity?

graceful tapir
#

technically contexactivity would be better

heady mauve
#

I think it would be easier to check ContextActivity. The hover state you'd probably either need a Local State, Resource, or Component to hold the value. ContextActivity already exists so you can check it directly.

Are you already using a query with the Context to get the entity? If so you could just grab the ContextActivity as well:

   scroll: Single<(Entity, Option<&ContextActivity<Scroll>>), With<Scroll>>,

then you can check whether ContextActivity exists and if so, what value it has in case you need to change it.

#

I had to make some changes to my query to make it valid.

graceful tapir
heady mauve
#

It probably doesn't have to be an option since I think it is a required component of Context so will always exist.

graceful tapir
#

/check when they changed

#

vs just being set over and over again

#

That would most likely fix the entire issue

#

I think there should be a better implementation for dealing with contextactivity in the future in my opinion.

heady mauve
# graceful tapir Do local variables have a way to only trigger when they change?

I don't think a local system variable would improve things. It just adds another thing to track. I looked at your should_stop_attacking function and here is an implementation that appears to do what you want. Let me know if it makes sense:

pub fn should_stop_attacking(
    scrollvalues: Single<&ScrollValues>,
    combat: Single<Entity, With<Combat>>,
    scroll: Single<(Entity, &ContextActivity<Scroll>), With<Scroll>>,
    mut commands: Commands,
) {
    // First we check if the scroll hovered matches the context activity
    if scrollvalues.hovered == **scroll.1 {
        // We return if they are the same
        return;
    }
    if scrollvalues.hovered && !(**scroll.1) {
        commands
            .entity(*combat)
            .insert(ContextActivity::<Combat>::INACTIVE);
        commands
            .entity(scroll.0)
            .insert(ContextActivity::<Scroll>::ACTIVE);
        info!("Scroll Hovered");
    } else if **scroll.1 {
        commands
            .entity(*combat)
            .insert(ContextActivity::<Combat>::ACTIVE);
        commands
            .entity(scroll.0)
            .insert(ContextActivity::<Scroll>::INACTIVE);
        info!("Combat Active");
    }
}
graceful tapir
#

Don't get it. Isn't hovered a boolean and scroll.1 just ContextActivity?

sharp warren
heady mauve
graceful tapir
#

Maybe it should follow the context_switch example and give both contextactivities to one input context?

heady mauve
#

I think the issue is that when pressing the mouse button egui takes that as pressing the entity and so removes the hover state from the entity. This switches the context. If you try with a gamepad, the same situation doesn't happen.

#

I'm not well versed in egui so don't know of a possible solution to that.

graceful tapir
#

Maybe a redesigning of this is in need.

#

aaaah

#

I know why it's plotting one at a time

#

hovered and clicked states can be true at the same time

#

so i'll have to add a ||

#

Still no, odd.

#

Because I noticed ScrollHovered would be printed as active every time I click.

#

alright it required image.contains_pointer

#

now everything works fine

#

Thanks for all this

#

With that being said, if that was the issue, would my first solution be ok?

heady mauve
graceful tapir
#

I'll see if it works

#

It works, but something tells me that inserting every frame is laggy, as well as Attack for some reason doesn't trigger when the scroll is turned off. I think a little maintenance should fix that.

vague temple
#

@sharp warren Perhaps it would be nice to make it so we can prioritize one action above another, I know there is a way to prioritize contexts. But i can see some scenarios where an action should have a higher consumption prio (should occur first) than another. I can make the PR just wondering if that is okay by you. For example: I want to jump but to jump I need to disable my push to floor forces. Oddly specific but that is what I ran into.

heady mauve
vague temple
#

What do you mean by list it?

heady mauve
#

Write it first in the code, or if you procedurally generate the actions somehow, you'll need to make sure that whatever you do that action is generated first before the other action.

sharp warren
#

Correct. Actions evaluated by their spawn order.

vague temple
#

Ah I see so for example: Move action is logged in first -> than jump action, move occur first to jump

sharp warren
vague temple
#

Another question: Is it still possible to read the actions that are inflicting the target entity (player)? Like hey this was the actions that occurred on player recently component.

sharp warren
sharp warren
#

Also @glad hawk ^

#

I'll draft a new release right after merge.

vague temple
sharp warren
vague temple
#

Also I think this little accident was cause by me hehe

#

sorry

sharp warren
sharp warren
vague temple
# sharp warren Automatic prioritization is useful because you may not know the right ordering a...

I ran into one right now, in summary, I would like to guarantee input consumption ordering by still utilizing observers. So I can avoid the constant usage of the "pull style" (which is what I am currently doing).
Here is my case:
A player in my game can dash, but while dashing I do not want to apply walking force. WIthout constrained ordering. I lack determinism causing a rollback (server does dash walking), client(walking dash). Is worth noting my dash is a constant force due to gameplay reasons. (i like floaty dashes)

#

There are other scenarios, for example: I have a float char, while jump I need to ensure jump occurs first to apply grounded force. Or the same occurs

#

Oddly specific but hey you know my game is cool hohoh

sharp warren
vague temple
sharp warren
vague temple
#

I think you won this argument, now that I think about it if my actions are guaranteed to be ordered in boot up I just need to do a simple comment.

#

ah

#

pain i will have to refactor again

#

gosh darnit

sharp warren
#

Also if you want to completely disable some actions, you can split into multiple input contexts.

vague temple
#

wait no, that doesnt ensure my grounded state scenario. It does fix my walk dash for sure

sharp warren
vague temple
#

I think the multiplayer deterministic scenarios like stun and so on would still require it, althought they are extremely specific and pull style got it handled.

sharp warren
vague temple
#

I predict my entity will be moving at timeline x+3, but then I get stunned by an ability. That should immediately disable my walking action. The problem is that move is applied through an observer, so I can’t guarantee when it runs. As a result, I might still process a walk input for one frame while I’m actually supposed to be stunned, which creates a client–server mismatch.

The same issue shows up with dashing: the dash needs the walking input from the current frame to determine direction. If I read the wrong value because of update order, the dash goes in the wrong direction. Worth noting I can order them in boot up (but it feels ifei you mentioned the conditions change ordering)

#

Again technically this exists, but I dont think that is the approach you want with your API (you groove the observers)

sharp warren
#

Your issues looks completely unrelated to the priority.
All events triggered in the action evaluation order. So action observers are ordered.

sharp warren
vague temple
#

HAHAHA oh well refactor again

#

@sharp warren One last question: ( Action::<MoveInput>::new(), DeadZone::default(), Bindings::spawn(( Cardinal::wasd_keys(), Axial::left_stick(), )), ), (Action::<RotateInput>::new(),ActionMock::new(ActionState::Fired, Vec2::ZERO, MockSpan::Manual)), (Action::<JumpInput>::new(),bindings![KeyCode::Space]), (Action::<DashInput>::new(),bindings![KeyCode::ShiftLeft]),
I have the Deadzone condition, will that make move run first or dash?

sharp warren
#

Like Shift, Ctrl, etc.

vague temple
#

note i am not handling rotation

quasi epoch
#

how do you bind ui? my other input is OnAdd for the player, but in the main menu that doesn't exist

heady mauve
#

I bind a context to the root entity in the UI.

quasi epoch
#

i'm gonna temporarily use the built in input to have a universal command

#

but the universal command probably won't exist later

#

then later i'll bind separately to teh player and to the ui

sharp warren
#

But you can have separate contexts for your UI and player

#

Just spawn your UI together with its context.

quasi epoch
#

yeah i know, i'm just putting this in to set up the main menu

sharp warren
sharp warren
#

Great, sorry for the confusion πŸ™‚

#

@glad hawk @vague temple the release with action entity inside events is up.

#

It's not a patch-release since I added a field. But no annoucement this time, the release is too small.

#

@thick kiln should be just a version bump in Cargo.toml for you ^

glad hawk
#

sweeet thanks!

#

I'll try it out once I am done with all the other stuff I still have to do

alpine socket
#

How would one do an axis like chord? E.g. holding a button and moving a stick, but outputting the stick's value to the action?

sharp warren
alpine socket
alpine socket
#

Nice, ty

glad hawk
#

much cleaner than my previous solution

#

thanks a bunch

sharp warren
# glad hawk works perfectly!!

Great!

It would be nice to have a runnable example for newcomers...
If you have some free time and can extract your code into a small example, I would appreciate a PR πŸ™‚

round portal
#

Hmm. One thing I noticed that if you want to check multiple actions inside the system - you have to derive Component. but for observers you don't, I do not understand why yet.
Hope it is reflected in docs, because it's somewhat confusing

I also got caught by the Actions<T>(old way) vs Action<T> in systems. nasty

round portal
#

any idea why my Navigate action always [0,0] using wasd? for example Crouch queried the same way works.

UPD: Interestingly enough, if I add arrow_keys they work

#[derive(InputAction, Component)]
#[action_output(Vec2)]
pub struct Navigate;
#[derive(InputAction, Component)]
#[action_output(bool)]
pub struct Crouch;

        (
            Action::<Navigate>::new(),
            DeadZone::default(),
            Scale::splat(0.3),
            Bindings::spawn(( Cardinal::wasd_keys(), Cardinal::arrow_keys(), Axial::left_stick() )),
        ),
        (
            Action::<Crouch>::new(),
            bindings![KeyCode::ControlLeft, GamepadButton::East],
        ),
// query in system
    navigate: Single<&Action<Navigate>>,
    crouch: Single<&Action<Crouch>>,
...
    let (navigate, crouch) = (*navigate.into_inner(), *crouch.into_inner());

sharp warren
sharp warren
limpid lake
#

heya @sharp warren I created a Cooldown input condition for my game and pushed a PR with it if it might be wanted by others, really appreciate the library so wanted to contribute back ❀️

sharp warren
thick kiln
#

To set manually the Axis2D value, I would have to use mocking?
Also the triggers seem to be triggered on the Context entity, but in the pull-mode (looking at the components directly; I would have to pull from components on the Action entity)? I think i need to use pull-mode because i'm handling 2 Actions in the same system

heady mauve
#

@sharp warren I've got a Binding for AnyKey/Button/Whatever we decide to call it working with an example of assigning gamepads. But it currently has to be the last action because I haven't figured out a good way to do consumption. Do you want me to put a Draft PR together so you and possibly Alice can look it over and provide feedback?

sharp warren
sharp warren
#

Like "Press any key to continue" should trigger first and then user should remove the context/action.

thick kiln
#

Would it be a good idea to insert automatically the Context component on the parent, if we spawn ActionOf<Context>? Or is that something that's already done?

sharp warren
#

Not done currently. But as for my taste it's too implicit.

thick kiln
#

but would there be a situation where that's incorrect? or should the context component always be present?
To switch contexts we don't remove/re-add the component, right?

sharp warren
thick kiln
#

Ok thanks; i'll add the Context component on the ActionOf parent automatically then; it would be easier for me to have that when ActionOf is replicated

#

ah actually I might not be able to, since Context doesn't necessarily implement default

sharp warren
# thick kiln Ok thanks; i'll add the Context component on the ActionOf parent automatically t...

But why do something like this? πŸ€”
When replicate the context entity, I'd expect the context to be a required component for some other gameplay component (i.e. it will be inserted automatically on replication) or replicated with the entity. And actions just deterministically spawned for it, like a scene, you just need to map them properly. Or are you trying a different strategy?

thick kiln
sharp warren
alpine socket
# sharp warren Create 2 actions: for the stick and for the button. Then attach chord modifier t...

I've gone through several iterations of this and still can't get it to require the chord.

let right_mouse = context.spawn((
    Action::<Chord1Action>::new(),
    bindings![MouseButton::Right]
)).id();

context.spawn((
    Action::<CameraMoveAction>::new(),
    Chord::single(right_mouse),
    bindings![Binding::mouse_motion()]
));

This ends up firing with the mouse motion alone, without requiring the right click to be pressed. Am I misunderstanding how the chord is supposed to work?

The only version I've seen in the docs is one with 2 ids in the chord without any bindings.

#

This version also does not work, but results in no mouse motion at all

let right_mouse = context.spawn((
    Action::<Chord2Action>::new(),
    bindings![MouseButton::Right]
)).id();

context.spawn((
    Action::<CameraMoveAction>::new(),
    Bindings::spawn((
        Spawn((
            Binding::mouse_motion(),
            Chord::single(right_mouse),
        )),
    )),
));
#

Wait, this may be because I had an additional different action bound to right click.

alpine socket
#

Yeah, that was it. I assumed that I could freely bind multple actions to the same input, but I assume they're getting consumed?

sharp warren
#

Yes, but you can disable the consumption

alpine socket
#

Ah, I see. In ActionSettings

#

ty

heady mauve
#

You could put the chord dependent action prior to the other ones. It would only be able to activate if the chord was active then.

sharp warren
#

You can also use logging to debug this kind of issues, see the troubleshooting section in the quick start guide

heady mauve
#

@sharp warren Thanks for the help getting that PR over the finish line.

sharp warren
sharp warren
#

Will wait for reviews from Alice for 2 last PRs and I'll draft a new release.

crude summit
#

If I remove input context from an entity, its triggers still get called.
Looks like a bug, v0.17.0

heady mauve
#

How are you removing the context?

crude summit
#
            commands
                .entity(entity)
                .remove::<Flying>();
heady mauve
#

I think it needs to be done a different way to fully remove the associated required components and related actions.

crude summit
#

I dont want to remove actions, I only want to temporarily disable context

heady mauve
#

If you just want to disable the context, look at ContextActivity

#

I think the context_switch example was updated to use it.

crude summit
#

Thanks, it works

#

Also in the docs
Inserting [`Self::INACTIVE`] is similar to removing the context.

#

Not similar, though

heady mauve
#

If you want, you could open a PR if you have a better, more understandable, way of wording it. As more people use BEI it becomes clearer where in the docs need work.

sharp warren
crude summit
crude summit
#

So if A requires B, which requires C. Then it wont remove C, right?

#

It works with context though, thanks

sharp warren
#

I think it would be better if Bevy used the same approach as with despawn

crude summit
#

Yeah

sharp warren
#

We no longer need to remember to call despawn_recursive.

sharp warren