1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00
azalea/azalea-ecs/src/lib.rs
mat cbc6af81fb
Add PacketEvent (#75)
* add PacketEvent

* docs and fixes

* Event::Packet works
2023-02-26 15:07:52 -06:00

157 lines
5.2 KiB
Rust

#![feature(trait_alias)]
//! Re-export important parts of [`bevy_ecs`] and [`bevy_app`] and make them
//! more compatible with Azalea.
//!
//! This is completely compatible with `bevy_ecs`, so it won't cause issues if
//! you use plugins meant for Bevy.
//!
//! Changes:
//! - Add [`TickPlugin`], [`TickStage`] and [`AppTickExt`] (which adds
//! `app.add_tick_system` and `app.add_tick_system_set`).
//! - Change the macros to use azalea/azalea_ecs instead of bevy/bevy_ecs
//! - Rename `world::World` to [`ecs::Ecs`]
//! - Re-export `bevy_app` in the [`app`] module.
//!
//! [`bevy_ecs`]: https://docs.rs/bevy_ecs
//! [`bevy_app`]: https://docs.rs/bevy_app
use std::time::{Duration, Instant};
pub mod ecs {
pub use bevy_ecs::world::World as Ecs;
pub use bevy_ecs::world::{EntityMut, EntityRef, Mut};
}
pub mod component {
pub use azalea_ecs_macros::Component;
pub use bevy_ecs::component::{ComponentId, ComponentStorage, Components, TableStorage};
// we do this because re-exporting Component would re-export the macro as well,
// which is bad (since we have our own Component macro)
// instead, we have to do this so Component is a trait alias and the original
// impl-able trait is still available as _BevyComponent
pub trait Component = bevy_ecs::component::Component;
pub use bevy_ecs::component::Component as _BevyComponent;
}
pub mod bundle {
pub use azalea_ecs_macros::Bundle;
pub trait Bundle = bevy_ecs::bundle::Bundle;
pub use bevy_ecs::bundle::Bundle as _BevyBundle;
}
pub mod system {
pub use azalea_ecs_macros::Resource;
pub use bevy_ecs::system::{
Command, Commands, EntityCommands, Query, Res, ResMut, SystemState,
};
pub trait Resource = bevy_ecs::system::Resource;
pub use bevy_ecs::system::Resource as _BevyResource;
}
pub mod schedule {
pub use azalea_ecs_macros::StageLabel;
pub use bevy_ecs::schedule::{
IntoRunCriteria, IntoSystemDescriptor, ReportExecutionOrderAmbiguities, Schedule, Stage,
SystemSet, SystemStage,
};
pub trait StageLabel = bevy_ecs::schedule::StageLabel;
pub use bevy_ecs::schedule::StageLabel as _BevyStageLabel;
}
pub use bevy_app as app;
pub use bevy_ecs::{entity, event, ptr, query, storage};
use app::{App, CoreStage, Plugin};
use bevy_ecs::schedule::*;
use ecs::Ecs;
pub struct TickPlugin {
/// How often a tick should happen. 50 milliseconds by default. Set to 0 to
/// tick every update.
pub tick_interval: Duration,
}
impl Plugin for TickPlugin {
fn build(&self, app: &mut App) {
app.add_stage_before(
CoreStage::Update,
TickLabel,
TickStage {
interval: self.tick_interval,
next_tick: Instant::now(),
stage: Box::new(SystemStage::parallel()),
},
);
}
}
impl Default for TickPlugin {
fn default() -> Self {
Self {
tick_interval: Duration::from_millis(50),
}
}
}
#[derive(StageLabel)]
struct TickLabel;
/// A [`Stage`] that runs every 50 milliseconds.
pub struct TickStage {
pub interval: Duration,
pub next_tick: Instant,
stage: Box<dyn Stage>,
}
impl Stage for TickStage {
fn run(&mut self, ecs: &mut Ecs) {
// if the interval is 0, that means it runs every tick
if self.interval.is_zero() {
self.stage.run(ecs);
return;
}
// keep calling run until it's caught up
// TODO: Minecraft bursts up to 10 ticks and then skips, we should too (but
// check the source so we do it right)
while Instant::now() > self.next_tick {
self.next_tick += self.interval;
self.stage.run(ecs);
}
}
}
pub trait AppTickExt {
fn add_tick_system_set(&mut self, system_set: SystemSet) -> &mut App;
fn add_tick_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut App;
}
impl AppTickExt for App {
/// Adds a set of ECS systems that will run every 50 milliseconds.
///
/// Note that you should NOT have `EventReader`s in tick systems, as this
/// will make them sometimes be missed.
fn add_tick_system_set(&mut self, system_set: SystemSet) -> &mut App {
let tick_stage = self
.schedule
.get_stage_mut::<TickStage>(TickLabel)
.expect("Tick Stage not found");
let stage = tick_stage
.stage
.downcast_mut::<SystemStage>()
.expect("Fixed Timestep sub-stage is not a SystemStage");
stage.add_system_set(system_set);
self
}
/// Adds a new ECS system that will run every 50 milliseconds.
///
/// Note that you should NOT have `EventReader`s in tick systems, as this
/// will make them sometimes be missed.
fn add_tick_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut App {
let tick_stage = self
.schedule
.get_stage_mut::<TickStage>(TickLabel)
.expect("Tick Stage not found");
let stage = tick_stage
.stage
.downcast_mut::<SystemStage>()
.expect("Fixed Timestep sub-stage is not a SystemStage");
stage.add_system(system);
self
}
}