game: fix latency of input events and repeated events

This commit is contained in:
SeanOMik 2024-12-17 21:42:35 -05:00
parent d4fc3000f1
commit e99153a53d
Signed by: SeanOMik
GPG key ID: FEC9E2FC15235964
10 changed files with 119 additions and 82 deletions
Cargo.lock
crates
examples/shadows/src

1
Cargo.lock generated
View file

@ -1837,6 +1837,7 @@ dependencies = [
"lyra-scene",
"petgraph",
"quote",
"rand",
"round_mult",
"rustc-hash 2.0.0",
"syn 2.0.77",

View file

@ -204,11 +204,11 @@ impl FnArgFetcher for Commands<'_, '_> {
CommandQueue::default()
}
fn apply_deferred<'a>(mut state: Self::State, mut world_ptr: NonNull<World>) {
fn apply_deferred<'a, 'state>(state: &'state mut Self::State, mut world_ptr: NonNull<World>) {
let world = unsafe { world_ptr.as_mut() };
let mut cmds = Commands::new(&mut state, world);
// safety: Commands has a mut borrow only to entities in the world
let mut cmds = Commands::new(state, world);
// SAFETY: Commands has a mut borrow only to entities in the world
let world = unsafe { world_ptr.as_mut() };
cmds.execute(world);
}

View file

@ -183,7 +183,7 @@ impl<Q: Query> FnArgFetcher for ViewOneState<'_, Q> {
ViewOneState::<Q>::new(world, Q::new())
}
fn apply_deferred(_: Self::State, _: NonNull<World>) { }
fn apply_deferred<'state>(_: &'state mut Self::State, _: NonNull<World>) { }
fn create_state(_: NonNull<World>) -> Self::State { () }
}

View file

@ -96,7 +96,7 @@ impl FnArgFetcher for WorldTick {
WorldTick(world.current_tick())
}
fn apply_deferred(_: Self::State, _: std::ptr::NonNull<World>) {
fn apply_deferred<'state>(_: &'state mut Self::State, _: std::ptr::NonNull<World>) {
}
}

View file

