Theme

alex/beta-minecraft-rust

Minecraft Beta 1.7.3 Rewrite

BRANCH main
main
SNAPSHOT Draw terrain GPU-driven from packed per-section buffers with GPU occlusion culling, add a render distance slider (2-128) with a quad/disk shape, cut chunk bookkeeping at high render distances, and fix a light underflow at y=0
DOWNLOAD
Download file

root / crates / client / src / app / warp.rs

use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
use wayland_client::backend::{Backend, InvalidId, ObjectId, WaylandError};
use wayland_client::globals::{GlobalError, GlobalListContents, registry_queue_init};
use wayland_client::protocol::wl_pointer::{self, WlPointer};
use wayland_client::protocol::wl_registry::{self, WlRegistry};
use wayland_client::protocol::wl_seat::{self, WlSeat};
use wayland_client::protocol::wl_surface::WlSurface;
use wayland_client::{
    Connection, Dispatch, DispatchError, EventQueue, Proxy, QueueHandle, WEnum, delegate_noop,
};
use wayland_protocols::wp::pointer_warp::v1::client::wp_pointer_warp_v1::WpPointerWarpV1;
use winit::window::Window;

#[derive(Debug, thiserror::Error)]
pub enum WarpError {
    #[error(transparent)]
    Handle(#[from] raw_window_handle::HandleError),
    #[error(transparent)]
    Global(#[from] GlobalError),
    #[error(transparent)]
    Id(#[from] InvalidId),
    #[error(transparent)]
    Dispatch(#[from] DispatchError),
    #[error(transparent)]
    Wayland(#[from] WaylandError),
}

/// Moves the pointer through `wp_pointer_warp_v1` on winit's Wayland connection, using a
/// dedicated `wl_pointer` to learn the enter serial winit keeps private.
pub struct PointerWarp {
    queue: EventQueue<State>,
    state: State,
    manager: WpPointerWarpV1,
    surface: WlSurface,
}

#[derive(Default)]
struct State {
    pointer: Option<WlPointer>,
    serial: Option<u32>,
}

impl PointerWarp {
    /// `None` when not on Wayland or the compositor lacks the protocol.
    pub fn new(window: &Window) -> Result<Option<Self>, WarpError> {
        let (RawDisplayHandle::Wayland(display), RawWindowHandle::Wayland(surface)) = (
            window.display_handle()?.as_raw(),
            window.window_handle()?.as_raw(),
        ) else {
            return Ok(None);
        };
        // Safety: winit keeps the display and surface alive for as long as the window
        let backend = unsafe { Backend::from_foreign_display(display.display.as_ptr().cast()) };
        let connection = Connection::from_backend(backend);
        let surface =
            unsafe { ObjectId::from_ptr(WlSurface::interface(), surface.surface.as_ptr().cast()) }?;
        let surface = WlSurface::from_id(&connection, surface)?;
        let (globals, mut queue) = registry_queue_init::<State>(&connection)?;
        let handle = queue.handle();
        let (Ok(manager), Ok(_)) = (
            globals.bind::<WpPointerWarpV1, _, _>(&handle, 1..=1, ()),
            globals.bind::<WlSeat, _, _>(&handle, 1..=5, ()),
        ) else {
            return Ok(None);
        };
        let mut state = State::default();
        queue.roundtrip(&mut state)?;
        Ok(Some(Self {
            queue,
            state,
            manager,
            surface,
        }))
    }

    /// Warps to a surface-local logical position; `false` while the pointer is outside.
    pub fn warp(&mut self, x: f64, y: f64) -> Result<bool, WarpError> {
        self.queue.dispatch_pending(&mut self.state)?;
        let (Some(pointer), Some(serial)) = (&self.state.pointer, self.state.serial) else {
            return Ok(false);
        };
        self.manager
            .warp_pointer(&self.surface, pointer, x, y, serial);
        self.queue.flush()?;
        Ok(true)
    }
}

impl Dispatch<WlRegistry, GlobalListContents> for State {
    fn event(
        _: &mut Self,
        _: &WlRegistry,
        _: wl_registry::Event,
        _: &GlobalListContents,
        _: &Connection,
        _: &QueueHandle<Self>,
    ) {
    }
}

impl Dispatch<WlSeat, ()> for State {
    fn event(
        state: &mut Self,
        seat: &WlSeat,
        event: wl_seat::Event,
        _: &(),
        _: &Connection,
        handle: &QueueHandle<Self>,
    ) {
        if let wl_seat::Event::Capabilities {
            capabilities: WEnum::Value(capabilities),
        } = event
            && capabilities.contains(wl_seat::Capability::Pointer)
            && state.pointer.is_none()
        {
            state.pointer = Some(seat.get_pointer(handle, ()));
        }
    }
}

impl Dispatch<WlPointer, ()> for State {
    fn event(
        state: &mut Self,
        _: &WlPointer,
        event: wl_pointer::Event,
        _: &(),
        _: &Connection,
        _: &QueueHandle<Self>,
    ) {
        match event {
            wl_pointer::Event::Enter { serial, .. } => state.serial = Some(serial),
            wl_pointer::Event::Leave { .. } => state.serial = None,
            _ => {}
        }
    }
}

delegate_noop!(State: ignore WpPointerWarpV1);