oxygengine-core 0.14.2

Core module for Oxygen Engine
Documentation
#![cfg(test)]

use super::{
    app::{App, AppLifeCycle, AppRunner, StandardAppTimer, SyncAppRunner},
    assets::{database::AssetsDatabase, protocols::prefab::PrefabAsset},
    fetch::engines::map::MapFetchEngine,
    hierarchy::{hierarchy_find_world, HierarchyChangeRes, Name, Parent},
    localization::Localization,
    log::{logger_setup, DefaultLogger},
    prefab::*,
    state::{State, StateChange},
};
use specs::prelude::*;
use std::collections::HashMap;

struct Counter {
    pub times: isize,
}

impl Component for Counter {
    type Storage = VecStorage<Self>;
}

struct CounterSystem;

impl<'s> System<'s> for CounterSystem {
    type SystemData = (WriteExpect<'s, AppLifeCycle>, WriteStorage<'s, Counter>);

    fn run(&mut self, (mut lifecycle, mut counters): Self::SystemData) {
        for counter in (&mut counters).join() {
            counter.times -= 1;
            println!("counter: {:?}", counter.times);
            if counter.times <= 0 {
                lifecycle.running = false;
            }
        }
    }
}

struct PrintableSystem;

impl<'s> System<'s> for PrintableSystem {
    type SystemData = ReadStorage<'s, Name>;

    fn run(&mut self, names: Self::SystemData) {
        for name in (&names).join() {
            println!("name: {:?}", name.0);
        }
    }
}

#[derive(Default)]
struct Example {
    root: Option<Entity>,
}

impl State for Example {
    fn on_enter(&mut self, world: &mut World) {
        world.create_entity().with(Counter { times: 10 }).build();

        let root = world.create_entity().with(Name("root".into())).build();

        world
            .create_entity()
            .with(Parent(root))
            .with(Name("child".into()))
            .build();

        self.root = Some(root);
    }

    fn on_process(&mut self, world: &mut World) -> StateChange {
        if let Some(root) = self.root {
            world.delete_entity(root).unwrap();
            self.root = None;
        }
        StateChange::None
    }
}

#[test]
fn test_general() {
    let app = App::build()
        .with_system(CounterSystem, "counter", &[])
        .with_system(PrintableSystem, "names", &[])
        .build(Example::default(), StandardAppTimer::default());

    let mut runner = AppRunner::new(app);
    drop(runner.run(SyncAppRunner::default()));
}

#[derive(Default)]
struct ExamplePrefab {
    phase: usize,
}

impl State for ExamplePrefab {
    fn on_enter(&mut self, world: &mut World) {
        world
            .write_resource::<AssetsDatabase>()
            .load("prefab://scene.yaml")
            .unwrap();
    }

    fn on_process(&mut self, world: &mut World) -> StateChange {
        match self.phase {
            0 => {
                if let Some(asset) = world
                    .read_resource::<AssetsDatabase>()
                    .asset_by_path("prefab://scene.yaml")
                {
                    let prefab = asset
                        .get::<PrefabAsset>()
                        .expect("scene.ron is not a prefab asset")
                        .get();
                    let entities = world
                        .write_resource::<PrefabManager>()
                        .load_scene_from_prefab_world(prefab, world)
                        .unwrap();
                    self.phase = 1;
                    println!("scene.yaml asset finally loaded: {:?}", entities);
                } else {
                    println!("scene.yaml asset not loaded yet");
                }
                StateChange::None
            }
            _ => StateChange::Pop,
        }
    }
}

#[test]
fn test_prefabs() {
    let prefab = PrefabScene {
        autoload: false,
        template_name: None,
        dependencies: vec![],
        entities: vec![
            PrefabSceneEntity::Data(PrefabSceneEntityData {
                uid: Some("uidname".to_owned()),
                components: {
                    let mut map = HashMap::new();
                    map.insert(
                        "Name".to_owned(),
                        PrefabValue::String("some name".to_owned()),
                    );
                    map
                },
            }),
            PrefabSceneEntity::Template("some template".to_owned()),
        ],
    };
    println!("Prefab string:\n{}", prefab.to_prefab_string().unwrap());

    let mut files = HashMap::new();
    files.insert(
        "scene.yaml".to_owned(),
        br#"
        entities:
          - Data:
              components:
                Name: hello
                Tag: greting
                NonPersistent:
        "#
        .to_vec(),
    );
    let app = App::build()
        .with_bundle(
            crate::assets::bundle_installer,
            (MapFetchEngine::new(files), |_| {}),
        )
        .with_bundle(crate::prefab::bundle_installer, |_| {})
        .build(ExamplePrefab::default(), StandardAppTimer::default());

    let mut runner = AppRunner::new(app);
    drop(runner.run(SyncAppRunner::default()));
}