@ -29,7 +29,7 @@ pub trait FnArgFetcher {
unsafe fn get<'a, 'state>(state: &'state mut Self::State, world: NonNull<World>) -> Self::Arg<'a, 'state>;
/// Apply some action after the system was ran.
fn apply_deferred(state: Self::State, world: NonNull<World>);
fn apply_deferred<'state>(state: &'state mut Self::State, world: NonNull<World>);
}
/// A system that is implemented as a function.
@ -64,22 +64,32 @@ macro_rules! impl_fn_system_tuple {
fn execute(&mut self, world: NonNull<World>) -> anyhow::Result<()> {
unsafe {
paste! {
// initialize state if it hasn't been
if self.arg_state.is_none() {
self.arg_state = Some(vec![
$(
Box::new($name::create_state(world))
),+
]);
}
// safe unwrap since state was just initialized
let mut state_iter = self.arg_state.as_mut().unwrap().iter_mut();
$(
// get the arg fetcher, create its state, and get the arg
let mut [<state_ $name:lower>]: $name::State = $name::create_state(world);
let mut [<state_ $name:lower>]: &mut $name::State = state_iter.next()
// Safe since state vec is initialized to expected size
//.unwrap()
.expect("state was not initialized to correct size")
.downcast_mut()
// Safe due to the ordering of the arguments ensuring the correct
// types.
.unwrap_or_else(|| panic!("Failed to downcast state '{}' from 'Box<dyn Any>'",
std::any::type_name::<$name::State>()));
let [<$name:lower>] = $name::get(&mut [<state_ $name:lower>], world);
)+
(self.inner)($( [<$name:lower>] ),+)?;
let mut state = Vec::new();
$(
// type erase the now modified state, and store it
let boxed = Box::new([<state_ $name:lower>]) as Box<dyn Any>;
state.push(boxed);
)+
self.arg_state = Some(state);
}
Ok(())
@ -87,14 +97,16 @@ macro_rules! impl_fn_system_tuple {
}
fn execute_deferred(&mut self, world: NonNull<World>) -> anyhow::Result<()> {
let state = self.arg_state.as_mut().expect("Somehow there was no state");
state.reverse();
let mut state = self.arg_state.as_mut()
.expect("State was never initialized")
.iter_mut();
$(
let arg_state_box = state.pop()
.expect("Missing expected arg state");
let arg_state = *arg_state_box.downcast::<$name::State>()
.expect("Somehow the state cannot be downcasted from boxed Any");
let arg_state_box = state.next()
.expect("Invalid number of state was initialized");
let arg_state = arg_state_box.downcast_mut::<$name::State>()
.unwrap_or_else(|| panic!("Failed to downcast state '{}' from 'Box<dyn Any>'",
std::any::type_name::<$name::State>()));
$name::apply_deferred(arg_state, world);
)+
@ -160,7 +172,7 @@ where
v
}
fn apply_deferred(_: Self::State, _: NonNull<World>) { }
fn apply_deferred<'state>(_: &'state mut Self::State, _: NonNull<World>) { }
fn create_state(_: NonNull<World>) -> Self::State {
(Q::new(), F::new())
@ -179,7 +191,7 @@ impl FnArgFetcher for &'_ World {
&*world.as_ptr()
}
fn apply_deferred(_: Self::State, _: NonNull<World>) { }
fn apply_deferred<'state>(_: &'state mut Self::State, _: NonNull<World>) { }
fn create_state(_: NonNull<World>) -> Self::State { () }
}
@ -196,7 +208,7 @@ impl FnArgFetcher for &'_ mut World {
&mut *world.as_ptr()
}
fn apply_deferred(_: Self::State, _: NonNull<World>) { }
fn apply_deferred<'state>(_: &'state mut Self::State, _: NonNull<World>) { }
fn create_state(_: NonNull<World>) -> Self::State { () }
}
@ -220,7 +232,7 @@ impl<R: ResourceObject> FnArgFetcher for Res<'_, R> {
.unwrap_or_else(|| panic!("world is missing resource: {}", std::any::type_name::<R>()))
}
fn apply_deferred(_: Self::State, _: NonNull<World>) { }
fn apply_deferred<'state>(_: &'state mut Self::State, _: NonNull<World>) { }
fn create_state(_: NonNull<World>) -> Self::State { () }
}
@ -236,7 +248,7 @@ impl<R: ResourceObject> FnArgFetcher for ResMut<'_, R> {
.unwrap_or_else(|| panic!("world is missing resource: {}", std::any::type_name::<R>()))
}
fn apply_deferred(_: Self::State, _: NonNull<World>) { }
fn apply_deferred<'state>(_: &'state mut Self::State, _: NonNull<World>) { }
fn create_state(_: NonNull<World>) -> Self::State { () }
}

View file

@ -42,6 +42,7 @@ bind_match = "0.1.2"
round_mult = "0.1.3"
fast_poisson = { version = "1.0.0", features = ["single_precision"] }
atomic_refcell = "0.1.13"
rand = "0.8.5"
[features]
tracy = ["dep:tracing-tracy"]
tracy = ["dep:tracing-tracy"]

View file

