use crate::ecs::world::World;
use crate::mcp::McpResponse;
pub(crate) fn mcp_load_asset(
world: &mut World,
request: crate::mcp::LoadAssetRequest,
) -> McpResponse {
use crate::ecs::prefab::resources::{CachedPrefab, mesh_cache_insert, prefab_cache_insert};
use crate::ecs::world::commands::WorldCommand;
let crate::mcp::LoadAssetRequest { path, asset_name } = request;
let extension = std::path::Path::new(&path)
.extension()
.and_then(|e| e.to_str())
.map(|e| e.to_lowercase());
let process_result =
|world: &mut World,
prefabs: Vec<crate::ecs::prefab::Prefab>,
meshes: std::collections::HashMap<String, crate::ecs::mesh::components::Mesh>,
textures: std::collections::HashMap<String, (Vec<u8>, u32, u32)>,
animations: Vec<crate::ecs::animation::components::AnimationClip>,
skins: Vec<crate::ecs::prefab::GltfSkin>,
asset_name: &str,
path: &str| {
for (name, (rgba_data, width, height)) in textures {
world.queue_command(WorldCommand::LoadTexture {
name,
rgba_data,
width,
height,
});
}
for (name, mesh) in meshes {
mesh_cache_insert(&mut world.resources.mesh_cache, name, mesh);
}
let prefab_count = prefabs.len();
for (index, prefab) in prefabs.into_iter().enumerate() {
let name = if prefab_count == 1 {
asset_name.to_string()
} else {
format!("{}_{}", asset_name, index)
};
prefab_cache_insert(
&mut world.resources.prefab_cache,
name,
CachedPrefab {
prefab,
animations: animations.clone(),
skins: skins.clone(),
source_path: Some(path.to_string()),
},
);
}
McpResponse::Success(format!(
"Loaded asset '{}' from '{}' ({} prefab(s))",
asset_name, path, prefab_count
))
};
match extension.as_deref() {
Some("glb") | Some("gltf") => match std::fs::read(&path) {
Ok(bytes) => match crate::ecs::prefab::import_gltf_from_bytes(&bytes) {
Ok(result) => process_result(
world,
result.prefabs,
result.meshes,
result.textures,
result.animations,
result.skins,
&asset_name,
&path,
),
Err(e) => McpResponse::Error(format!("Failed to load '{}': {}", path, e)),
},
Err(e) => McpResponse::Error(format!("Failed to read '{}': {}", path, e)),
},
#[cfg(feature = "fbx")]
Some("fbx") => {
match crate::ecs::prefab::import_fbx_from_path(std::path::Path::new(&path)) {
Ok(result) => process_result(
world,
result.prefabs,
result.meshes,
result.textures,
result.animations,
result.skins,
&asset_name,
&path,
),
Err(e) => McpResponse::Error(format!("Failed to load '{}': {}", path, e)),
}
}
_ => McpResponse::Error(
"Unsupported file extension. Supported: .glb, .gltf, .fbx".to_string(),
),
}
}
pub(crate) fn mcp_spawn_prefab(
world: &mut World,
request: crate::mcp::SpawnPrefabRequest,
) -> McpResponse {
use crate::ecs::prefab::resources::prefab_cache_get;
use crate::ecs::prefab::spawn_prefab_with_skins;
use crate::ecs::world::NAME;
let crate::mcp::SpawnPrefabRequest {
asset_name,
entity_name,
position,
scale,
} = request;
let scale = scale.unwrap_or([1.0, 1.0, 1.0]);
if world.resources.entity_names.contains_key(&entity_name) {
return McpResponse::Error(format!("Entity '{}' already exists", entity_name));
}
let Some(cached) = prefab_cache_get(&world.resources.prefab_cache, &asset_name) else {
return McpResponse::Error(format!(
"Asset '{}' not found. Use load_asset first.",
asset_name
));
};
let prefab = cached.prefab.clone();
let animations = cached.animations.clone();
let skins = cached.skins.clone();
let pos = nalgebra_glm::Vec3::new(position[0], position[1], position[2]);
let entity = spawn_prefab_with_skins(world, &prefab, &animations, &skins, pos);
if scale != [1.0, 1.0, 1.0]
&& let Some(transform) = world.get_local_transform_mut(entity)
{
transform.scale = nalgebra_glm::Vec3::new(scale[0], scale[1], scale[2]);
crate::ecs::transform::systems::mark_local_transform_dirty(world, entity);
}
world.add_components(entity, NAME);
world.set_name(
entity,
crate::ecs::name::components::Name(entity_name.clone()),
);
world
.resources
.entity_names
.insert(entity_name.clone(), entity);
McpResponse::Success(format!(
"Spawned prefab '{}' as entity '{}' at {:?}",
asset_name, entity_name, position
))
}
pub(crate) fn mcp_list_loaded_assets(world: &World) -> McpResponse {
use crate::ecs::prefab::resources::prefab_cache_names;
let names: Vec<String> = prefab_cache_names(&world.resources.prefab_cache)
.cloned()
.collect();
McpResponse::AssetList(names)
}