use bevy::prelude::*;
use bevy::render::view::screenshot::Screenshot;
use bevy::render::view::screenshot::ScreenshotCaptured;
use bevy::tasks::IoTaskPool;
use bevy_remote::BrpError;
use bevy_remote::BrpResult;
use bevy_remote::error_codes::INTERNAL_ERROR;
use bevy_remote::error_codes::INVALID_PARAMS;
use serde_json::Value;
use serde_json::json;
pub fn handler(In(params): In<Option<Value>>, world: &mut World) -> BrpResult {
if bevy::image::ImageFormat::from_extension("png").is_none() {
return Err(BrpError {
code: INTERNAL_ERROR,
message: "PNG support not available. Enable the 'png' feature in your Bevy dependency"
.to_string(),
data: None,
});
}
let path = params
.as_ref()
.and_then(|v| v.get("path"))
.and_then(|v| v.as_str())
.ok_or_else(|| BrpError {
code: INVALID_PARAMS,
message: "Missing 'path' parameter".to_string(),
data: None,
})?;
let path_buf = std::path::Path::new(path);
let absolute_path = if path_buf.is_absolute() {
path_buf.to_path_buf()
} else {
std::env::current_dir()
.map_err(|e| BrpError {
code: INTERNAL_ERROR,
message: format!("Failed to get current directory: {e}"),
data: None,
})?
.join(path_buf)
};
let absolute_path_str = absolute_path.to_string_lossy().to_string();
info!("Screenshot requested for: {}", absolute_path_str);
let window_exists = world.query::<&Window>().iter(world).any(|w| {
info!(
"Found window - resolution: {:?}, visible: {:?}",
w.resolution, w.visible
);
true
});
if !window_exists {
warn!("No windows found in the world!");
}
let path_for_observer = absolute_path_str.clone();
let entity = world
.spawn((
Screenshot::primary_window(),
Name::new(format!("Screenshot_{absolute_path_str}")),
))
.observe(move |screenshot_captured: On<ScreenshotCaptured>| {
info!("Screenshot captured! Starting async save to: {path_for_observer}");
let img = screenshot_captured.event().image.clone();
let path_clone = path_for_observer.clone();
IoTaskPool::get()
.spawn(async move {
match img.try_into_dynamic() {
Ok(dyn_img) => {
if let Some(parent) = std::path::Path::new(&path_clone).parent()
&& let Err(e) = std::fs::create_dir_all(parent)
{
error!(
"Failed to create directory for screenshot {path_clone}: {e}"
);
return;
}
match dyn_img.save(&path_clone) {
Ok(()) => {
info!("Screenshot successfully saved to: {path_clone}");
},
Err(e) => {
error!("Failed to save screenshot to {path_clone}: {e}");
},
}
},
Err(e) => error!("Failed to convert screenshot to dynamic image: {e}"),
}
})
.detach();
})
.id();
info!("Screenshot entity spawned with ID: {:?}", entity);
Ok(json!({
"success": true,
"path": absolute_path_str,
"working_directory": std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("unknown")).to_string_lossy(),
"note": "Screenshot capture initiated. File I/O will be performed asynchronously on background thread."
}))
}