@ -77,12 +77,17 @@ pub struct Events<T: Event> {
last_cleared_at: Tick,
/// Used to indicate when the cursor in readers should be reset to zero.
/// This becomes true after the old events are cleared.
reset_cursor: bool,
//reset_cursor: bool,
/// This is set to the amount of elements that were deleted.
///
/// Its used to decrease the cursor by the amount of elements deleted, instead of resetting
/// to zero to avoid rereading events that are in other levels of the vec.
decrease_cursor_by: Option<usize>,
}
impl<T: Event> Default for Events<T> {
fn default() -> Self {
Self { events: Default::default(), last_cleared_at: Default::default(), reset_cursor: false }
Self { events: Default::default(), last_cleared_at: Default::default(), decrease_cursor_by: None }
}
}
@ -96,37 +101,36 @@ impl<T: Event> Events<T> {
events.push(event);
}
pub fn reader(&self) -> EventReader<T> {
/* pub fn reader(&self) -> EventReader<T> {
EventReader {
events: self.events.clone(),
cursor: Arc::new(AtomicRefCell::new(0)),
//cursor: Arc::new(AtomicRefCell::new(0)),
cursor: Arc::new(AtomicUsize::new(0)),
}
}
} */
pub fn writer(&self) -> EventWriter<T> {
/* pub fn writer(&self) -> EventWriter<T> {
EventWriter {
events: self.events.clone(),
}
}
} */
}
pub struct EventReader<T: Event> {
pub struct EventReader<'state, T: Event> {
events: Arc<AtomicRefCell<WaterfallVec<T>>>,
cursor: Arc<AtomicRefCell<usize>>,
cursor: &'state mut usize,
}
impl<T: Event> EventReader<T> {
pub fn read(&self) -> Option<atomic_refcell::AtomicRef<T>> {
impl<'state, T: Event> EventReader<'state, T> {
pub fn read(&mut self) -> Option<T> {
let events = self.events.borrow();
let mut cursor = self.cursor.borrow_mut();
if *cursor >= events.total_len() {
if *self.cursor >= events.total_len() {
None
} else {
let e = atomic_refcell::AtomicRef::map(events,
|e| e.get(*cursor).unwrap());
*cursor += 1;
Some(e)
let e = events.get(*self.cursor).unwrap();
*self.cursor += 1;
Some(e.clone())
}
}
}
@ -152,12 +156,19 @@ where
if last_tick + 2 < world_tick {
events.last_cleared_at = *tick;
events.reset_cursor = true;
let mut events = events.events.borrow_mut();
events.clear_oldest();
let mut events_fall = events.events.borrow_mut();
// Since oldest will be cleared, we need to decrease the cursor by the removed amount
// store the amount it needs to decrease by.
let old_len = events_fall.old.len();
events_fall.clear_oldest();
drop(events_fall);
events.decrease_cursor_by = Some(old_len);
} else {
events.reset_cursor = false;
events.decrease_cursor_by = None;
}
let mut events = events.events.borrow_mut();
@ -166,34 +177,36 @@ where
Ok(())
}
impl<T: Event> FnArgFetcher for EventReader<T> {
type State = Arc<AtomicRefCell<usize>>;
impl<T: Event> FnArgFetcher for EventReader<'_, T> {
type State = usize;
type Arg<'a, 'state> = EventReader<T>;
type Arg<'b, 'state> = EventReader<'state, T>;
fn create_state(_: std::ptr::NonNull<lyra_ecs::World>) -> Self::State {
Arc::new(AtomicRefCell::new(0))
0
}
unsafe fn get<'a, 'state>(state: &'state mut Self::State, world: std::ptr::NonNull<lyra_ecs::World>) -> Self::Arg<'a, 'state> {
unsafe fn get<'b, 'state>(state: &'state mut Self::State, world: std::ptr::NonNull<lyra_ecs::World>) -> Self::Arg<'b, 'state> {
let world = world.as_ref();
let events = world.get_resource::<Events<T>>()
.unwrap_or_else(|| panic!("world missing Events<{}> resource", std::any::type_name::<T>()));
if events.reset_cursor {
let mut state_num = state.borrow_mut();
*state_num = 0;
if let Some(dec_by) = events.decrease_cursor_by {
// The waterfall vec had its oldest events deleted.
// The cursor needs to be decreased by the amount of elements deleted, instead of resetting
// to zero to avoid rereading events that are in other levels of the vec.
*state = state.checked_sub(dec_by).unwrap_or_default();
}
let reader = EventReader {
events: events.events.clone(),
cursor: state.clone(),
cursor: state,
};
reader
}
fn apply_deferred(_: Self::State, _: std::ptr::NonNull<lyra_ecs::World>) { }
fn apply_deferred<'state>(_: &'state mut Self::State, _: std::ptr::NonNull<lyra_ecs::World>) { }
}
impl<T: Event> FnArgFetcher for EventWriter<T> {
@ -209,8 +222,10 @@ impl<T: Event> FnArgFetcher for EventWriter<T> {
let world = world.as_ref();
let events = world.get_resource::<Events<T>>()
.unwrap_or_else(|| panic!("world missing Events<{}> resource", std::any::type_name::<T>()));
events.writer()
EventWriter {
events: events.events.clone(),
}
}
fn apply_deferred(_: Self::State, _: std::ptr::NonNull<lyra_ecs::World>) { }
fn apply_deferred<'state>(_: &'state mut Self::State, _: std::ptr::NonNull<lyra_ecs::World>) { }
}

View file

@ -493,7 +493,7 @@ impl ActionHandlerBuilder {
//fn actions_system(world: &mut World) -> anyhow::Result<()> {
fn actions_system(
input_btns: Res<InputButtons<KeyCode>>,
mouse_ev: EventReader<MouseMotion>,
mut mouse_ev: EventReader<MouseMotion>,
mut handler: ResMut<ActionHandler>,
) -> anyhow::Result<()> {
// clear the states of all axises each frame

View file

@ -1,5 +1,3 @@
use std::ops::Deref;
use glam::Vec2;
use lyra_ecs::query::ResMut;
use winit::{event::{MouseScrollDelta, WindowEvent}, keyboard::PhysicalKey};
@ -31,8 +29,8 @@ pub fn input_system(
mut key_code_res: ResMut<InputButtons<KeyCode>>,
mut mouse_btn_res: ResMut<InputButtons<MouseButton>>,
mut touches_res: ResMut<Touches>,
window_ev: EventReader<WindowEvent>,
device_ev: EventReader<DeviceEventPair>,
mut window_ev: EventReader<WindowEvent>,
mut device_ev: EventReader<DeviceEventPair>,
mut mouse_scroll_ev: EventWriter<MouseScroll>,
mouse_btn_ev: EventWriter<MouseButton>,
mouse_exact_ev: EventWriter<MouseExact>,
@ -41,7 +39,7 @@ pub fn input_system(
mouse_motion_ev: EventWriter<MouseMotion>,
) -> anyhow::Result<()> {
while let Some(event) = window_ev.read() {
match event.deref() {
match event {
WindowEvent::KeyboardInput { event, .. } => {
write_key_event(&mut key_code_res, event.physical_key, event.state);
},
@ -59,7 +57,7 @@ pub fn input_system(
mouse_left_ev.write(CursorLeftWindow);
},
WindowEvent::MouseWheel { delta, .. } => {
write_scroll_delta(&mut mouse_scroll_ev, delta);
write_scroll_delta(&mut mouse_scroll_ev, &delta);
},
WindowEvent::MouseInput { button, state, .. } => {
let button_event = match button {
@ -68,11 +66,11 @@ pub fn input_system(
winit::event::MouseButton::Middle => MouseButton::Middle,
winit::event::MouseButton::Back => MouseButton::Back,
winit::event::MouseButton::Forward => MouseButton::Forward,
winit::event::MouseButton::Other(v) => MouseButton::Other(*v),
winit::event::MouseButton::Other(v) => MouseButton::Other(v),
};
mouse_btn_ev.write(button_event);
mouse_btn_res.add_input_from_winit(button_event, *state);
mouse_btn_res.add_input_from_winit(button_event, state);
},
WindowEvent::Touch(t) => {
let touch = Touch {

View file

@ -1,6 +1,6 @@
use lyra_engine::{
assets::ResourceManager,
game::App,
game::{App, GameStages},
gltf::Gltf,
input::{
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
@ -12,9 +12,7 @@ use lyra_engine::{
light::{directional::DirectionalLight, SpotLight},
},
scene::{
CameraBundle, FreeFly3dCamera, FreeFlyCameraPlugin, WorldTransform, ACTLBL_LOOK_LEFT_RIGHT,
ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD,
ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN,
system_update_world_transforms, CameraBundle, FreeFly3dCamera, FreeFlyCameraPlugin, WorldTransform, ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN
},
};
@ -90,11 +88,17 @@ async fn main() {
};
let mut app = App::new();
app.with_plugin(lyra_engine::DefaultPlugins);
app.with_plugin(setup_scene_plugin);
app.with_plugin(action_handler_plugin);
//app.with_plugin(camera_debug_plugin)
app.with_plugin(FreeFlyCameraPlugin);
app.with_plugin(lyra_engine::DefaultPlugins)
.with_plugin(setup_scene_plugin)
.with_plugin(action_handler_plugin)
.add_system_to_stage(
GameStages::Last,
"update_world_transforms",
system_update_world_transforms,
&[],
)
//.with_plugin(camera_debug_plugin)
.with_plugin(FreeFlyCameraPlugin);
app.run();
}
@ -120,7 +124,7 @@ fn setup_scene_plugin(app: &mut App) {
.request::<Gltf>("../assets/shadows-platform-palmtree.glb")
.unwrap();
palm_tree_platform_gltf.wait_recurse_dependencies_load();
palm_tree_platform_gltf.wait_recurse_dependencies_load().unwrap();
let palm_tree_platform_mesh = &palm_tree_platform_gltf.data_ref().unwrap().scenes[0];
drop(resman);
@ -236,6 +240,12 @@ fn setup_scene_plugin(app: &mut App) {
));
}
/* world.spawn((
CameraBundle::default(),
Transform::from_xyz(0.0, 0.0, -5.5),
FreeFly3dCamera::default(),
)); */
let mut pos = Transform::from_xyz(-1.0, -10.0, -1.5);
pos.rotate_x(math::Angle::Degrees(-27.0));
pos.rotate_y(math::Angle::Degrees(-90.0));