valence-rs / valence

A Rust framework for building Minecraft servers.
http://valence.rs/
MIT License
2.77k stars 142 forks source link

Digging EventReader has incorrect state when block is instant mined #333

Open Wyatt-Stanke opened 1 year ago

Wyatt-Stanke commented 1 year ago

Valence Version

8897eeacb9104e404f91b529bc0488ef313aa694 (latest as of date of issue)

What You Did

I have code to listen for when a block is mined. It works fine for blocks take time to mine, but if a block instant mines (for example, wheat), the Stop event is not fired. This problem also happens in this example: https://github.com/valence-rs/valence/blob/main/crates/valence/examples/building.rs

Playground
use valence::client::despawn_disconnected_clients;
use valence::network::ConnectionMode;
use valence::prelude::*;

#[allow(unused_imports)]
use crate::extras::*;

const SPAWN_Y: i32 = 64;

pub fn build_app(app: &mut App) {
    app.insert_resource(NetworkSettings {
        connection_mode: ConnectionMode::Offline,
        ..Default::default()
    })
    .add_plugins(DefaultPlugins)
    .add_startup_system(setup)
    .add_system(init_clients)
    .add_system(listener)
    .add_system(despawn_disconnected_clients)
    .add_system(toggle_gamemode_on_sneak.in_schedule(EventLoopSchedule));
}

fn setup(
    mut commands: Commands,
    server: Res<Server>,
    biomes: Query<&Biome>,
    dimensions: Query<&DimensionType>,
) {
    let mut instance = Instance::new(ident!("overworld"), &dimensions, &biomes, &server);

    for z in -5..5 {
        for x in -5..5 {
            instance.insert_chunk([x, z], Chunk::default());
        }
    }

    for z in -25..25 {
        for x in -25..25 {
            // Insta-break block
            instance.set_block([x, SPAWN_Y, z], BlockState::TNT);
        }
    }

    commands.spawn(instance);
}

fn init_clients(
    mut clients: Query<(&mut Location, &mut Position), Added<Client>>,
    instances: Query<Entity, With<Instance>>,
) {
    for (mut loc, mut pos) in &mut clients {
        loc.0 = instances.single();
        pos.set([0.5, SPAWN_Y as f64 + 1.0, 0.5]);
    }
}

fn listener(mut instances: Query<&mut Instance>, mut events: EventReader<Digging>) {
    let mut instance = instances.single_mut();

    for event in events.iter() {
        if event.state == DiggingState::Stop {
            instance.set_block(event.position, BlockState::AIR);
        }
    }
}

What Went Wrong

I expected for when a block is insta-broken for it to fire an event with the state DiggingState::Stop.

Additional Information

The reason why this is happening is because the DiggingState::Stop event is not firing. https://github.com/valence-rs/valence/blob/main/crates/valence/examples/building.rs has this bug. A quick workaround I used is to check if the block is an insta-breakable block or the event state is DiggingState::Stop Screen recording: https://github.com/valence-rs/valence/assets/47758296/524e9b88-a039-488a-8956-406b417b9641

rj00a commented 1 year ago

This is actually a bug in the Minecraft client and is out of our control unfortunately. I would leave a link to the issue in the Minecraft bug tracker here, but I can't find it right now.

We can leave this issue open until it's fixed by Mojang.

Wyatt-Stanke commented 1 year ago

Related: https://github.com/PrismarineJS/mineflayer/issues/2208