Path: blob/main/crates/bevy_ecs/src/message/message_registry.rs
6849 views
use crate::{1change_detection::{DetectChangesMut, MutUntyped},2component::{ComponentId, Tick},3message::{Message, Messages},4resource::Resource,5world::World,6};7use alloc::vec::Vec;89#[doc(hidden)]10struct RegisteredMessage {11messages_component: ComponentId,12// Required to flush the secondary buffer and drop messages even if left unchanged.13previously_updated: bool,14// SAFETY: The message's component ID and the function must be used to fetch the Messages<T> resource15// of the same type initialized in `register_message`, or improper type casts will occur.16update: unsafe fn(MutUntyped),17}1819/// A registry of all of the [`Messages`] in the [`World`], used by [`message_update_system`](crate::message::message_update_system)20/// to update all of the messages.21#[derive(Resource, Default)]22pub struct MessageRegistry {23/// Should the messages be updated?24///25/// This field is generally automatically updated by the [`signal_message_update_system`](crate::message::signal_message_update_system).26pub should_update: ShouldUpdateMessages,27message_updates: Vec<RegisteredMessage>,28}2930/// Controls whether or not the messages in an [`MessageRegistry`] should be updated.31#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]32pub enum ShouldUpdateMessages {33/// Without any fixed timestep, messages should always be updated each frame.34#[default]35Always,36/// We need to wait until at least one pass of the fixed update schedules to update the messages.37Waiting,38/// At least one pass of the fixed update schedules has occurred, and the messages are ready to be updated.39Ready,40}4142impl MessageRegistry {43/// Registers a message type to be updated in a given [`World`]44///45/// If no instance of the [`MessageRegistry`] exists in the world, this will add one - otherwise it will use46/// the existing instance.47pub fn register_message<T: Message>(world: &mut World) {48// By initializing the resource here, we can be sure that it is present,49// and receive the correct, up-to-date `ComponentId` even if it was previously removed.50let component_id = world.init_resource::<Messages<T>>();51let mut registry = world.get_resource_or_init::<Self>();52registry.message_updates.push(RegisteredMessage {53messages_component: component_id,54previously_updated: false,55update: |ptr| {56// SAFETY: The resource was initialized with the type Messages<T>.57unsafe { ptr.with_type::<Messages<T>>() }58.bypass_change_detection()59.update();60},61});62}6364/// Updates all of the registered messages in the World.65pub fn run_updates(&mut self, world: &mut World, last_change_tick: Tick) {66for registered_message in &mut self.message_updates {67// Bypass the type ID -> Component ID lookup with the cached component ID.68if let Some(messages) =69world.get_resource_mut_by_id(registered_message.messages_component)70{71let has_changed = messages.has_changed_since(last_change_tick);72if registered_message.previously_updated || has_changed {73// SAFETY: The update function pointer is called with the resource74// fetched from the same component ID.75unsafe { (registered_message.update)(messages) };76// Always set to true if the messages have changed, otherwise disable running on the second invocation77// to wait for more changes.78registered_message.previously_updated =79has_changed || !registered_message.previously_updated;80}81}82}83}8485/// Removes a message from the world and its associated [`MessageRegistry`].86pub fn deregister_messages<T: Message>(world: &mut World) {87let component_id = world.init_resource::<Messages<T>>();88let mut registry = world.get_resource_or_init::<Self>();89registry90.message_updates91.retain(|e| e.messages_component != component_id);92world.remove_resource::<Messages<T>>();93}94}959697