Last active
August 7, 2022 15:27
-
-
Save zicklag/3446143d563657d54e292cc7e2c15378 to your computer and use it in GitHub Desktop.
Custom Command Queues in Bevy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use bevy::prelude::*; | |
use custom_commands::*; | |
struct MyPlugin; | |
// Create a marker type that represents our custom command queue | |
struct MyCmds; | |
impl Plugin for MyPlugin { | |
fn build(app: &mut App) { | |
app | |
// Initialize our custom command queue | |
.init_custom_commands::<MyCmds>() | |
.add_system(my_system) | |
.add_system_to_stage( | |
CoreStage::PostUpdate, | |
// Flush our custom command que at the beginning of PostUpdate | |
flush_custom_commands::<MyCmds> | |
.exclusive_system() | |
.at_start() | |
); | |
} | |
} | |
// Use our the CustomCommands for MyCmds instead of the default Bevy Commands | |
fn my_system(my_commands: CustomCommands<MyCmds>) { | |
// Get a `Commands` struct from our CustomCommands. This is the real Bevy Commands | |
// struct, not a fake copy. It works exactly the same, just writing to a different | |
// queue. | |
let commands = my_commands.commands(); | |
// At the start of PostUpdate, SomeComponent will be added to some_entity | |
commands.entity(some_entity).insert(SomeComponent); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::marker::PhantomData; | |
use bevy::{ | |
ecs::{ | |
entity::Entities, | |
system::{Command, CommandQueue, EntityCommands, SystemParam}, | |
}, | |
prelude::*, | |
}; | |
/// Resource containing the state transition command queue | |
pub struct CustomCommandQueue<Marker> { | |
queue: CommandQueue, | |
_phantom: PhantomData<Marker>, | |
} | |
impl<Marker> Default for CustomCommandQueue<Marker> { | |
fn default() -> Self { | |
Self { | |
queue: Default::default(), | |
_phantom: Default::default(), | |
} | |
} | |
} | |
/// System parameter very similar to the [`Commands`] parameter, but commands issued though it will | |
/// be flushed during [`FighterStateSystemSet::FlushStateTransitions`] instead of at the end of the | |
/// frame. | |
#[derive(SystemParam)] | |
pub struct CustomCommands<'w, 's, Marker: Sync + Send + 'static> { | |
queue: ResMut<'w, CustomCommandQueue<Marker>>, | |
entities: &'w Entities, | |
#[system_param(ignore)] | |
_phantom: PhantomData<(&'s (), Marker)>, | |
} | |
impl<'w, 's, Marker: Sync + Send + 'static> CustomCommands<'w, 's, Marker> { | |
pub fn commands<'a>(&'a mut self) -> Commands<'w, 'a> { | |
Commands::new_from_entities(&mut self.queue.queue, self.entities) | |
} | |
} | |
/// Extension trait for [`App`] that adds a function to initialize a custom command queue. | |
pub trait InitCustomCommandsAppExt { | |
/// Initialize a custom command queue tha will be usable as a system param with | |
/// `CustomCommands<Marker>`. | |
fn init_custom_commands<Marker: Sync + Send + 'static>(&mut self) -> &mut Self; | |
} | |
impl InitCustomCommandsAppExt for App { | |
fn init_custom_commands<Marker: Sync + Send + 'static>(&mut self) -> &mut Self { | |
self.init_resource::<CustomCommandQueue<Marker>>() | |
} | |
} | |
/// Exclusive system that can be added to flush a custom command queue. | |
pub fn flush_custom_commands<Marker: Send + Sync + 'static>(world: &mut World) { | |
let mut queue = world | |
.remove_resource::<CustomCommandQueue<Marker>>() | |
.unwrap(); | |
queue.queue.apply(world); | |
world.insert_resource(queue); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment