3

I've got a toy project that's using the Amethyst game engine. I'm trying to write my own System for collecting user input, similar to the FlyMovementSystem and ArcBallRotationSystem they have implemented here.

It appears the right way to go about collecting mouse movements is via an EventChannel<Event>, where Event comes from the winit crate, which Amethyst depends on, but does not re-export.

What's the "right" way to reference the same winit::Event that Amethyst does?

  • Should I add winit to my Cargo.toml file? If so, what is the recommended way to specify the version? (Is there some keyword I can use instead of a specific version number, to allow me to "inherit" the dependency from Amethyst?)
  • Is referencing sub-dependencies actually discouraged? If so, what should I be doing instead?
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Dylan
  • 13,645
  • 3
  • 40
  • 67

2 Answers2

6

There is currently no great solution to this problem. The best workaround is to add a direct dependency on the same version of the transitive dependency:

[dependencies]
foo = "0.1" 
bar = "0.2" # `foo` depends on bar 0.2 and we need to keep these in sync

You can use tools like cargo tree to manually identify the versions needed by foo and keep your Cargo.toml up to date. I highly recommend adding a comment specifying why you've picked a specific version.

If the crate is very difficult to use without also using the underlying dependency alongside it, I'd also encourage you to file an issue with the parent crate to request that they re-export what is needed. A good example of this is the Tokio crate, which re-exports large chunks of the futures crate.


Similar to your idea, I proposed having a way to use the same version as a dependency. Instead, the Cargo team opted to add the distinction of public and private dependencies. While this will be a better solution from an engineering point of view, very little progress has been made on the implementation of it.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    I dug a bit more, and it looks like in the case of Amethyst, its `InputSystem` is responsible for taking events from `winit` and translating them to Amethyst's own `InputEvent` type, which I was able to use without fiddling with my Cargo.toml. – Dylan Feb 18 '19 at 21:47
  • 1
    @Dylan I would encourage you to make an answer to that effect; even if it doesn't suit the general case, it may help other people who come across the same problem with Amethyst. – trent Feb 19 '19 at 14:23
1

I'm leaving @Shepmaster's answer as the accepted one, as it answers the general question I was going for. But thanks to a gentle push from @trentcl, in case anyone found this question specifically for its relation to Amethyst, here's what I ended up doing.

Don't try to get the winit::Events at all.

When you attach an InputBundle<AX, AC> to your GameData, it sets up an InputSystem<AX, AC>, which re-publishes winit::Events in the form of InputEvent<AC>.

It does this by setting up an EventChannel<InputEvent<AC>> as a Resource, which you can access via the Read type in the ECS system. EventChannels and their usage are explained in the Amethyst Book.

I've since switched to a different approach for handling my user input, but here's roughly what it looked like (note: Amethyst a little after v0.10.0):

pub struct MouseMovementSystem {
    reader: Option<ReaderId<InputEvent<()>>>, // AC = () 
}

impl<'s> System<'s> for MouseMovementSystem {
    type SystemData = (
        Read<'s, EventChannel<InputEvent<()>>>,
        /* and others */
    }

    fn run(&mut self, (events, /* and others */): Self::SystemData) {
        let foo = events.read(self.reader.as_mut().unwrap())
            .yadda_yadda(/* ... */); // event processing logic
        do_stuff(foo);
    }

    fn setup(&mut self, res: &mut Resources) {
        use amethyst::core::specs::prelude::SystemData;
        Self::SystemData::setup(res);
        self.reader = Some(res.fetch_mut::<EventChannel<InputEvent<()>>>().register_reader());
    }
}
Dylan
  • 13,645
  • 3
  • 40
  • 67