use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use bevy::prelude::*;
use bevy::reflect::TypePath;
use jackdaw_jsn::format::{JsnAssets, JsnEntity, JsnHeader, JsnMetadata, JsnScene};
use jackdaw_runtime::{JackdawPlugin, JackdawScene, JackdawSceneRoot};
use serde_json::json;
#[derive(Component, Reflect, Clone, Copy, Default)]
#[reflect(Component, Default)]
struct PlayerSpawn {
pub variant: u32,
}
#[derive(Resource, Default, Clone)]
struct InsertObservation(Arc<Mutex<Vec<Vec3>>>);
#[test]
fn on_insert_observer_sees_propagated_global_transform() {
let mut app = App::new();
app.add_plugins(MinimalPlugins);
app.add_plugins(bevy::transform::TransformPlugin);
app.add_plugins(bevy::asset::AssetPlugin::default());
app.add_plugins(bevy::scene::ScenePlugin);
app.add_plugins(JackdawPlugin);
app.register_type::<PlayerSpawn>();
let observation = InsertObservation::default();
app.insert_resource(observation.clone());
app.add_observer(
|trigger: On<Insert, PlayerSpawn>,
transforms: Query<&GlobalTransform>,
observation: Res<InsertObservation>| {
if let Ok(gt) = transforms.get(trigger.entity)
&& let Ok(mut log) = observation.0.lock()
{
log.push(gt.translation());
}
},
);
let scene = JsnScene {
jsn: JsnHeader::default(),
metadata: JsnMetadata::default(),
editor: None,
assets: JsnAssets::default(),
scene: vec![
JsnEntity {
parent: None,
components: [(
"bevy_transform::components::transform::Transform".to_string(),
json!({
"translation": [10.0, 0.0, 0.0],
"rotation": [0.0, 0.0, 0.0, 1.0],
"scale": [1.0, 1.0, 1.0],
}),
)]
.into_iter()
.collect(),
},
JsnEntity {
parent: Some(0),
components: [
(
"bevy_transform::components::transform::Transform".to_string(),
json!({
"translation": [0.0, 5.0, 0.0],
"rotation": [0.0, 0.0, 0.0, 1.0],
"scale": [1.0, 1.0, 1.0],
}),
),
(
<PlayerSpawn as TypePath>::type_path().to_string(),
json!({ "variant": 0 }),
),
]
.into_iter()
.collect(),
},
],
};
let scene_handle = app
.world_mut()
.resource_mut::<Assets<JackdawScene>>()
.add(JackdawScene::new(scene, PathBuf::new()));
app.world_mut().spawn(JackdawSceneRoot(scene_handle));
app.update();
app.update();
let log = observation.0.lock().unwrap();
assert_eq!(log.len(), 1, "expected one PlayerSpawn insert observation");
let translation = log[0];
assert!(
(translation.x - 10.0).abs() < 1e-4 && (translation.y - 5.0).abs() < 1e-4,
"On<Insert, PlayerSpawn> observer must see GlobalTransform = parent * child = (10, 5, 0); got {translation:?}",
);
}