#bevy_enhanced_input

1 messages ยท Page 4 of 1

crude summit
#

I also found much more compact way to write debug/technical input

type Kbd<'w> = Res<'w, ButtonInput<KeyCode>>;
type Mouse<'w> = Res<'w, ButtonInput<MouseButton>>;
// ...
        .add_systems(Update, (
            grab_cursor.run_if(|k: Mouse| k.just_pressed(MouseButton::Left)),
            release_cursor.run_if(|k: Kbd| k.just_pressed(KeyCode::Escape)),
            toggle_free_camera.run_if(|k: Kbd| k.just_pressed(KeyCode::KeyC)),
        ))

Maybe it would be worth adding to BEI some short syntax for such case?

sharp warren
crude summit
thick kiln
neat bloom
#

hi. im switching our game over from leafwing to bevy enhanced input. we have a situation where we need to see if the Alt key is pressed while a Move Action is happening. i already implemented the Move action with wasd and gamepad and its working. now i need to change the behavior depending on if the Alt key is pressed. i looked through the examples and didnt see how to get more than 1 target in an observer function...

neat bloom
#

guessing i shouold use a bevy state and set that with an observer function

sharp warren
sharp warren
static hearth
#

While updating from before the component refactor to 0.17.1, I ran into the same issue. Is there a workaround?
Before the refactor I used SwizzleAxis (SwizzleAxis also can't be attached) and Negate to bind the 3d translation of a spacecraft to a single Action like this:

actions.bind::<Translate>().to((
  Cardinal::wasd_keys().with_modifiers_each((
    SwizzleAxis::XZY,
      Negate {
        x: true,
        y: false,
        z: true,
      },
    )),
    Bidirectional {
      positive: KeyCode::Space,
      negative: KeyCode::ShiftLeft,
    }.with_modifiers_each(SwizzleAxis::ZXY),
));

These are my bindings now:

    actions!(
        ShipControl[(
            Action::<Translate>::new(),
            Bindings::spawn((
                Cardinal::wasd_keys().with((
                        SwizzleAxis::XZY,
                        Negate {
                            x: true,
                            y: false,
                            z: true,
                        }
                    )),
                Bidirectional::<Binding, Binding> {
                    positive: KeyCode::Space.into(),
                    negative: KeyCode::ShiftLeft.into()
                }
                .with(SwizzleAxis::ZXY)
            )),
        )]
    )
#

It crashes when SwizzleAxis and Negate aren't commented out for the Cardinal binding

sharp warren
#

Or don't use Cardinal

#

And you can also create your own preset tied to what you expect.

static hearth
#

I'll create a my own preset

sharp warren
neat bloom
sharp warren
outer wyvern
#

@sharp warren I've done a review pass on all open PRs now ๐Ÿ™‚

#

A couple are blocked / waiting on author, but I've kicked off a merge for the others

sharp warren
#

Thanks!

limpid lake
#

@sharp warren maybe for the โ€˜remove_with_requiresโ€™ issue, it can be solved with a macro like โ€˜remove_context!โ€™ That will do it without any footguns?

#

At least for now so it will be more user friendly

sharp warren
limpid lake
#

Yeah fair haha

sharp warren
#

@limpid lake @thick kiln @heady mauve drafted a new release with the features you requested/submitted.

zinc cliff
#

Is there an example for how to use non-observer based actions?

#

migrating from 0.14 rn and struggling a bit

#

o, nvm just above same question

#

Does each action have its own entity? curious how this is actually implemented because it feels a bit like magic to me right now:
(Action::<EquipItem>::new(), EquipHotbarIndex(0), bindings![KeyCode::Digit1]),

sharp warren
#

I highly suggest reading the quick start guide in the docs first, it's all explained.

#

Feel free to ask if something is unclear. I constantly try to improve docs and examples.

zinc cliff
#

Is there any event/trigger on a context becoming active/inactive or is it always necessary for a ContextActivity to be inserted to trigger the change, never modified? I see it's immutable so insert only

#

Trying to re-implement this:

pub fn started_flying(
    trigger: Trigger<OnInsert, ContextActivity<FlyingCamera>>,
    mut query: Query<(&Transform, &ContextActivity<FlyingCamera>, &mut FlyingState)>,
) {
    let Ok((transform, context_activity, mut state)) = query.get_mut(trigger.target()) else {
        return;
    };

    if *context_activity == ContextActivity::<FlyingCamera>::INACTIVE {
        return;
    }

    let (yaw, pitch, _roll) = transform.rotation.to_euler(EulerRot::YXZ);
    state.yaw = yaw;
    state.pitch = pitch;
}

but I'm not entirely sure if I can do this with a check either?

#

oh I'm dumb there is a deref to bool

sharp warren
#

Events won't fire for inactive contexts.

zinc cliff
sharp warren
#

Ah, I see

zinc cliff
#

in this case I want the flying camera to start with the same position and orientation as the previous camera

round portal
#

I thought priority means that if action is not defined in higher priority then it searches for the binding in the lower priority contexts, is that not the case?

sharp warren
round portal
#

so if I have defined Action Forward with KeyW binding on context with priority 0 but not on another with priority 1 when context with priority 1 is active it means that on KeyW no Forward action will be fired?

heady mauve
round portal
heady mauve
thick kiln
#

How does BEI behave for entities that don't have ActionMock or Bindings; would it still trigger the Events from ActionEvents?
(this is so that when I rollback and I predict future inputs, the push-based triggers still get emitted)

#

Maybe what I should do is just set an ActionMock on the remote-client Action entities with their last received State/Value; that way on rollback it acts as if the State/Value stay the same, and i get updated ActionTime and ActionEvent for free

thick kiln
thick kiln
#

It looks like I have to use ActionMock; because otherwise BEI::Update runs on Action entities even if they have no bindings and no mocks, and resets the State/Value to zero.

thick kiln
#

What would be the best way for me to block an Action from being updated in BEI::Update?
Adding a custom 'Filter' component to BEI? or some custom InputCondition?

sharp warren
thick kiln
#

i thought about that but right now it's easier if i can just exclude some actions from being updated (because of other reasons related to rollback)

#

besides it seems like it would be generally useful?

sharp warren
#

I ensured disabling works as expected, so it shouldn't break

#

Would that work for you?

thick kiln
#

I don't think that would work, because then my users would need to know about my custom Disabling component whenever they want to query the ActionState of remote players

sharp warren
#

But you previosly mentioned that you intercept actions, if you just run your logic after Update, wouldn't that work?

thick kiln
#

i guess; but why pay the cost of updating all these entities

#

also then i lose the previous state of ActionState, which I rely on for predicting future states

sharp warren
thick kiln
#

The issue is that I have action_predict function (that increments ActionTime/ActionEvents) that I call during rollbacks or when receiving a new InputMessage.
e.g. we had remote actions up to tick 8, current tick is 12 and we rollback to tick 4.
For ticks 4-8, we fetch the remote action from the buffer.
For ticks 8-12, we run action_predict to update ActionTime/ActionEvents.

You could say: why don't you just set the MockAction at tick 8 (during rollback) when you detect that you reached the end of the input buffer?
The reason is that I don't run BEI::Update at all during rollbacks because it's not needed and would hurt performance. I already have all the information for the inputs of all players, so I don't really want to have to call Update again

#

The other reason is that my API is shared between leafwing, lightyear_native, and BEI

#

so i cannot rely on some smart mocking API from BEI since it doesn't exist in leafwing

sharp warren
thick kiln
#

I still need the context to be active for the client-controlled entity

sharp warren
thick kiln
#

yes the context needs to be active; but I don't want the ActionState/ActionValue to be modified for the remote-client inputs. And I don't want to run BEI::Update during rollbacks for performance reasons.

#

but also don't you think that this kind of filter would be useful in general?

sharp warren
thick kiln
#

well right now you can disable an entire context, but you can't disable BEI from running for an individual Action

sharp warren
sharp warren
thick kiln
#

I disable all the Actions for remote players, not for the local player

sharp warren
#

So each player has its own context?

thick kiln
#

No the context is the same for all players. The context is called Move
But for prediction a client needs to be aware of the inputs/actions of other clients

sharp warren
thick kiln
#

ah, yes

#

ah i thought context-disabling was done for the type, but it's only for the entity, i see

sharp warren
#

Yeah

thick kiln
#

the issue is that I still want apply to run, so that triggers are emitted

sharp warren
thick kiln
#

sure, let me know

sharp warren
#

@thick kiln what if we adjust current mocking to allow expressing "Externally mocked"?
It's basically what you did, we just need to rename ExcludeFromUpdate into something like UserMocked ๐Ÿ˜…
Another option is to somehow adjust ActionMock. Like turn it into an enum. But I think an archetype filter would work better.

thick kiln
#

yes UserMocked works for me; basically it means that i am controlling how the ActionState/Events/Time/etc. get updated for that specific Action

sharp warren
zinc cliff
#

things I might suggest for docs: a mention to chords/modkeys for action bindings, and maybe of how to traverse backwards from the "target" of an action to an individual action

#

overall, fantastic work, ported over to 0.18 and it feels cleaner than ever ๐Ÿ™‚

sharp warren
thick kiln
#

Removing the Context entity doesn't unregister it? I have to specifically remove ContextPriority<C> ?

sharp warren
vague temple
#

@sharp warren ah meme for your troubles

sharp warren
#

@thick kiln I'll draft a new patch release once Alice approves. It's weekends, so possibly on Monday ๐Ÿ™‚

#

Ah, the PR was merged because I enabled auto-merge and approved it. It's configured for one approval and CI pass ๐Ÿ˜ข

thick kiln
#

thanks!

thick kiln
sharp warren
# thick kiln Why is `despawn_related` required? Doesn't `linked_spawn` mean that if you despa...

No ๐Ÿ˜ข
I also found it weird, even opened this issue: https://github.com/bevyengine/bevy/issues/20252
Please, upvote if you agree ๐Ÿ™‚

GitHub

What problem does this solve or what need does it fill? The following code works: let mut world = World::new(); let mut entity = world.spawn(( Name::new("Root"), children![Name::new(&quot...

thick kiln
#

ah, but it still works if the parent entity is despawned though

sharp warren
#

Yes, despawn_related needed only if you remove the context.

#

I probably should clarify this in the docs

round portal
# heady mauve Are you adding the observers to entities directly, or do you have them as global...

global observers

my idea was that PlayerCtx is inserted for each player(I plan to add split screen), but before player model is spawned, you have to move through menu somehow.
Thats what ModalCtx is for. It also is for overriding some keys everytime a modal is spawned: pause, inventory, any other modal where you have to navigate, because navigating with gamepad stick right now it's not implemented and is one of the TODOs

p.s. sorry for delayed response, I'm having little time for project nowadays

sharp warren
round portal
#

ok I've finally figured it out - I override wasd on the second context as well ๐Ÿคฆโ€โ™‚๏ธ
This has been bugging me for weeks. Oh how good it feels to carve some time for the hobby project and see the progress.

Btw, I love how the new component approach gets rid of some crutch systems I had

sharp warren
sharp warren
#

@thick kiln the patch is up!

vague temple
#

can an action be considered started and completed in the same frame @sharp warren

#

Note - This is not me trying to do that

#

just trying to figure out where my state machien is clunka

vague temple
#

@sharp warren would you like a meme?

sharp warren
compact island
quasi epoch
#

how do i prevent errors from having spawning a bundle too large in the bind function?

#

@sharp warren

sharp warren
spice knot
#

is there a way to temporarily deactivate action contexts without deleting all the actions?

cursive gorge
#

Does entity disabling work? ๐Ÿค”

spice knot
#

lemme check

sharp warren
sharp warren
spice knot
#

thanks ARARthumbsup

spice knot
#

when I have the same action context on 3 different entities the action value only gets updated for one of them when I press the corresponding button, is this a bug or expected behaviour?

sharp warren
native pendant
#

is it possible to have bevy_enhanced_input on a headless server? for Actions replication, but without the systems that read InputReader?

#
thread 'main' panicked at /home/hukasu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0.16.1/src/error/handler.rs:141:1:
Encountered an error in system `bevy_enhanced_input::context::input_reader::update_pending`: Parameter `InputReader::keys` failed validation: Resource does not exist
sharp warren
native pendant
#

0.18?

sharp warren
#

I linked it in the opened issue.

native pendant
#

nice

coarse brook
#

I have two contexts, letโ€™s call them Base and ObjectGrabbed, where ObjectGrabbed has a higher priority. Both of them have an action on left mouse click: Select for Base and PlaceObject for ObjectGrabbed. When the object is placed, the ObjectGrabbed context is cleaned up.

When left clicking and both contexts are active, PlaceObject is obviously called. For some reason the Base context still gets Select called when ObjectGrabbed is despawned, even though Select is configured to require reset.

Whatโ€™s the best way to block this? I want Select to only be triggered once the user has let go of the mouse button after placing the object.

heady mauve
coarse brook
#

Aaaah thank you! I had already set up require reset in other things where it worked, but I had it conceptually the other way around. Now that I added require reset to PlaceObject as well it works as expected. Phew, I thought I'd have to add a hacky workaround for now. ๐Ÿ˜„

vague temple
#

@sharp warren Should an input buffer be unreliable?

sharp warren
vague temple
#

yes

sharp warren
# vague temple yes

If you use Lightyear, it already handles the input for you. It should be handled in a bit special way.
But yeah, under the hood it's unrealiable.

vague temple
#

that mean packet losses can affect it?

sharp warren
# vague temple that mean packet losses can affect it?

Yes, but it's handled with the mentioned special way ๐Ÿ™‚
Check this video starting from this timestep if you need details: https://youtu.be/W3aieHjyNvw?feature=shared&t=1528

In this 2017 GDC session, Blizzard's Timothy Ford explains how Overwatch uses the Entity Component System (ECS) architecture to create a rich variety of layered gameplay.

Register for GDC: https://ubm.io/2yWXW38

Join the GDC mailing list: http://www.gdconf.com/subscribe

Follow GDC on Twitter: https://twitter.com/Official_GDC

GDC talks cover...

โ–ถ Play video
sharp warren
#

I believe that's what lightyear_inputs and rewind_input do.

vague temple
#

interesting this although avoids some issue can still scre my char controller

sharp warren
cursive gorge
# sharp warren I believe that's what `lightyear_inputs` and `rewind_input` do.

Yep, I just send things unreliable, but send a whole array of ticks, all of the ones that might still arrive in time on the server, and make sure the client is far enough ahead to handle at least 1 lost packet (though if inputs are very important this could be increased, or you might just want to go for reliable events in the cases where they need to definitely happen, even if not on the desired tick)

vague temple
#

That is my case

#

If a single tick is lost there is a slight chance a state may never be removed

alpine socket
quasi epoch
#

i'm making a 0.17 migration for bevy_enhanced_input, i've fixed almost everything but the one thing remaining is it tries to spawn things with various direction types or something? i'm not really sure what's going on, i tried searching the migration guides but couldn't find anything on it

error[E0185]: method `spawn` has a `self` declaration in the impl, but not in the trait
  --> src/preset/ordinal.rs:87:5
   |
87 |     fn spawn(self, world: &mut World, entity: Entity) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` used in impl
   |
   = note: `spawn` from trait: `fn(MovingPtr<'_, Self>, &mut bevy::prelude::World, bevy::prelude::Entity)`
error[E0599]: no method named `spawn` found for struct `cardinal::Cardinal<N, E, S, W>` in the current scope
   --> src/preset/ordinal.rs:94:18
    |
 94 |         cardinal.spawn(world, entity);
    |                  ^^^^^ this is an associated function, not a method
    |
   ::: src/preset/cardinal.rs:11:1
    |
 11 | pub struct Cardinal<N, E, S, W> {
    | ------------------------------- method `spawn` not found for this struct
    |
quasi epoch
#

@inner sky

sharp warren
#

Try writing this as this: MovingPtr<'_, Self>

quasi epoch
#

SpawnableList::spawn(move_as_ptr!(xy), world, entity);
this works

#

well, at least it doesn't throw an error

#

nvm

#

that macro doesn't exist

#

ugh these moving pointer things are confusing

sharp warren
#

On second thought, no ๐Ÿค”
The problem is that when we create a spawnable list, we need to convert it into MovingPtr.

sharp warren
sharp warren
inner sky
#

You should definitely not have to puzzle this out on your own ๐Ÿ™‚

shrewd wolf
#
    fn spawn(this: MovingPtr<'_, Self>, world: &mut World, entity: Entity) {
        let (n, ne, e, se, s, sw, w, nw) = unsafe {
            deconstruct_moving_ptr!(
                this => {
                    north,
                    north_east,
                    east,
                    south_east,
                    south,
                    south_west,
                    west,
                    north_west,
                }
            );
            (
                north, north_east, east, south_east, south, south_west, west, north_west,
            )
        };
        let cardinal = Cardinal {
            north: n.read(),
            east: e.read(),
            south: s.read(),
            west: w.read(),
        };
        move_as_ptr!(cardinal);
        SpawnableList::spawn(cardinal, world, entity);

        world.spawn((BindingOf(entity), ne.read(), SwizzleAxis::XXZ));
        world.spawn((BindingOf(entity), se.read(), SwizzleAxis::XXZ, Negate::y()));
        world.spawn((
            BindingOf(entity),
            sw.read(),
            SwizzleAxis::XXZ,
            Negate::all(),
        ));
        world.spawn((BindingOf(entity), nw.read(), SwizzleAxis::XXZ, Negate::x()));
    }
``` this might work? This is somewhat unergonomic though lol
sharp warren
sharp warren
#

I would expect to see only move_as_ptr!

shrewd wolf
#

because it's moving bundles within bundles

sharp warren
#

Ah, right, this is MovingPtr

shrewd wolf
#

there's definitely room for improvement here in terms of usability though..

sharp warren
shrewd wolf
#

yeah but it's a tough problem I think

analog fiber
#

Hi, Iโ€™m trying to set up an input action that only triggers when the middle mouse button is held down and the mouse is dragged (so MMB + motion)

#

I didnโ€™t see an example of this in the docs โ€” what would be the recommended way to implement it?

heady mauve
# analog fiber Hi, Iโ€™m trying to set up an input action that only triggers when the middle mous...

I would probably create an action when the middle mouse button is held and create a Chord condition that uses the held button action for the dragging. Create the held action first, then the action with the Chord condition and finally any other actions that use mouse motion afterwards to make sure they are prioritized correctly. Although if you use any mouse motions with keyboard modifiers you might have to make a separate context that you switch to instead.

analog fiber
#

Got it, thanks! But it does feel a lot more involved than what Iโ€™m used to with leafwing_input_manager though

analog fiber
heady mauve
#

Yeah, you are combining trying to create a Context and Actions in a Bundle with using command spawning to try and create the Context and different Actions.

heady mauve
analog fiber
#

it says: Bundle ... has duplicate components: bevy_enhanced_input::action::relationship::Actions<MainCamera>

#

So like, how do you mix actions! and SpawnWith together?

heady mauve
#

Did you look at the all_conditions example? It doesn't use the actions! macro.

analog fiber
heady mauve
#

Yeah, I'm not sure if Chords can be done in a Bundle since they have to hook into other Actions.

analog fiber
#

Weird, the result of MMB drag is: 2025-09-14T06:38:02.036267Z DEBUG Fired CameraOrbit with value [0, 0]

#

MMB drag gets triggered with zero values, but the R/F/Q/E keys work fine

#

๐Ÿค” Seems similar to an old leafwing_input_manager issue where chords with axial values were ignored

#

Or maybe I missed some docs, or is it actually intended to work this way?

sharp warren
#

If you want to get the value, you need to create only 2 actions and attach the chord condition to the action value of which you want to read.

#

For example:

  1. Mouse middle aciton
  2. Mouse move action, with a chord to the mouse middle action. You will get the mouse move action.
analog fiber
vague temple
#
/// Input context for player actions. This is here due to the fact player inputs are sometime used in other contexts
///
/// ## Actions
/// [`MoveInput`], [`RotateInput`], [`JumpInput`], [`DashInput`], [`Attack`],
/// [`NextWeapon`], [`PreviousWeapon`].
#[derive(Component, Serialize, Deserialize, Reflect, Clone, Debug, PartialEq)]
pub struct PlayerInputs;

impl PlayerInputs {
    /// NOTE DO NOT TOUCH THIS ORDERING OR YOU WILL FUCK UP DETERMINISM
    pub fn context_player() -> impl Bundle {
        (
            Self,
            actions!(Self[
                // MOVE INPUTS
                (
                    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]),
                // GUN INPUTS
                (Action::<Attack>::new(),bindings![MouseButton::Left]),
                (Action::<NextWeapon>::new(),bindings![KeyCode::KeyE]),
                (Action::<PreviousWeapon>::new(),bindings![KeyCode::KeyQ]),
                (Action::<Reload>::new(),bindings![KeyCode::KeyR]),
                (Action::<Interact>::new(),bindings![KeyCode::KeyT]),
                // BET INPUTS
                (Action::<IncreaseAmount>::new(),bindings![KeyCode::KeyH]),
                (Action::<DecreaseAmount>::new(),bindings![KeyCode::KeyN]),
                (Action::<IncreaseThreshold>::new(),bindings![KeyCode::KeyK]),
                (Action::<DecreaseThreshold>::new(),bindings![KeyCode::KeyL]),
            ]),
        )
    }
}```
#

Question how can i split the bundle (make sub bundles so i dont get too many components error) in this macro? I know this sounds weird but the moment I add a comma I get a weird duplicate components error

#

Is it by writing another actions?

analog fiber
#

When you also add another bundle with actions!(Self[..]), it inserts another Actions::<PlayerInputs>, so you get a duplicate

inner sky
#

But I don't remember the solution

sharp warren
#

Additionally

analog fiber
sharp warren
#

It's the same limitation.

#

You could do SpawnWith instead of using the actions! macro, but it will be ugly.

vague temple
inner sky
vague temple
#

i didnt know that was a thing

sharp warren
#

Same here, but with_related::<Actions<Self>>

#

I think it's solved on main

#

And it will just work after the update to Bevy 0.17.

vague temple
vague temple
sharp warren
vague temple
#

marvelous

analog fiber
# sharp warren I think you can attach `Down` condition ๐Ÿค”

๐Ÿค” Got a weird issue: I have MMB drag and RMB drag actions, but if I add Down to both, one action just never fires (for me CameraOrbit never works, doesnโ€™t matter which mouse button or order of spawning), even with Down(0). If I remove Down, they both work (though with 0 values).

let rmb_held = context
    .spawn((Action::<RmbHeld>::new(), bindings![MouseButton::Right]))
    .id();
context.spawn((
    Action::<CameraRotate>::new(),
    Bindings::spawn((
        Spawn((
            Binding::mouse_motion(),
            Down::new(0.0),
            Chord::single(rmb_held),
        )),
    )),
));

let mmb_held = context
    .spawn((Action::<MmbHeld>::new(), bindings![MouseButton::Middle]))
    .id();
context.spawn((
    Action::<CameraOrbit>::new(),
    Bindings::spawn((
        Spawn((
            Binding::mouse_motion(),
            Down::new(0.0),
            Chord::single(mmb_held),
        )),
    )),
));
sharp warren
#

On second though, consumption happens only when the action activates ๐Ÿค”

analog fiber
#

Really nice lib, but yeah itโ€™s pretty different from leafwing_input_manager

#

so in the migration Iโ€™ve been going back and forth between the docs and the few examples

#

Any plans to add more examples?

analog fiber
sharp warren
ionic sundial
#

What's the best way to deal with actions! macro having a limit of 12 actions in it? I have more than 12 actions to add. I guess, just don't use the macro?

inner sky
inner sky
sharp warren
sharp warren
#

And since we use related! inside actions! it should just work after 0.17 ๐Ÿ™‚

#

@quasi epoch how the migration to 0.17 is going? Maybe you could open a draft with what you have?

inner sky
#

move_as_ptr! is broken upstream

#

sec

sharp warren
#

Oh, I didn't know ๐Ÿ˜ข

inner sky
sharp warren
inner sky
#

since I believe that's what the macro points to

inner sky
#

It is not!

#

opening an issue

#

this is too awesome to not mention

quasi epoch
#

maybe i did something wrong tho ill try again tomorrow

vague temple
inner sky
vague temple
sharp warren
quasi epoch
quasi epoch
#

@sharp warren opened

sharp warren
quasi epoch
#

@inner sky i've fixed almost everything, but i've just got this left

error[E0185]: method `spawn` has a `self` declaration in the impl, but not in the trait
  --> src/preset/axial.rs:44:5
   |
44 |     fn spawn(self, world: &mut World, entity: Entity) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` used in impl
   |
   = note: `spawn` from trait: `fn(MovingPtr<'_, Self>, &mut bevy::prelude::World, bevy::prelude::Entity)`
#

about 5 of those

#
impl<X: Bundle, Y: Bundle> SpawnableList<BindingOf> for Axial<X, Y> {
    fn spawn(self, world: &mut World, entity: Entity) {
        let xy = Axial {
            x: self.x,
            y: self.y,
        }
        .with(SwizzleAxis::YXZ);
        move_as_ptr!(xy);
        SpawnableList::spawn(xy, world, entity);
    }

    fn size_hint(&self) -> usize {
        2
    }
}```
inner sky
quasi epoch
#

just more errors

#

do you wanna see them?

inner sky
swift grail
quasi epoch
sharp warren
#

See this message: #1297361733886677036 message

ionic sundial
#

It's cool how BEI supports Disabled OOTB. No idea if the below is "best practice" but I realised I can just disable my actions when the game is paused.

The other option (which I was originally doing) was checking the state at the top of my observer function. Observers don't support run_if like systems (which I still think could be neat), so I made all of my action observer functions check they were in the right state (mostly just to make sure the game wasn't paused).

Once I realised Disabled works, I added support for DisabledOnEnter and EnabledOnExit to my game and I think I like this better.

// ...
commands.entity(book_player_entity).insert((
    TroopRosterPlayer,
    ContextPriority::<TroopRosterPlayer>::new(**book_player_context_priority + 1),
    actions!(TroopRosterPlayer[
        (
            Action::<PreviousRegimentAction>::new(),
            bindings![KeyCode::KeyW],
            DisabledOnEnter(CampaignPaused::Active),
            EnabledOnExit(CampaignPaused::Active),
        ),
        (
            Action::<NextRegimentAction>::new(),
            bindings![KeyCode::KeyS],
            DisabledOnEnter(CampaignPaused::Active),
            EnabledOnExit(CampaignPaused::Active),
        ),
    ]),
));
sharp warren
thick kiln
#

So using Disabled is equivalent to disabling the Context?

sharp warren
ionic sundial
#

@sharp warren @outer wyvern re https://github.com/simgine/bevy_enhanced_input/issues/194 (Depend on subcrates directly not bevy in actions! and bindings! macros), I discovered through a post on #engine-dev that it looks like an accepted solution in the Rust ecosystem here is to use a __private mod.

Both serde 1 2 and bitflags 3 do this.

I patched BEI locally and tested it:

  • With my game which uses bevy_* subcrates and I was successfully able to remove the unneeded bevy dep from my Cargo.tomls and my game was able to compile.
  • With the examples in BEI which use bevy, i.e., there's no regression.

Would you accept a PR?

#

The diff is tiny:

diff --git a/src/action/relationship.rs b/src/action/relationship.rs
index 97cd59b..6009dd9 100644
--- a/src/action/relationship.rs
+++ b/src/action/relationship.rs
@@ -166,6 +166,6 @@ pub type ActionSpawnerCommands<'w, C> = RelatedSpawnerCommands<'w, ActionOf<C>>;
 #[macro_export]
 macro_rules! actions {
     ($context:ty [$($action:expr),*$(,)?]) => {
-        ::bevy::prelude::related!($crate::prelude::Actions<$context>[$($action),*])
+        $crate::__private::related!($crate::prelude::Actions<$context>[$($action),*])
     };
 }
diff --git a/src/binding/relationship.rs b/src/binding/relationship.rs
index 696fb84..b8a5e24 100644
--- a/src/binding/relationship.rs
+++ b/src/binding/relationship.rs
@@ -96,7 +96,7 @@ pub type BindingSpawnerCommands<'w> = RelatedSpawnerCommands<'w, BindingOf>;
 #[macro_export]
 macro_rules! bindings {
     [$($binding:expr),*$(,)?] => {
-        ::bevy::prelude::related!($crate::prelude::Bindings[$($crate::prelude::IntoBindingBundle::into_binding_bundle($binding)),*])
+        $crate::__private::related!($crate::prelude::Bindings[$($crate::prelude::IntoBindingBundle::into_binding_bundle($binding)),*])
     };
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index 41be7c7..f1fac64 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -435,6 +435,13 @@ pub mod prelude {
 
 use bevy::{input::InputSystem, prelude::*};
 
+// Private module for macro internals.
+#[doc(hidden)]
+pub mod __private {
+    pub use bevy::prelude::related;
+}
+
 use condition::fns::ConditionRegistry;
 use context::{
     ContextRegistry,
outer wyvern
brittle swallow
sharp warren
#

I mean, yeah, your game will be able to use bevy_*. But what the point if the crates you use depend on bevy?

brittle swallow
#

Hm, shouldnโ€™t BEI move to depending on subcrates anyway in anticipation of upstreaming?

sharp warren
brittle swallow
sharp warren
brittle swallow
#

Yes, but it wonโ€™t be in scope in the userโ€™s crate. So it wonโ€™t compile.

sharp warren
#

We could also just depend on bevy_*, but then it won't work for users who use bevy

brittle swallow
#

People who depend on subcrates may do it for a number reasons. For one, it makes it easier to keep the number of dependencies down. I assume BEI doesn't depend on bevy with default features, yes? If so, I don't see the point in preventing these subcrate users from using BEI. Wether some crate depends on bevy directly really doesn't matter.

sharp warren
#

I think Bevy should document this. I see people ask this a lot. There are disadvantages with both approaches.

  1. bevy - longer compile times because all third-party crates need to wait for all Bevy sub-dependencies to compile. And it pulls more, such as bevy_ecs, and bevy_math, while you might need only the ECS part.
  2. bevy_* - no mentioned problem with compile times. But users need to manually enable all necessary deps on bevy. So if a third-party plugin requires some stuff, you also need to manually enable it on bevy, otherwise it won't appear in prelude and DefaultPlugins, while being in your dependency tree. It also completely breaks patching, you need to patch every single bevy subcrate in your tree because of this.

I'd recommend a balanced approach:

  • Crates that can be used outside of Bevy and depend only on certain components should depend on bevy_*.
  • Crates that make sense only with Bevy should depend on bevy. I'd trade fresh compile times for patching, prelude and DefaultPlugins with depds that enabled automatically any time. Especially for games, where you pull all this stuff anyway.
brittle swallow
#

Well, really we should fix the... rather unpleasant plugin situation (crates should be able to register the plugins they depend on in an idempotent way). But yes, 2 can problematic now.

sharp warren
# brittle swallow Well, really we should fix the... rather unpleasant plugin situation (crates sho...

And develop tools for patching. It's very common to patch your game when you need a fix or some feature and don't want to wait for the next release.
Doing this manually is ugly: https://github.com/simgine/simgine/blob/4e9947b33cf95f915d9fc82eb6ac42e43a72aaee/Cargo.toml#L47

GitHub

A work-in-progress life simulation game. Contribute to simgine/simgine development by creating an account on GitHub.

ionic sundial
# sharp warren Yep, I pointed above that the mentioned workaround will result in using `bevy` a...

Yeah in this case Iโ€™m not thinking of reducing dependency compile times by talking about BEI not depending on bevy. That could just be a separate discussion to this maybe.

The discussion specifically this time for me is just โ€œhow can I make my game compile with OOTB BEI without forcing my game to depend on bevyโ€.

I know I can just stick a bevy dep in my crate to make it compile (and Iโ€™ll just continue to do that if I have to), but it would be nice if BEI (and bevy_asset_loader) worked out of the box for both these cases (and I believe the patch above does thisโ€”if there are other ways to get this to work as Corvus suggests Iโ€™m down with that too).

sharp warren
brittle swallow
#

Not having to do an extensive refactor is a pretty good benefit! That's part of what I was trying to get at.

#

(Moving to and from subcrates / bevy is very annoying in any nontrivial project.)

ionic sundial
#

Thereโ€™s also other non quantifiable benefits. Eg I have my game broken down into crates and I can clearly see the dependency tree those depend on. If I have a giga โ€˜bevyโ€™ dep in a crate does it depend on render? ECS? State? UI?

So subcrates isnโ€™t just about compile times itโ€™s about code architecture and cognition.

sharp warren
sharp warren
ionic sundial
#

Anyway my goal wasnโ€™t to raise this again, it was just to suggest a possible fix for my original issue. But if itโ€™s not desired I wonโ€™t create a PR with that patch.

sharp warren
#

Yeah, just wanted to express my thoughts on it for others ๐Ÿ™‚

slim field
#

just want to say that bevy_enhanced_input is really nice and imo a clear improvement over leafwing input manager so far

sharp warren
#

Thanks, I'm glad you like it ๐Ÿ™‚

inner sky
#

@sharp warren @quasi epoch I'm blocked by the BEI migration. If you both donโ€™t have anything against it, I'll try to finish the existing PR today

sharp warren
#

Just quite busy with work and Replicon right now ๐Ÿ™‚

quasi epoch
inner sky
#

@sharp warren may I rename EnhancedInputSet to the new official convention, i.e. EnhancedInputSystems?

inner sky
#

@sharp warren bevy::prelude::Press now clashes with bevy::prelude::Press

#

same for Release

#

Context: the Bevy types used to be called Pressed and Released

inner sky
#

And another thingy

#
#[derive(EntityEvent)]
pub struct Started<A: InputAction> {
    /// Entity that this event was triggered on.
    #[event_target]
    pub context: Entity,

    /// Action that triggered this event.
    pub action: Entity,

    /// Current action value.
    pub value: A::Output,

    /// Current action state.
    pub state: ActionState,
}
#

Started and friends now want to have their event target as a field

#

I called it context for now

#

but I could also just call it entity

sharp warren
# sharp warren Not again ๐Ÿ˜ข

I remember renaming it to avoid collision with picking, but it's renamed again ๐Ÿ˜ข
Probably we need to rename them into JustPressed and JustReleased...

inner sky
#

we just migrated away from .target

#

on Bevy itself

#

So this feels very 0.16 to me

#

Bevy itself advocates .entity where possible

#

I only picked .context because there are two entities here

sharp warren
sharp warren
inner sky
#

But yeah I know, it's usually .id() in Bevy APIs ๐Ÿ˜„

sharp warren
inner sky
sharp warren
#

Ah, got it.

#

I'd advocate for this.
I.e.:

#[derive(EntityEvent)]
struct Explode {
    player: Entity
}
inner sky
#

yeah makes sense ๐Ÿ™‚

sharp warren
#

I.e. when it makes sense. When it could be anything, I usually go with just entity, yeah

inner sky
#

Also, you're nudged to no longer use generic trigger names

#

e.g. instead of trigger: Trigger<OnAdd, Foo> it's add: On<Add, Foo>

#

I'm also doing that in our examples

sharp warren
#

Reads better

inner sky
#

I have one issue with .context

#

Looking at the examples, it comes up a lot

#

and the Bevy API just uses .entity

#

so this may be a conflict for beginners

#

since they're used to .entity

sharp warren
#

Since we have 2 entities inside, I'm more inclined to context.

#

Having action and entity is a bit confusing.

sharp warren
inner sky
#

Alright, makes sense to me ๐Ÿ™‚

#

And JustPressed for Press

#

it's supposed to be present tense

sharp warren
#

Yeah, looks like we have to rename ๐Ÿ˜ข

inner sky
#

but I don't have a better suggestion

#

PressNow

#

meh

#

PressForRealForReal

sharp warren
#

๐Ÿ˜…

inner sky
#

StartPress I guess

#

no wait

#

that doesn't make sense

#

JustPress sounds awful

sharp warren
#

Tough choice

inner sky
#

Oh I probably should also rename Fired to Fire

#

@sharp warren is that fine?

#

DW I'm adding deprecated aliases everywhere

sharp warren
#

In Unreal it was actually Triggered. I went with Fired to avoid conflicts with Bevy Trigger ๐Ÿ˜…

inner sky
#

Also, for move: On<Fired<Move>> I need to call it move_ because move is a keyword and r#move is extremely ugly bavy_spin

inner sky
#

wait no, that clashes with the deprecated type export in Bevy

#

But 0.18 could have Trigger ๐Ÿ˜„

sharp warren
#

I think Fire is nicer. It's shorter ๐Ÿ™‚

sharp warren
inner sky
#

@outer wyvern opinion?

sharp warren
inner sky
#

(me included)

#

connection_messages: MessageReader<GamepadConnectionEvent>

#

Baaah I hate the Messages that are still called Event bavy

#

This is not a bug, Cart left it intentionally

#

But it reads awfully

#

I'll rename that part of the example to just use connections and connection instead of the confusing _event suffix

sharp warren
#

Yeah, I usually don't use suffixes like this

inner sky
#

In the vein of Fired -> Fire, can I also do Started -> Start?

#

And Canceled -> Cancel

#

Ooh and also Completed -> Complete

#

I sure hope those don't conflict too much with user types

sharp warren
#

Yep. Looks like Bevy now uses this naming convention.

sharp warren
#

I feel like users rarely name their structs in present-tense, so I think it's fine ๐Ÿ™‚

#

Unless they named their buttons like this ๐Ÿค”

inner sky
#

They also use Cancel

sharp warren
#

Oh no

inner sky
#

Oh no indeed bavy_spin

sharp warren
#

Let's continue with present tense. Yeah, there is a bit of a naming collision, but keeping Cancelled won't be that much better.

#

Maybe once upstreamed we implement picking events as BEI actions.

sharp warren
sharp warren
inner sky
#

Do you want me to keep those in our prelude?

inner sky
#

Also, it's just pushing the problem down the road given that we want to upstream BEI

sharp warren
inner sky
sharp warren
inner sky
#

Rust is smart enough about that

sharp warren
inner sky
#

I could also add it to the docs of the individual items though

#

sounds like a good idea ๐Ÿ™‚

sharp warren
inner sky
#

I also bumped the version of the macro crate even though there are no changes FYI

#

so that they stay in version lockstep

sharp warren
inner sky
#

hehe, hotbar is not looking so hot

#

oof something broke no_std

#

And a test fails locally hmm

#

@sharp warren any idea what may have caused this?

sharp warren
sharp warren
#

Maybe something changed related to time in Bevy?

#

Tap is timing-related

inner sky
inner sky
#

I'll chase the no_std thing for now

sharp warren
inner sky
#

mind running the ci again?

#

I think I'll open an issue upstream about the no_std thing

#

don't think that's something the migration introduces

sharp warren
inner sky
sharp warren
inner sky
#

People created throwaways and then just submitted PRs automatically everywhere

sharp warren
#

Yeah, I remember ๐Ÿ˜…
I guess you can't farm much if you open PR's only to the repositories you contributed

inner sky
#

@sharp warren is it intentional that we always depend on serialize?

#

That seems wrong

sharp warren
#

Yeah, worth fixing.

inner sky
#

I think the serialize feature unintentionally always activates bevy_render

sharp warren
#

See, my laziness helped us ๐Ÿ˜…

sharp warren
# inner sky

I think the same applies to transform ๐Ÿค”

#

And time

inner sky
sharp warren
#

Ah, okay

inner sky
#

Mind running the CI again?

#

If I did it right, only the failing test should remain

#

which honestly puzzles me a bit

sharp warren
inner sky
#

nvm found it

sharp warren
inner sky
#

spot the error ๐Ÿ˜„

#

Alright, migration done ๐Ÿ‘

#

@sharp warren I'm doing a quick break, but I can work through any issues you have with the migration when I'm back

#

In case you don't have any issues, I'll be migrating Foxtrot later

sharp warren
sharp warren
sharp warren
#

Looking into the PR right now

#

@inner sky what do you think about Move -> Movement?

inner sky
sharp warren
#

I also like the shortness ๐Ÿค”

sharp warren
sharp warren
inner sky
#

so I'll do it real quick

sharp warren
#

Okay, I'll rebase :)

#

I'll make a few tiny changes, such as Move -> Movement.

You did a really good job, this saved me a ton of time. I also like your taste in naming ๐Ÿ™‚

inner sky
sharp warren
sharp warren
inner sky
#

done

sharp warren
#

Pushed the changes. I think I'm ready to draft a new release if there are no suggestions about the changes.

#

I'm thinking about keeping it in a branch untill the release drops, so the latest master points to the latest Bevy release.

#

Otherwise users sometimes get confused.

outer wyvern
sharp warren
outer wyvern
sharp warren
#

Published

inner sky
round portal
inner sky
#

You don't have to rename Movement in your own code ๐Ÿ™‚

quasi epoch
inner sky
quasi epoch
#

what's the difference out of curiosity? why run the method multiple times?

sharp warren
quasi epoch
#

ah

outer wyvern
#

@sharp warren how are we feeling about upstreaming for the 0.18 cycle?

#

Are we stable enough?

sharp warren
outer wyvern
#

@here, as a non-representative users sample, how are you feeling about this?

daring latch
#

surprise ping

#

I don't even know the state of things

#

๐Ÿ˜”

elder shore
#

the 4th answer: idk

inner sky
glad hawk
#

very surprising but I think having to get a 3rd party solution for proper input handling does feel weird

daring latch
#

I thought there was a competing crate for input handling

tender cave
#

@summer patrol

valid harbor
#

If I had to reccomend bevy to someone, I would 100% tell them to handle inputs with a library and to use BEI specifically, so yes.

outer wyvern
#

So I'm inclined to push this forward

outer wyvern
valid harbor
daring latch
#

Oh, I didn't realize we weren't in that channel x)

outer wyvern
daring latch
#

then I know the state of things even less

cinder grail
inner sky
#

which happens very quickly in 3D

#

But that's more of a Bevy issue than a BEI issue tbh

slim field
#

i like BEI but it had a major api refactor very recently so it doesn't seem clear to me that it's fully baked yet

outer wyvern
cinder grail
#

I think that the biggest risk factor is that we may later come up with a better architecture, but there's no way to predict when, or even if, this might happen.

slim field
#

I'm also not super fond of the macro API but perhaps there are good reasons for it; I don't know what went into the design

outer wyvern
sharp warren
#

I really hoped for BSN for 0.17.
With bsn bindings would become a scene.

cinder grail
sharp warren
#

Until then, we either have to use a macro or functional API (spawn_related).

cinder grail
#

To quote Bruce Sterling, "When the world was given the gift of TCP/IP, all of a sudden a billion ideas became obvious."

brittle swallow
#

In terms of API stability, it seems like a bit of a slippery slope. Do we wait until BSN has stabilized so BEI can integrate it? But it'll be another API shift, so do we wait another cycle for it to settle? Or do we accept that it may need to change upstream and just pull the trigger.

cinder grail
sharp warren
brittle swallow
#

On the other hand, if the upstreaming calcifies the API, it does feel a little scary with BSN being imminent. I think BSN will have a profound impact on the shape of the ecosystem.

slim field
#

As an example of why I dislike the macro API, I had a bug the other day where this was crashing my game and it took me a while to figure out why

        commands.entity(entity).insert(actions![
            MyContext[(
                (
                    Action::<CancelAction>::new(),
                    ActionSettings {
                        require_reset: true,
                        ..default()
                    },
                    bindings![KeyCode::Escape, GamepadButton::East, MouseButton::Right]
                ),
                (
                    Action::<DoAction>::new(),
                    ActionSettings {
                        require_reset: true,
                        ..default()
                    },
                    bindings![KeyCode::KeyE, MouseButton::Left, GamepadButton::South]
                ),
            )]
        ]);
sharp warren
outer wyvern
# inner sky Do we?

Sometimes when writing complex generic or conditional code the macro approach fails

brittle swallow
#

Well, also like @sharp warren said, it's just a hierarchy of entities. You don't need BSN to express that. It's just nicer.

outer wyvern
#

And the macro also needs to generate something

inner sky
outer wyvern
#

Yeah, totally

inner sky
#

So I'm still using BSN, just not the macro

outer wyvern
#

I think it's fine to have bsn! be the standard definition

slim field
#

With all that said, maybe there is something to be said for done is better than perfect. BEI is far better than what is built into bevy today

brittle swallow
#

by a lot haha

cinder grail
# inner sky Do we?

We should probably discuss this elsewhere, but my assumption is that bsn will be a choice, just like everything else in Bevy is a choice - you don't have to use bsn, any more than you have to use bevy's renderer.

slim field
#

actually i change my vote, i'm pro upstreaming

sharp warren
slim field
#

and i will just say again that having contextual input that works out of the box without any fiddling is absolutely awesome. one thing i thought about the other day was that it might be interesting to have more sophisticated ways of layering and combining contexts. right now it's still manual enabling/disabling through ContextActivity which is a bit brittle if you have a lot of contexts, or multiple ways of combining them and entering/exiting them.

mossy plover
#

I got pinged.

#

What's happened?

sharp warren
sharp warren
mossy plover
#

Wonderful.

#

What features did BEI give?

#

(I know I was looking at it for some reason.)

slim field
#

In practice what I mean is that it would be nice to have a context stack or similar where I could simply pop off an input context without the subsystem that does the context popping necessarily having to know where it goes next. I suppose I could implement this myself as some sort of higher level abstraction for transitioning between contexts

sharp warren
sharp warren
vague temple
#

@sharp warren Do you think it ought to be possible to increase the dimensional field in enum in ActionValueDim to also consider rotations? My use case is pre-buffering a clients rotation, consuming it client-side and later on server doing the same aciton. I guessed it made sense to use inputs in that scenario.
https://docs.rs/bevy_enhanced_input/latest/bevy_enhanced_input/action/value/enum.ActionValueDim.html - Enum mentioned

#

Like an Axis4d

mossy plover
#

I'm not asking what features it has.

#

I just know there was some particular reason this was found helpful (over other options).

outer wyvern
outer wyvern
mossy plover
#

That may be why I'm here.

sharp warren
thick kiln
vague temple
thick kiln
#

On 0.17 i'm getting this:

thread 'Compute Task Pool (1)' panicked at src/action.rs:131:13:
output value should be axis 2D

when using

#[derive(Debug, InputAction)]
#[action_output(Vec2)]
pub struct Movement;

and

Bindings::spawn(Cardinal::wasd_keys()),
#

probably my fault, but do I have to change anything?

fallow ivy
#

Hi, I'm trying to use this crate but it doesn't seem to work, the observer are never triggered. Am I missing something?
Here's a small project for testing.

coarse brook
#

One mistake I often make is that I forget to add the context with add_input_context::<YourContextName>. I can't see any context adding in your plugin function. Overall, skimming through your code, I can't find any contexts at all, so you might want to revisit some of the examples to see how to set up a context for your input bindings.

outer wyvern
fallow ivy
sharp warren
# thick kiln probably my fault, but do I have to change anything?

This is weird. This panic comes from unreachable!. And I can't imagine how this could even reach here ๐Ÿค”
I saw a few people faced it, but we never managed to reproduce. The problem magically disappeared.
Could you try to provide me a minimal repro?
I think it's not 0.17-specific. We didn't change anything in this release.

sharp warren
inner sky
#

Maybe #[reflect(InputContext)]

sharp warren
#

Ah, wait, I think I might can...

#

No, never mind. I need static typing here.

#

I won't be able to create observer on a reflected type.

inner sky
sharp warren
#

It's okay, using inventory directly instead of the reflection is not that bad.

sharp warren
thick kiln
#

The easiest repro I have is to go on branch https://github.com/cBournhonesque/lightyear/tree/cb/confirmed-merge, examples/bevy_enhanced_inputs
And run

rm -rf SL && cargo run --no-default-features --features=server,netcode,udp -- server 2>&1 | tee SL
rm -rf CL1 && cargo run --no-default-features --features=client,netcode,gui,udp -- client -c 1 2>&1 | tee CL1
#

I did change some input-related networking stuff, so maybe it's on me

sharp warren
#

(will take a look tomorrow, going to sleep right now)

untold bridge
#

Hello, is there a way to trigger action on double click using BEI? I just cant find the right combination of conditions and events to make it work

sharp warren
untold bridge
#

thanks for response ๐Ÿ™‚ I will have a go at it

sharp warren
# untold bridge thanks for response ๐Ÿ™‚ I will have a go at it

In Unreal Engine they have a Combo modifier.
It's the only modifier I didn't port. But it's what could be used for double clicks.
It's marked as "beta" in Unreal and the idea behind is a bit weird: you specify the sequence of actions and you need to list all other actions that might cancel each step which is quite verbose.
I wanted something better, but didn't do it in the end.
if you have some ideas - feel free to experiement with it.

round portal
#

sooo, there is this migration guide tip:

// New
commands.add_observer(|explode: On<Explode>| {
    info!("{} exploded!", explode.entity);
    // you can also use `EntityEvent::event_target`, but we encourage
    // using direct field access when possible, for better documentation and clarity.
    info!("{} exploded!", explode.event_target());
});

but there is no field entity on bevy_enhanced_input. At least not on Start, I did not get to others yet

native pendant
round portal
#

yep

#

this works:

fn pause(on: On<Start<Pause>>, mut commands: Commands) {
    commands.trigger(TogglePause {
        entity: on.event_target(),
    });
}
#

I mean I'm fine calling event_target(), but it just kinda confusing to recommend using field in migration guide when its not always available

heady mauve
# round portal

Looks like it is using context as the event target since there is more than one entity for the event. This is mentioned in the news update for Bevy 0.17:

Deriving EntityEvent will set EntityEvent::event_target to a field named entity by default. In some cases (such as events that have multiple entity fields), it might make sense to use a more descriptive name.

round portal
#

Oh, right. this makes sense

sharp warren
#

We didn't went with entity because the event actually contains 2 entities: context and action.

round portal
#

I'm not against it, I was just a bit confused with the recommendation from guide use .entity field, your decision makes total sense!

sharp warren
#

Yeah, I definitely see how the guide might be confusing

sharp warren
thick kiln
#

hm it doesn't seem to be that, it might be an entity mapping issue. Don't bother investigating, i'm pretty sure it's on me

sharp warren
# thick kiln hm it doesn't seem to be that, it might be an entity mapping issue. Don't bother...

I opened https://github.com/simgine/bevy_enhanced_input/pull/216
Maybe this will help with the investigation (or at least make it less painful).

GitHub

I used panic! because users couldn&#39;t trigger it. But since we split update and triggering for networking, it&#39;s now possible to cause this panic for advanced users. Since we can reco...

glad hawk
#

I think I had a similar error when I tried using cranelift

outer wyvern
# outer wyvern
poll_question_text

Should we upstream Bevy Enhanced Input?

victor_answer_votes

36

total_votes

40

victor_answer_id

1

victor_answer_text

Yes, in 0.18.

inner sky
thick kiln
thick kiln
minor dune
# outer wyvern

Hi I realise I'm a little late to the discussion here, but I just want to mention a couple of small pain points that I've had as a user of BEI:

  • There's no documentation on how to do pull-style queries when there are multiple context entities, e.g. in local multiplayer. All of the pull-style examples assume a single entity for each action. I found the solution is to query for the actions along with their ActionOf component, and then use that to get the context entity. However this leads to my next point:
  • There's no ergonomic way to query for multiple actions of a context in the same system. Because the relationship is one context to many actions, it's easy to go from an action to its related context, but not the other way around. Maybe there is a "find_related" bevy api that I am missing... It's worth noting that the observer API has a similar issue - you only get the value of one action at a time. I can see this being a common use-case, where you want to handle multiple inputs at the same time because they affect each other.
  • Input modifiers don't have any documented order in which they apply (when you have multiple on the same entity). I'm not sure if they actually support stacking? But in one case I needed to apply a deadzone and then a scale. I ended up making a custom modifier instead to achieve this.

Otherwise I think it's great and support it being upstreamed ๐Ÿ˜„

sharp warren
sharp warren
limpid lake
#

Canโ€™t wait to see this package upstreamed, the transition to components api is amazing and inspiring!

minor dune
neat bloom
#

hi. i was using Press with bevy 0.16 like this

(
                Action::<Alt>::new(),
                Press::new(1.0),
                bindings![KeyCode::ShiftLeft, GamepadButton::LeftTrigger],
            ),

but not now that bevy 0.17 uses press this is ambiguous. but i dont know where to import the BEI Press from

sharp warren
acoustic marsh
#

I'm trying to use the pulse condition for an automatic weapon fire action, but I don't want the player to be able to click rapidly and circumvent it. Is there a way to do this with the pulse condition or combination with cooldown or something?

kindred epoch
#

also a question from me. I am aware of Binding::mouse_motion() for Vec2s. is it possible to separate out the X and Y axis for mouse motion so that it's two separate events with f32's? .. oh maybe i can just SwizzleAxis it?

ok that works.

But now new problem. The Horizontal and Vertical Event only fires one Axis at a time. Is it possible to make the events fire at the same time?

outer wyvern
kindred epoch
#

i think it just makes logical sense if X axis controls one entity and Y axis controls another entity they should be two different events.

#

but yeah I guess I can work around this by having one Entity as the "driver" and get a reference to the other entity in the component or something.

sharp warren
sharp warren
sharp warren
kindred epoch
# sharp warren > The Horizontal and Vertical Event only fires one Axis at a time But wasn't thi...

I am not sure that's the implied goal in my mind.

The observed behaviour is that when I moved the mouse diagonally I would only see "Horizontal" or "Vertical" event fires, where the other is suppressed.

I was hoping for they both fire at the same time.

I got the two action, both f32, bound to two different entities independent of each other, so in my mind that's a valid thing to do and they should be able to act in parallel with each other

#

but maybe i am misunderstanding something. Also for reference can I have the same binding for different action?
as in if i bind LMB to "Jump" and "Atk" at the same time, and i press LMB, should both fire or just one fire?

heady mauve
kindred epoch
#

can u quickly remind me how to do that? I did a quick look and I don't really see how to do that from the quick examples.

#

oh it's an action setting, i will give that a shot, but this is most likely what i need, thanks!

heady mauve
kindred epoch
#

yep, that seems to be the missing puzzle piece, no longer limit it to just one axis

#

Appreciate it!

acoustic marsh
sharp warren
muted pewter
#

Is there a way to query which contexts are live in a system? Trying to come up with a clever way to combine bevy_enhanced_input with picking.

sharp warren
fallow ivy
#

Hi, what would be the best practice for entities that react to the same actions ?
Let's say I have multiple entities that should react to wasd, only one can react at a time based on which one is selected.

Currently I just remove every components related to the actions (ContextPriority, ContextActivity) from the last selected entity and add them to the currently selected entity.

But I feel like it a bit clunky and there's probably a better way to do it.

sharp warren
#

We definitely need a "patterns" section

fallow ivy
sharp warren
outer wyvern
outer wyvern
#

Alright, I think that's enough for today โค๏ธ

#

Let me know what y'all think, and what details I got wrong ๐Ÿ˜…

sharp warren
#

Thank you! I'll take a look today ๐Ÿ™‚

native pendant
#

how to get mouse motion only while hold a mouse button?

sharp warren
native pendant
#

how do i give preference for an action over another, because i need [MouseMotion, MouseButton::Left] and [MouseMotion, MouseButton::Left.with_mod(ModKeys::SHIFT)]

sharp warren
#

If you press Shift, it will execute the action with modifiers first.

native pendant
#

thanks

#

@sharp warren the ActionValue of the Chord is always zero, how do i transfer the values of the MouseMotion to the action of the Chord?

sharp warren
tame umbra
#

how are repeated key pressed handled?

tame umbra
#

The behavior I'm looking for is to trigger once when first pressed, wait x seconds, then start the pulse

#

maybe adding the same action twice, once for triggering right away, and once for pulsing after a certain amount of time? not sure if that would work or if it would just hold the action as active

native pendant
#

Fired has elapsed_seconds you could ignore the pulses that happen before n seconds

tame umbra
#

oh wickedge

native pendant
#

@sharp warren is there easy way to detect double clicks?

tame umbra
#

hmm I can't seem to make this work, holding shift should make ONGOING true?

#

but it stays false

#

oh wait i might be missing ActionState

native pendant
#

for actions like that it is Fired, not Ongoing

tame umbra
#

I do want ongoing

native pendant
#

i don't remember but ongoing only happens for a very few selection of modifiers

tame umbra
#

I want to be able to check if the button is being held down

#

instead of fired

native pendant
#

Fired is fired every frame

tame umbra
#

oh I need Hold

#

this gives the intended behavior

#

it seems to crash when I have duplicate key bindings

native pendant
#

what is the crash?

tame umbra
native pendant
#

i think you wrapped the bindings in one too many ()

tame umbra
#

oh wait

#

you are right

#

ty

native pendant
tame umbra
#

i just noticed

sharp warren
# native pendant <@243426730851696640> is there easy way to detect double clicks?

In Unreal Engine they have a Combo modifier for it.
It's the only modifier I didn't port. But it's what could be used for double clicks.
It's marked as "beta" in Unreal and the idea behind is a bit weird: you specify the sequence of actions and you need to list all other actions that might cancel each step which is quite verbose.
I wanted something better, but didn't do it in the end.
if you have some ideas - feel free to experiement with it.

native pendant
#

DoubleTap being Tap with 2 timers, the tap timer and the timer between taps

tame umbra
#

doubleclick is usually positional too right, where you have to click twice in the same spotish

sharp warren
tame umbra
#

Is there a way to bind to mousewheel up/down?

native pendant
#

Binding::mouse_wheel()

#

@sharp warren i need 2 actions on MouseButton::Right, one on Hold and one on Tap, but only one of them runs

sharp warren
tame umbra
#

PartRotate is a f32 action, how could I map "Q" into -1.0 and "E" into 1.0?

#

I'm looking and SwizzleAxis and it's really not clicking for me

tame umbra
#

tyty

tame umbra
#

feels a little janky though, optimally I would be able to attach it to bindings or actions

sharp warren
tame umbra
#

more like keyboard typing repeat, you press and it fires, you hold for 0.5s, then it starts firing every 0.05s

#

similar to holding down a key while typing

#

also mousewheel doesn't fire for me with this, but the keypresses work

sharp warren
tame umbra
#

ty that fixes it

tame umbra
tame umbra
#

actually its a bit different than i described, switching between rotate directions or left/right directions does reset time_elapsed, but switching Up -> Right -> Down -> Left does not

sharp warren
#

I lack context

#

But you can try looking at logs to see how the values are processed

tame umbra
sharp warren
tame umbra
#

Yeah I think I'm doing it in a jank way, I might look into the PR later but want to focus on the game for now

sharp warren
#

I.e. you can define custom modifiers in your crate and they can be based on default modifiers.

tame umbra
#

I looked into the input modifiers and didn't understand how I could detect direction changes like that

sharp warren
#

I.e. about adding a parameter to configure the initial delay.

tame umbra
#

I will look into it tomorrow maybe

sharp warren
#

You can just open an issue, I might take a look into this option myself later.

tame umbra
sharp warren
tame umbra
#

icic

thick kiln
#

For networking BEI i've been sending the ActionState/ActionValue of various Actions.
But that might actually be pretty expensive, since there could be a ton of different actions (that depend on various combinations of raw input key presses).
Maybe the easiest would be to just network the raw input key presses, and the compute the action on both the client and server based on those?
Note that this would not involve ActionMock, which would be used to set the values on the Action directly

sharp warren
native pendant
#

@sharp warren i have an action with Hold and an action with Tap on the same binding, both with consume_input: false, now the Tap is continuously firing on mouse movement

sharp warren
native pendant
sharp warren
native pendant
#

ShiftMouseRightAction is for the Chord of the CameraPitch

#

the tap should go to None and shouldn't reset to Ongoing right?

#

and that is only while there is mouse movement

sharp warren
#

I need to see your setup as well.

native pendant
#
#[derive(InputAction)]
#[action_output(Vec2)]
pub struct CameraPitch;

#[derive(InputAction)]
#[action_output(bool)]
pub struct ResetCameraPitch;

#[derive(InputAction)]
#[action_output(bool)]
struct ShiftMouseRightAction;

fn spawn_camera_pitch_action(commands: &mut Commands, camera: Entity) {
    let shift_mouse_right = commands
        .spawn((
            ChildOf(camera),
            ActionOf::<OrbitalCamera>::new(camera),
            Action::<ShiftMouseRightAction>::new(),
            ActionSettings {
                consume_input: false,
                ..Default::default()
            },
            Hold::new(0.25),
        ))
        .id();
    commands.spawn((
        ChildOf(shift_mouse_right),
        <BindingOf as Relationship>::from(shift_mouse_right),
        MouseButton::Right.with_mod_keys(ModKeys::SHIFT),
    ));

    let camera_pith = commands
        .spawn((
            ChildOf(camera),
            ActionOf::<OrbitalCamera>::new(camera),
            Action::<CameraPitch>::new(),
            Scale::splat(1. / 128.),
            Chord::new(vec![shift_mouse_right]),
        ))
        .id();
    commands.spawn((
        ChildOf(camera_pith),
        <BindingOf as Relationship>::from(camera_pith),
        Binding::mouse_motion().with_mod_keys(ModKeys::SHIFT),
    ));
}


fn spawn_reset_camera_pitch_action(commands: &mut Commands, camera: Entity) {
    let reset_camera_pitch = commands
        .spawn((
            ChildOf(camera),
            ActionOf::<OrbitalCamera>::new(camera),
            Action::<ResetCameraPitch>::new(),
            ActionSettings {
                consume_input: false,
                ..Default::default()
            },
            Tap::new(0.25),
        ))
        .id();
    commands.spawn((
        ChildOf(reset_camera_pitch),
        <BindingOf as Relationship>::from(reset_camera_pitch),
        MouseButton::Right.with_mod_keys(ModKeys::SHIFT),
    ));
}
sharp warren
native pendant
#

autism mostly, i want to have them as children of the their respective context (for actions)

#

i already thought up a way to deal with that though

#

i am being very exaggerated on how much i organize the hierarchy

sharp warren
native pendant
#

i like having them as children on the inspector

sharp warren
#

Ah, it doesn't provide a way to register custom relationship types? ๐Ÿ˜ข

native pendant
#

not that i know of

sharp warren
sharp warren
#

So if your mouse movement triggered, it swallows Shift

native pendant
#

The elapsed_secs on the ResetCameraPitch is continuous, it doesn't reset between each firing

sharp warren
# native pendant

Your log says that it reads true except when you release the button, in this case it reads false and the event fires.

#

When you hold the button, it's Ongoing.

native pendant
#

the 2 segments are not the entire log

#

i took just small segments to show that they go ONGOING -> ONGOING -> FIRED -> ONGOING -> ONGOING -> ONGOING -> FIRED

#

while holding mouse right and moving the mouse

native pendant
sharp warren
#

The log looks expected to me. When you start holding, it becomes Ongoing. When you release it in time - it's Fired.

native pendant
#

my hypothesis is that when the Hold gets fired, it goes to the Chord and consumes the Shift which causes the Hold and Tap to reset

native pendant
sharp warren
native pendant
#

i need to think of an architecture that works now, because i have also other actions that are a mirror to what i sent but without the Shift mod

sharp warren
#

The Shift modifier could be on either of them.

#

I.e. once

native pendant
#

without it being on both the action that gets triggered is the mirrored version without the mod

#

Right Hold + Mouse movement change camera yaw
Double Right Tap reset camera yaw
Shift Right Hold + Mouse movement change camera pitch
Shift Double Right Tap reset camera pitch

sharp warren
#

Actually, it doesn't matter, I think it should just work.

sharp warren
#

And assign a higher priority to the context with hold + movement.

tame umbra
#

duplicate bindings don't seem to work for me

#

Multiselect doesn't work

#

multiselect works

sharp warren
tame umbra
#

How could I prevent that?

#

additional ActionSettings component to the same entity?

#

yay that fixed it cool

tame umbra
#

I'm working on

#

the PR

#

and I managed to get it to work with something like this

#

this works for my rotation pulse, but for my movement pulse, because the action is constantly actuated, it never resets the held duration

#

I basically encounter the same problem I had earlier

#

I guess for my situation, i need the actuation state to "reset" whenever the value changes

#

i finished it

sharp warren
tame umbra
#

i answered there

weary maple
tame umbra
#

if let chaining my beloved ๐Ÿ˜

tame umbra
#

fixed my branch, although wasn't able to run the tests locally

sharp warren
# tame umbra if let chaining my beloved ๐Ÿ˜

Yeah, it's awesome!

Saw your changes, I'll take a proper look today after work. I think it's good for merging, but I need to update the changelog and maybe make a few stylistic changes.
Also looks like it's non-breaking, so I'll draft a new patch right after merge ๐Ÿ™‚

tame umbra
#

morning shatur

sharp warren
tame umbra
#

tests don't run bc of some dependency issue on my computer

sharp warren
# tame umbra

First time I see something like this ๐Ÿ˜…

But no problem, we can run CI.
A bit annoying that I have to confirm the run every time until I merge your first PR. I wish they add a button to autoconfirm for specific user.

tame umbra
#

yeah i'm unsure what that is

#

oh wait i did something silly

#

did a fix

tame umbra
#

last one hopefully

native pendant
sharp warren
#

Ah, and input consumption could be kept

native pendant
#

i actually got it to work putting the Tap with a higher priority

#

then when the tap goes to None it fallsback to the hold + movement

tame umbra
#

should be ready for merge

outer wyvern
#

I think we're getting close ๐Ÿ˜…

#

Thanks for iterating on it with my @sharp warren

outer wyvern
#

@sharp warren round 5 or whatever is ready ๐Ÿ˜„

sharp warren
compact island
#

@sharp warren
I stumbled upon:

press::Press::default(),

and I have a question: Is there any reasoning for mod condition to not reexport all conditions?
this would allow:

condition::Press::default(),
sharp warren
compact island
sharp warren
compact island
outer wyvern
#

I do like the new structure a lot too now

sharp warren
outer wyvern
#

Perfect ๐Ÿ˜„

#

I'll be doing another docs pass next week hopefully to prep for upstreaming, but this was the bulk of the improvements needed

#

The docs for each item are quite good: it was just trying to explain the big picture to a new user that was hard

tame moat
#

Can i make some inputs only work when in a certain state?

#

I need this on the input level bcs the inputs are networked through lightyear and if the client is in the menu i need them not move with wasd and such

#

for example if i want rotation only working if CursorState::Focused

sharp warren
mossy plover
#

Can someone help me figure out why my player_jump system isn't being triggered?

I was following the simple_fly_cam.rs example for reference, to make sure I wasn't missing anything, but I seem to have everything necessary, but it just won't run.

Here is the freestanding code:

// The player component
#[derive(Component, Default, Debug)]
pub struct Player;

// The input action which represents the player jumping.
#[derive(InputAction, Debug)]
    #[action_output(bool)]
pub(crate) struct PlayerJump;

// This system works as intended, so I can confirm the player exists and there is only one.
pub(crate) fn weigh_player_down(mut transform_q:Query<&mut Transform, With<Player>>) {
  let Ok(mut transform) = transform_q.single_mut() else { return; };
  
  transform.translation.y -= 4.5;
}

// Spawns in the player.
pub(crate) fn spawn_player(mut other_players_q:Query<Entity, With<Player>>, mut cmds:Commands) {
  for player in other_players_q.iter_mut() { cmds.entity(player).despawn(); }
  
  cmds.spawn((
    actions!(Player [
      Action::<PlayerJump>::new(),
      bindings![GamepadButton::East, MouseButton::Left, KeyCode::Space]
    ]),
    
    Player,
    /* ... */
  ));
}

// This system doesn't work for some reason.
pub(crate) fn player_jump(
      trigger:On<Fire<PlayerJump>>,
  mut transform_q:Query<&mut Transform, With<Player>>
) {
  let Ok(mut transform) = transform_q.get_mut(trigger.context) else { return; };
  
  transform.translation.y += 10.;
}

and here is the code that I use to register these things:

app.add_input_context::<Player>();
app.add_observer(player_jump);

Any pointers in the right direction would help, as I haven't used bevy_enhanced_input since version 0.11, which seemingly had a very different structure to how it does now.

mossy plover
tame moat
#

i solved it with the ContextActivity

mossy plover
#

I am not sure if this works for observers, but I am sure it is likely you reach your observer through a system at some point.

mossy plover
#

It seems to have to do with the actions! macro being kinda broken.

#

I had:

actions!(Player [
  Action::<PlayerJump>::new(),
  bindings![GamepadButton::East, MouseButton::Left, KeyCode::Space]
])

but needed:

actions!(Player [(
  Action::<PlayerJump>::new(),
  bindings![GamepadButton::East, MouseButton::Left, KeyCode::Space]
)])

and actions! didn't tell me that the type ov (whatever is generated by) bindings! was incorrect where it would expect an Action.

#

Who is the creator ov bevy_enhanced_input so I can ping them?

#

This seems like something they should know about.

outer wyvern
languid thorn
mossy plover
#

I can't log into GitHub right now.

#

My phone is broken and GitHub is requiring a code from my number. ๐Ÿ’€

outer wyvern
#

I really want to ship an entity inspector by default though

languid thorn
mossy plover
mossy plover
#

At least I read that in the documentation for the macro.

#

There is probably something else that could be done.

outer wyvern
outer wyvern
#

But it would probably be possible

mossy plover
#

Anything is possible with a turing-complete machine. ๐Ÿ‘

mossy plover
#

And can you programmatically trigger actions that are keybound?

outer wyvern
#

I'd need to look it up, but you basically just inject events in the same way that the keybinding layer does

sharp warren
mossy plover
#

What is BSN?

#

How will it help the situation in this regard?

#

(I.e. what is the current limitation that BSN eliminates?)

mossy plover
sharp warren
sharp warren
outer wyvern
#

Mostly by virtue of better syntax

sharp warren
#

Yeah, because right now it's easy to miss a brace.

mossy plover
#

It is.

#

It's a very small thing.

#

(Though, it's a parenthesis here.)

outer wyvern
mossy plover
sharp warren
mossy plover
sharp warren
mossy plover
#

Yes, please. That would be helpful.

atomic wasp
#

found a nice way to enable/disable mouse bindings while mouse is/isn't grabbed, could any problems arise from handling it like this?

fn on_grab_mouse(bindings: Query<(Entity, &Binding)>, (...)) {
    use Binding as B;
    for (id, binding) in bindings {
        if matches!( binding, B::MouseButton { .. } | B::MouseMotion { .. } | B::MouseWheel { .. }) {
            commands.entity(id)
                .insert((Disabled, DisabledByMouseGrab));
        }
    }
}

fn on_ungrab_mouse(
    bindings: Query<Entity, (With<Disabled>, With<DisabledByMouseGrab>)>,
    (...)
) {
    for id in bindings {
        commands.entity(id)
            .remove::<(Disabled, DisabledByMouseGrab)>();
    }
}
ornate bobcat
ornate bobcat
#

Sorry if this has been asked before (discord search sucks) but is there a typical way to re-use an existing actions logic for another action? Example: OpenInventory is a superset of PauseGame, so being able to say "this action runs this other actions logic first" or something could be helpful.

sharp warren
ornate bobcat
#

Perfect thanks gives me plenty to chew on ๐Ÿ™‚

outer wyvern
sharp warren
mossy plover
#

What is the 'proper' way to remove Actions, Bindings, et cetera, from an entity โ€“ such as when I want to disable the player's ability to move?

outer wyvern
mossy plover
#

I shouldn't remove them myself? (I don't plan on reenabling the controls.)

#

How do I add Disabled to them?

outer wyvern
outer wyvern
mossy plover
#

I want to disable the movement and then visually show the player dropping to the bottom ov the screen, so I have to keep them around.

outer wyvern
#

Those aren't actually components: you're creating a pseudo-hierarchy of entities

mossy plover
#

Or are they used globally for all similar action types for all entities?

outer wyvern
#

Since you need to store the state for each instance of the action seperately

mossy plover
#

Is it part ov base bevy rather than bevy_enhanced_input?

mossy plover
sharp warren
sharp warren
sharp warren
mossy plover
#

I'm not exactly sure how to remove the entities other than this method.

#

(Isn't this technically the same as what @outer wyvern suggested?)

sharp warren
#

Disabling an entity hides the entity from queries.

sharp warren
languid thorn
#

Does this plugin have a built-in way of responding to input outside of observers? With bevy-tnua you need to move the controller in FixedUpdate and you also need to know if an action is not being held. Is there a way to do this?

sharp warren
languid thorn
languid thorn
uneven axle
#

I am trying to get some observer based selection working that filters through bevy_enhanced_input to get contextpriority and such to sort it automatically but I'm struggling to figure out how to mock an input with a specific entity.

I have an observer(using bevy picking for that input) attached to my selectable entities on_click_unit that I want to fire an input for the entity that was selected. Ideally this would let me adapt to different input contexts/controls(controllers)/etc. I need the action event On<Fire<SelectUnit>> to have the entity for the original selected unit while currently it seems to be using the observer entity and I cant find a way to change that and manually provide the right entity.

pub fn on_click_unit_selection_controls(
    trigger: On<Fire<SelectUnit>>,
    actions: Single<&ContextActivity<SelectionControls>>,
    mut currently_selected_unit: ResMut<PlayerSelectedObject>,
) {
    let actions = actions.clone();
    if *actions != true {
        return;
    }
    println!("Unit selected");
    currently_selected_unit.select_unit(trigger.event().action);
}

//
pub fn on_click_unit(
    trigger: On<Pointer<Click>>,
    actions: Single<Entity, With<Action<SelectUnit>>>,
    mut commands: Commands,
) {
    println!("Unit selected");
    commands.entity(actions.entity()).insert(ActionMock::once(
        bevy_enhanced_input::action::ActionState::Fired,
        true,
    ));
}
sharp warren
uneven axle
sharp warren
uneven axle
sharp warren
uneven axle
sharp warren
uneven axle
#

Or the entity that the action is happening to. Eg the unit that is being clicked?

sharp warren
uneven axle
# sharp warren This ^ Because from the code it looks like you insert it on the context entity.

I might be misunderstanding but I don't believe I am. on_click_unit runs first and applied the ActionMock to the entity with Action<SelectUnit> on it. The other function runs afterwards and uses the entity in the trigger which I believe is the action entity. I think my issue is that I need that entity to either be the original one that was actually selected or be able to pass that entity somehow because RN it's the middle man I believe

sharp warren
#

On<Pointer<Click>> comes from picking and the associated entity is the entity with the mesh / collider. But it's also an action entity?

uneven axle
sharp warren
# uneven axle No they are separate entities. Im just saying I need the picking entity to be th...

I'm sorry, but truly don't understand you ๐Ÿ˜…
From the code you insert the mocking component on the wrong entity. You need to query for the action entity instead. Just query for the action you want to trigger using hierarchy traversal.
See the second example in the pull-style guide how to iterate over the hierarchy:
https://docs.rs/bevy_enhanced_input/latest/bevy_enhanced_input/#pull-style

uneven axle
# sharp warren I'm sorry, but truly don't understand you ๐Ÿ˜… From the code you insert the mocki...

Lol it's fine I think I'm confusing you or I'm really not tracking what you mean by action entity. I'm definitely inserting the MockAction onto the entity that has Action<SelectUnit> on it. It sends the action and the second observer listening to Fire<SelectUnit> activates. So I know it's all "working" from that perspective.

My issue is that I want the entity target from the original observer to be the one that is sent to the second observer and it's not. The path would ideally be (initial observer that activates through bevy_picking targeting itself -> sends that entity as the target of the action to bei -> second observer is able to send the actual game event SelectUnit with the right entity that bevy_picking started with. For some reason that second observer is reporting a different target entity and I'd like to force it to report the first entity as part of my action mock.

sharp warren
uneven axle
#

Rip. That would definitely be helpful because unless someone smarter than mes looked at it I'm not sure how possible/reasonable it is to use bevy picking with bei. It makes lots of stuff that seem tied to input very difficult. In my case selecting units and differentiating between whether that's a Selection vs a Move vs an Attack.

ornate bobcat
#

So I was able to mostly migrate to bei for mouse-based aim like this:

#[derive(InputAction)]
#[action_output(Vec2)]
pub(super) struct PlayerAim;

fn on_player_aim(
    player_aim: On<Fire<PlayerAim>>,
    player: Single<(&mut Player, &mut Vision, &Transform)>,
    mut window: Single<&mut Window, With<PrimaryWindow>>,
    camera: Single<(&Camera, &GlobalTransform)>,
) {
    let (mut player, mut player_vision, transform) = player.into_inner();

    let (camera, camera_transform) = *camera;

    let Ok(viewport_cursor_position) =
        camera.world_to_viewport(camera_transform, player.aim_position.extend(0.0))
    else {
        return;
    };

    player.aim_position += player_aim.value;
    window.set_cursor_position(Some(viewport_cursor_position));
}
...
// on player
(
  Action::<PlayerAim>::new(),
   Bindings::spawn((Spawn(Binding::mouse_motion()), Axial::right_stick())),
  Negate::y()
)

But I'm wondering if there is a better way because this seems both convoluted and also produces some weird results. Notably:

  1. negating y works for mouse but not for the right controller stick.
  2. Controller and mouse sensitives behave completely differently
  3. Mouse settings like DPI do not take affect at all (duh im overriding cursor pos)
  4. The Fire<MouseMotion> stops but the cursor continues to glide causing a discrepency between aim position and the on screen cursor location

Should I be doing something entirely different like hiding the cursor and using a custom sprite set to aim position?

uneven axle
ionic sundial
#

A helper like this could be useful to add to BEI:

fn cardinal_with_mod_keys(
    cardinal: Cardinal<Binding, Binding, Binding, Binding>,
    mod_keys: ModKeys,
) -> Cardinal<Binding, Binding, Binding, Binding> {
    Cardinal {
        north: cardinal.north.with_mod_keys(mod_keys),
        east: cardinal.east.with_mod_keys(mod_keys),
        south: cardinal.south.with_mod_keys(mod_keys),
        west: cardinal.west.with_mod_keys(mod_keys),
    }
}

Example:

Bindings::spawn(cardinal_with_mod_keys(Cardinal::arrows(), ModKeys::CONTROL))

Not sure if there's a more ergonomic design than this being a helper function.

I couldn't find another way to add mod keys to cardinals but maybe I missed it.

sharp warren
sharp warren
sharp warren
uneven axle
# sharp warren I'd probably just do vice versa - trigger picking from BEI.

That might be smarter but I'm not sure that would do what I want. I need bevy picking to drive the actual picking and unit selection for mouse/keyboard support first of all. Secondly I wanted to use BEI for the input/action sorting. EG have a context for CombatActions, MovementActions, BaseUnitActions, UnitAbilityActions, SelectionActions, etc. Send a single event and then let bei see if it should consume it as a combat event first then go down the line if not and check movement, selection, etc.

sharp warren
#

Ah, I see

proud coral
#

What is the appropiate way to have different observers for the same action in different contexts?

#

For context:

#

I have 3 contexts: ControllingProjectile, ControllingWorld and ControllingLauncher

#

And i have one action called "Cylce" whcih basically allows you to cycle through things.

#

ControllingProjectile: It should cycle skills
ControllingWorld: It should cycle rooms
ControllingLauncher: It should cycle the loaded projectile

heady mauve
proud coral
#

I guess I could query for the Entity with the input machine attached, and check whether it has the component that represents the context attached

proud coral
#

but idk, I thought this was enough of a common case that there would be a more streamlined solution for it

heady mauve
#

Are they all active at the same time?

proud coral
#

They're not usually but the can overlap yeah

#

so if they overlap the observers for all the ones that are active should trigger

heady mauve
#

Is there a reason you aren't using separate CycleProjectile, CycleWorld, CycleLauncher actions? They can be bound to the same binding and if they don't consume inputs then whatever combination are active will fire.

proud coral
#

Because to me it looks like if I have the same action for different contexts

#

it should be the same action ๐Ÿค”

#

if I have different actions for different contexts too

#

what is the point of contexts

#

I can have everything in the same context and just create different actions