diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index 04a7e6d74906e..47972a4fa46ee 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -2,7 +2,7 @@ use crate as bevy_ecs; use crate::system::{Local, Res, ResMut, Resource, SystemParam}; -use bevy_utils::tracing::trace; +use bevy_utils::tracing::{trace, warn}; use std::ops::{Deref, DerefMut}; use std::{ fmt::{self}, @@ -149,6 +149,14 @@ impl Default for Events { } } +impl Events { + pub fn oldest_event_count(&self) -> usize { + self.events_a + .start_event_count + .min(self.events_b.start_event_count) + } +} + #[derive(Debug)] struct EventSequence { events: Vec>, @@ -351,10 +359,18 @@ impl ManualEventReader { + ExactSizeIterator)> { // if the reader has seen some of the events in a buffer, find the proper index offset. // otherwise read all events in the buffer + let missed = self.missed_events(events); + if missed > 0 { + let plural = if missed == 1 { "event" } else { "events" }; + let type_name = std::any::type_name::(); + warn!("Missed {missed} `{type_name}` {plural}. Consider reading from the `EventReader` more often (generally the best solution) or calling Events::update() less frequently (normally this is called once per frame). This problem is most likely due to run criteria/fixed timesteps or consuming events conditionally. See the Events documentation for more information."); + } + let a_index = (self.last_event_count).saturating_sub(events.events_a.start_event_count); let b_index = (self.last_event_count).saturating_sub(events.events_b.start_event_count); let a = events.events_a.get(a_index..).unwrap_or_default(); let b = events.events_b.get(b_index..).unwrap_or_default(); + let unread_count = a.len() + b.len(); // Ensure `len` is implemented correctly debug_assert_eq!(unread_count, self.len(events)); @@ -379,6 +395,13 @@ impl ManualEventReader { .min(events.len()) } + /// Amount of events we missed. + pub fn missed_events(&self, events: &Events) -> usize { + events + .oldest_event_count() + .saturating_sub(self.last_event_count) + } + /// See [`EventReader::is_empty`] pub fn is_empty(&self, events: &Events) -> bool { self.len(events) == 0