Skip to content

Instantly share code, notes, and snippets.

@zicklag
Last active August 7, 2022 15:27
Show Gist options
  • Save zicklag/3446143d563657d54e292cc7e2c15378 to your computer and use it in GitHub Desktop.
Save zicklag/3446143d563657d54e292cc7e2c15378 to your computer and use it in GitHub Desktop.
Custom Command Queues in Bevy
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);
}
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