Merge pull request #183 from Schmarni-Dev/better_oxr_events

make OpenXR event handlers completely safe! (no unsafe!)
This commit is contained in:
Schmarni
2025-04-26 00:11:58 +02:00
committed by GitHub
3 changed files with 29 additions and 45 deletions

View File

@@ -7,7 +7,7 @@ use crate::{
next_chain::{OxrNextChainStructBase, OxrNextChainStructProvider},
openxr::exts::OxrEnabledExtensions,
openxr_session_available,
poll_events::{OxrEvent, OxrEventHandlerExt},
poll_events::{OxrEventHandlerExt, OxrEventIn},
session::{OxrSessionCreateNextChain, OxrSessionCreateNextProvider},
};
@@ -25,9 +25,8 @@ impl Plugin for OxrOverlayPlugin {
}
}
fn handle_overlay_event(event: In<OxrEvent>, mut writer: EventWriter<OxrOverlaySessionEvent>) {
// this unwrap will never panic since we are in a valid scope
if let Event::MainSessionVisibilityChangedEXTX(event) = unsafe { event.get() }.unwrap() {
fn handle_overlay_event(event: OxrEventIn, mut writer: EventWriter<OxrOverlaySessionEvent>) {
if let Event::MainSessionVisibilityChangedEXTX(event) = *event {
writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged {
visible: event.visible(),
flags: event.flags(),

View File

@@ -27,7 +27,7 @@ use crate::session::OxrSessionCreateNextChain;
use crate::types::*;
use super::exts::OxrEnabledExtensions;
use super::poll_events::OxrEvent;
use super::poll_events::OxrEventIn;
use super::poll_events::OxrEventHandlerExt;
pub fn session_started(started: Option<Res<OxrSessionStarted>>) -> bool {
@@ -297,14 +297,13 @@ impl OxrInitPlugin {
pub struct OxrInteractionProfileChanged;
pub fn handle_events(
event: In<OxrEvent>,
event: OxrEventIn,
mut status: ResMut<XrState>,
mut changed_event: EventWriter<XrStateChanged>,
mut interaction_profile_changed_event: EventWriter<OxrInteractionProfileChanged>,
) {
use openxr::Event::*;
// this unwrap will never panic since we are in a valid scope
match unsafe { event.get() }.unwrap() {
match *event {
SessionStateChanged(state) => {
use openxr::SessionState;

View File

@@ -1,5 +1,3 @@
use std::{cell::RefCell, mem, ops::Deref, rc::Rc};
use bevy::{ecs::system::SystemId, prelude::*};
use bevy_mod_xr::session::{XrFirst, XrHandleEvents};
use openxr::{Event, EventDataBuffer};
@@ -27,63 +25,51 @@ pub fn poll_events(world: &mut World) {
.poll_event(&mut buffer)
.expect("Failed to poll event")
{
let event = Rc::new(RefCell::new(Some(event)));
for handler in handlers.handlers.iter() {
if let Err(err) =
world.run_system_with_input::<_, ()>(*handler, OxrEvent::new(event.clone()))
for handler in handlers
.0
.iter()
.map(|v| SystemId::<OxrEventIn, ()>::from_entity(*v))
{
if let Err(err) = world.run_system_with_input(handler, event) {
error!("error when running oxr event handler: {err}");
};
}
event.deref().take();
}
world.insert_resource(handlers);
}
use super::{openxr_session_available, resources::OxrInstance};
#[derive(Resource, Debug, Default)]
pub struct OxrEventHandlers {
pub handlers: Vec<OxrEventHandler>,
}
pub type OxrEventHandler = SystemId<In<OxrEvent>, ()>;
pub struct OxrEvent {
event: Rc<RefCell<Option<Event<'static>>>>,
}
impl OxrEvent {
pub(crate) fn new(event: Rc<RefCell<Option<Event<'_>>>>) -> Self {
Self {
#[allow(clippy::missing_transmute_annotations)]
event: unsafe { mem::transmute(event) },
}
}
/// always returns [Some] if called in a valid scope
/// # Safety
/// The event is only valid for the duration of the poll event callback,
/// don't Store the [Event] anywhere!!
#[allow(clippy::needless_lifetimes)]
pub unsafe fn get<'a>(&'a self) -> Option<Event<'a>> {
*self.event.borrow()
}
}
pub struct OxrEventHandlers(Vec<Entity>);
pub trait OxrEventHandlerExt {
fn add_oxr_event_handler<M>(
&mut self,
system: impl IntoSystem<In<OxrEvent>, (), M> + 'static,
system: impl IntoSystem<OxrEventIn<'static>, (), M> + 'static,
) -> &mut Self;
}
impl OxrEventHandlerExt for App {
fn add_oxr_event_handler<M>(
&mut self,
system: impl IntoSystem<In<OxrEvent>, (), M> + 'static,
system: impl IntoSystem<OxrEventIn<'static>, (), M> + 'static,
) -> &mut Self {
self.init_resource::<OxrEventHandlers>();
let id = self.register_system(system);
self.world_mut()
.resource_mut::<OxrEventHandlers>()
.handlers
.push(id);
.0
.push(id.entity());
self
}
}
#[derive(Deref)]
pub struct OxrEventIn<'a>(pub Event<'a>);
impl SystemInput for OxrEventIn<'_> {
type Param<'i> = OxrEventIn<'i>;
type Inner<'i> = Event<'i>;
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
OxrEventIn(this)
}
}