#[test]
fn test_hierarchy_find() {
    let mut app = App::build().build_empty(StandardAppTimer::default());
    let root = app
        .world_mut()
        .create_entity()
        .with(Name("root".into()))
        .build();
    let child_a = app
        .world_mut()
        .create_entity()
        .with(Name("a".into()))
        .with(Parent(root))
        .build();
    let child_b = app
        .world_mut()
        .create_entity()
        .with(Name("b".into()))
        .with(Parent(child_a))
        .build();
    let child_c = app
        .world_mut()
        .create_entity()
        .with(Name("c".into()))
        .with(Parent(root))
        .build();
    app.process();
    assert_eq!(hierarchy_find_world(root, "", app.world()), Some(root));
    assert_eq!(hierarchy_find_world(root, ".", app.world()), Some(root));
    assert_eq!(hierarchy_find_world(root, "..", app.world()), None);
    assert_eq!(hierarchy_find_world(root, "a", app.world()), Some(child_a));
    assert_eq!(hierarchy_find_world(root, "a/", app.world()), Some(child_a));
    assert_eq!(
        hierarchy_find_world(root, "a/.", app.world()),
        Some(child_a)
    );
    assert_eq!(hierarchy_find_world(root, "a/..", app.world()), Some(root));
    assert_eq!(hierarchy_find_world(root, "a/../..", app.world()), None);
    assert_eq!(hierarchy_find_world(root, "b", app.world()), None);
    assert_eq!(hierarchy_find_world(root, "c", app.world()), Some(child_c));
    assert_eq!(hierarchy_find_world(root, "c/", app.world()), Some(child_c));
    assert_eq!(
        hierarchy_find_world(root, "c/.", app.world()),
        Some(child_c)
    );
    assert_eq!(hierarchy_find_world(root, "c/..", app.world()), Some(root));
    assert_eq!(hierarchy_find_world(root, "c/../..", app.world()), None);
    assert_eq!(
        hierarchy_find_world(root, "a/b", app.world()),
        Some(child_b)
    );
    assert_eq!(
        hierarchy_find_world(root, "a/b/", app.world()),
        Some(child_b)
    );
    assert_eq!(
        hierarchy_find_world(root, "a/b/", app.world()),
        Some(child_b)
    );
    assert_eq!(
        hierarchy_find_world(root, "a/b/..", app.world()),
        Some(child_a)
    );
    assert_eq!(
        hierarchy_find_world(root, "a/b/../..", app.world()),
        Some(root)
    );
    assert_eq!(
        hierarchy_find_world(root, "a/b/../../..", app.world()),
        None
    );
    assert_eq!(
        hierarchy_find_world(root, "a/b/../../..", app.world()),
        None
    );
}

#[test]
fn test_hierarchy_add_remove() {
    fn sorted(container: &[Entity]) -> Vec<Entity> {
        let mut result = container.to_vec();
        result.sort();
        result
    }

    let mut app = App::build().build_empty(StandardAppTimer::default());
    {
        let changes = app.world().read_resource::<HierarchyChangeRes>();
        assert_eq!(changes.added(), &[]);
        assert_eq!(changes.removed(), &[]);
    }
    let root = app
        .world_mut()
        .create_entity()
        .with(Name("root".into()))
        .build();
    let e1 = app.world_mut().create_entity().with(Parent(root)).build();
    app.process();
    {
        let changes = app.world().read_resource::<HierarchyChangeRes>();
        assert_eq!(sorted(changes.added()), sorted(&[root, e1]));
        assert_eq!(changes.removed(), &[]);
    }
    app.process();
    {
        let changes = app.world().read_resource::<HierarchyChangeRes>();
        assert_eq!(changes.added(), &[]);
        assert_eq!(changes.removed(), &[]);
    }
    app.world_mut().delete_entity(root).unwrap();
    app.world_mut().delete_entity(e1).unwrap();
    app.process();
    {
        let changes = app.world().read_resource::<HierarchyChangeRes>();
        assert_eq!(changes.added(), &[]);
        assert_eq!(sorted(changes.removed()), sorted(&[root, e1]));
    }
}

#[test]
fn test_logger() {
    logger_setup(DefaultLogger);
    info!("my logger {}", "info");
    warn!("my logger {}", "warn");
    error!("my logger {}", "error");
}

#[test]
fn test_localization() {
    let mut loc = Localization::default();
    loc.add_text(
        "hello",
        "lang",
        "Hello |@name|, you've got |@score| points! \\| |@bye",
    );
    loc.set_current_language(Some("lang".to_owned()));
    // let text = loc.format_text("hello", &[("name", "Person"), ("score", &42.to_string())]).unwrap();
    let text = localization_format_text!(loc, "hello", "name" => "Person", "score" => 42).unwrap();
    assert_eq!(text, "Hello Person, you've got 42 points! | {@bye}");
}