retaker 0.8.6

a simple ecs implementation
Documentation
use retaker::{work::Work, world::LockedWorld};

pub struct Health(i32);
pub struct Attaker {
    damage: u32,
}
#[derive(PartialEq, Eq, Debug)]
pub enum Faction {
    Allies,
    Enemies,
}
pub struct Dead;
pub struct Battle {
    on_going: bool,
}

fn create_battle(world: &LockedWorld) {
    let mut world = world.lock_exclusive();
    _ = world.create_resource(Battle { on_going: true });
}

fn create_player(world: &LockedWorld) {
    let mut world = world.lock_exclusive();
    let player = world.create_entity();
    world.insert(&player, Health(3));
    world.insert(&player, Attaker { damage: 1 });
    world.insert(&player, Faction::Allies);
}

fn create_enemy(world: &LockedWorld) {
    let mut world = world.lock_exclusive();
    let enemy = world.create_entity();
    world.insert(&enemy, Health(2));
    world.insert(&enemy, Attaker { damage: 1 });
    world.insert(&enemy, Faction::Enemies);
}

fn tick_attacks(world: &LockedWorld) {
    let world = world.lock_shared();

    let battle_state = world.resource::<Battle>().unwrap();
    if !battle_state.on_going {
        return;
    }

    let attaker_comps = world.components::<Attaker>().unwrap();
    let mut health_comps = world.components_mut::<Health>().unwrap();
    let faction_comps = world.components::<Faction>().unwrap();

    let attakers = attaker_comps.with(faction_comps.query());
    let attackable = health_comps.with(faction_comps.query());

    for attacker_id in attakers {
        let attacker_faction = faction_comps.get(&attacker_id).unwrap();
        let attacker_comp = attaker_comps.get(&attacker_id).unwrap();
        for attackable_id in attackable.clone() {
            let attackable_health = health_comps.get_mut(&attackable_id).unwrap();
            let attackable_faction = faction_comps.get(&attackable_id).unwrap();
            if attackable_id == attacker_id {
                continue;
            }

            if *attackable_faction != *attacker_faction {
                attackable_health.0 -= attacker_comp.damage as i32;
                println!(
                    "{:?} attacked {:?} and inflicted {}, {} health remaining on {:?} entity",
                    *attacker_faction,
                    *attackable_faction,
                    attacker_comp.damage,
                    attackable_health.0,
                    *attackable_faction,
                );
                continue;
            }
        }
    }
}

fn check_battle(world: &LockedWorld) {
    let world = world.lock_shared();
    let mut battle = world.resource_mut::<Battle>().unwrap();
    if battle.on_going {
        let factions = world.components::<Faction>().unwrap();
        let reference_point = factions.query().into_iter().last();
        if let Some(reference_point) = reference_point {
            for faction in factions.query() {
                if reference_point != faction {
                    return;
                }
            }
            battle.on_going = false;
            println!("battle finished");
        }
    }
}

fn print_dead(world: &LockedWorld) {
    let world = world.lock_shared();
    let healths = world.components::<Health>().unwrap();
    let factions = world.components::<Faction>().unwrap();
    for printable_id in factions.with(healths.query()) {
        let faction = factions.get(&printable_id).unwrap();
        let health = healths.get(&printable_id).unwrap();
        if health.0 <= 0 {
            println!("{:?} died", *faction);
        }
    }
}

fn clear_dead(world: &LockedWorld) {
    let mut world = world.lock_exclusive();
    let health_comps = world.components_mut::<Health>().unwrap();
    let mut queued_deletes = vec![];
    for health_id in health_comps.query() {
        let health = health_comps.get(&health_id).unwrap();
        if health.0 <= 0 {
            queued_deletes.push(health_id.clone());
        }
    }
    drop(health_comps);
    for queued in queued_deletes {
        world.delete_entity(&queued);
    }
}

fn main() {
    let world = LockedWorld::new();

    let start_work = Work::new()
        .add_system(create_battle)
        .add_system(create_player)
        .add_system(create_enemy);

    let update_work = Work::new()
        .add_system(check_battle)
        .add_system(tick_attacks)
        .add_system(print_dead)
        .add_system(clear_dead);

    start_work.run(&world);

    loop {
        update_work.run(&world);
        let world = world.lock_shared();
        let battle = world.resource::<Battle>().unwrap();
        if !battle.on_going {
            break;
        }
    }
}