use bevy_ecs::{
entity::EntityHashSet,
prelude::*,
schedule::{ScheduleCleanupPolicy, ScheduleError},
system::SystemState,
};
use bevy_log::prelude::*;
use bevy_platform::collections::{HashMap, HashSet};
use crate::{
mods::{ModDespawnBehaviour, ModSystemSet},
prelude::ModSchedules,
};
#[derive(Message)]
pub(crate) struct DisableSystemSet {
pub(crate) set: ModSystemSet,
pub(crate) schedules: ModSchedules,
}
impl Command<()> for DisableSystemSet {
fn apply(self, world: &mut World) {
if !self.schedules.0.is_empty() {
world.write_message(self);
}
}
}
pub(crate) fn disable_mod_system_sets(
world: &mut World,
param: &mut SystemState<MessageReader<DisableSystemSet>>,
) {
let mut messages = param.get_mut(world);
let mut remove = HashMap::new();
for DisableSystemSet { set, schedules } in messages.read() {
for schedule in schedules.0.iter() {
remove
.entry(schedule.schedule_label())
.or_insert(HashSet::new())
.insert(set.clone());
}
}
for (label, sets) in remove {
let mut schedules = world
.get_resource_mut::<Schedules>()
.expect("Running in a bevy App");
let Some(mut schedule) = schedules.remove(label) else {
continue;
};
for set in sets {
if let Err(error) = schedule.remove_systems_in_set(
set.clone(),
world,
ScheduleCleanupPolicy::RemoveSetAndSystems,
) && !matches!(error, ScheduleError::SetNotFound)
{
warn!(
"Unable to remove system set {set:?}. Systems from unloaded mods might still be running!\nError: {error}."
);
}
}
world
.get_resource_mut::<Schedules>()
.expect("Running in a bevy App")
.insert(schedule);
}
}
#[derive(Component, Default)]
#[relationship_target(relationship = DespawnModEntity, linked_spawn)]
pub(crate) struct DespawnModEntities(EntityHashSet);
#[derive(Component)]
#[relationship(relationship_target = DespawnModEntities)]
pub(crate) struct DespawnModEntity(pub(crate) Entity);
#[derive(Clone, Copy)]
pub(crate) struct InsertDespawnComponent(pub(crate) Option<Entity>);
impl InsertDespawnComponent {
pub(crate) fn new(mod_id: Entity, world: &World) -> Self {
Self(if ModDespawnBehaviour::should_despawn_entities(world) {
Some(mod_id)
} else {
None
})
}
}