Created
July 21, 2023 00:16
-
-
Save dmlary/943af6900ce3abe152ae295afc746bd8 to your computer and use it in GitHub Desktop.
bevy 0.10.1 stun race-condition resolution
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
//! Example workaround for ecs-based race-conditions when used in muds. | |
//! The key problem is two characters stunning each other in the same | |
//! frame, only one of them should end up stunned. | |
//! | |
//! This solution in bevy uses an exclusive system that runs without | |
//! world deferment. | |
#[allow(unused)] | |
use anyhow::{bail, Result}; | |
use bevy::{log::LogPlugin, prelude::*}; | |
fn main() { | |
App::new() | |
.add_plugin(LogPlugin::default()) | |
.add_startup_system(setup) | |
.add_systems((perform_actions, check_state).chain()) | |
.add_event::<ActionEvent>() | |
.run(); | |
} | |
trait Action: Sync + Send + std::fmt::Debug { | |
fn run(&mut self, world: &mut World) -> Result<()>; | |
} | |
struct ActionEvent(Box<dyn Action>); | |
#[derive(Component)] | |
struct Stunned; | |
#[derive(Debug)] | |
struct StunAction { | |
actor: Entity, | |
target: Entity, | |
} | |
impl Action for StunAction { | |
fn run(&mut self, world: &mut World) -> Result<()> { | |
if world.entity(self.actor).contains::<Stunned>() { | |
bail!("actor is stunned"); | |
} | |
world.entity_mut(self.target).insert(Stunned); | |
Ok(()) | |
} | |
} | |
impl<T: Action + 'static> From<T> for ActionEvent { | |
fn from(value: T) -> Self { | |
let action: Box<dyn Action> = Box::new(value); | |
ActionEvent(action) | |
} | |
} | |
fn setup(mut commands: Commands, mut events: EventWriter<ActionEvent>) { | |
let a = commands.spawn((Name::new("player_a"),)).id(); | |
let b = commands.spawn((Name::new("player_b"),)).id(); | |
events.send( | |
StunAction { | |
actor: a, | |
target: b, | |
} | |
.into(), | |
); | |
events.send( | |
StunAction { | |
actor: b, | |
target: a, | |
} | |
.into(), | |
); | |
} | |
fn perform_actions(world: &mut World) { | |
let mut events = world.remove_resource::<Events<ActionEvent>>().unwrap(); | |
world.init_resource::<Events<ActionEvent>>(); | |
for mut action in events.drain() { | |
if let Err(e) = action.0.run(world) { | |
warn!("Action failed {:#?} -> {:?}", action.0, e); | |
} | |
} | |
} | |
fn check_state(stunned: Query<Entity, With<Stunned>>) { | |
assert_eq!(stunned.iter().len(), 1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment