nightshade 0.13.3

A cross-platform data-oriented game engine.
Documentation
use crate::ecs::world::World;
use crate::mcp::McpResponse;

pub(crate) fn mcp_spawn_particles(
    world: &mut World,
    request: crate::mcp::SpawnParticlesRequest,
) -> McpResponse {
    use crate::ecs::particles::components::ParticleEmitter;
    use crate::ecs::transform::components::LocalTransform;
    use crate::ecs::world::{
        GLOBAL_TRANSFORM, LOCAL_TRANSFORM, LOCAL_TRANSFORM_DIRTY, NAME, PARTICLE_EMITTER,
    };

    let enabled = request.enabled.unwrap_or(true);
    let pos = nalgebra_glm::Vec3::new(
        request.position[0],
        request.position[1],
        request.position[2],
    );
    let color_vec = request
        .color
        .map(|c| nalgebra_glm::Vec3::new(c[0], c[1], c[2]));
    let count = request.particle_count.unwrap_or(200);

    let mut emitter = match request.preset.to_lowercase().as_str() {
        "fire" => ParticleEmitter::fire(nalgebra_glm::Vec3::zeros()),
        "smoke" => ParticleEmitter::smoke(nalgebra_glm::Vec3::zeros()),
        "sparks" => ParticleEmitter::sparks(nalgebra_glm::Vec3::zeros()),
        "firework_explosion" | "firework" | "explosion" => {
            let c = color_vec.unwrap_or(nalgebra_glm::Vec3::new(1.0, 0.5, 0.2));
            ParticleEmitter::firework_explosion(nalgebra_glm::Vec3::zeros(), c, count)
        }
        "firework_willow" | "willow" => {
            let c = color_vec.unwrap_or(nalgebra_glm::Vec3::new(0.8, 0.9, 1.0));
            ParticleEmitter::firework_willow(nalgebra_glm::Vec3::zeros(), c, count)
        }
        "firework_chrysanthemum" | "chrysanthemum" => {
            let c = color_vec.unwrap_or(nalgebra_glm::Vec3::new(1.0, 0.3, 0.3));
            ParticleEmitter::firework_chrysanthemum(nalgebra_glm::Vec3::zeros(), c, count)
        }
        "firework_ring" | "ring" => {
            let c = color_vec.unwrap_or(nalgebra_glm::Vec3::new(0.3, 0.8, 1.0));
            ParticleEmitter::firework_ring(nalgebra_glm::Vec3::zeros(), c, count)
        }
        "flash" | "flash_burst" => ParticleEmitter::flash_burst(nalgebra_glm::Vec3::zeros()),
        _ => {
            return McpResponse::Error(format!("Unknown particle preset '{}'", request.preset));
        }
    };

    emitter.enabled = enabled;

    let entity = world
        .spawn_entities(
            NAME | LOCAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY | GLOBAL_TRANSFORM | PARTICLE_EMITTER,
            1,
        )
        .into_iter()
        .next()
        .unwrap();
    world
        .core
        .set_local_transform(entity, LocalTransform::from_translation(pos));
    world.core.set_particle_emitter(entity, emitter);
    world.core.set_name(
        entity,
        crate::ecs::name::components::Name(request.name.clone()),
    );
    world
        .resources
        .entity_names
        .insert(request.name.clone(), entity);

    McpResponse::Success(format!("Spawned particle emitter '{}'", request.name))
}

pub(crate) fn mcp_set_particles(
    world: &mut World,
    request: crate::mcp::SetParticlesRequest,
) -> Result<McpResponse, McpResponse> {
    let entity = super::resolve_entity(world, &request.name)?;

    let Some(emitter) = world.core.get_particle_emitter_mut(entity) else {
        return Err(McpResponse::Error(format!(
            "Entity '{}' has no particle emitter",
            request.name
        )));
    };

    if let Some(e) = request.enabled {
        emitter.enabled = e;
    }
    if let Some(rate) = request.spawn_rate {
        emitter.spawn_rate = rate;
    }
    if let Some(strength) = request.emissive_strength {
        emitter.emissive_strength = strength;
    }

    Ok(McpResponse::Success(format!(
        "Particle emitter '{}' updated",
        request.name
    )))
}

pub(crate) fn mcp_spawn_decal(
    world: &mut World,
    request: crate::mcp::SpawnDecalRequest,
) -> McpResponse {
    use crate::ecs::decal::components::Decal;
    use crate::ecs::transform::components::LocalTransform;
    use crate::ecs::world::{
        DECAL, GLOBAL_TRANSFORM, LOCAL_TRANSFORM, LOCAL_TRANSFORM_DIRTY, NAME,
    };

    let size = request.size.unwrap_or([1.0, 1.0, 1.0]);
    let rotation = request.rotation.unwrap_or([0.0, 0.0, 0.0]);

    let entity = world
        .spawn_entities(
            NAME | LOCAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY | GLOBAL_TRANSFORM | DECAL,
            1,
        )
        .into_iter()
        .next()
        .unwrap();

    let pos = nalgebra_glm::Vec3::new(
        request.position[0],
        request.position[1],
        request.position[2],
    );
    let quat = nalgebra_glm::quat_identity();
    let quat =
        nalgebra_glm::quat_rotate(&quat, rotation[0], &nalgebra_glm::Vec3::new(1.0, 0.0, 0.0));
    let quat =
        nalgebra_glm::quat_rotate(&quat, rotation[1], &nalgebra_glm::Vec3::new(0.0, 1.0, 0.0));
    let quat =
        nalgebra_glm::quat_rotate(&quat, rotation[2], &nalgebra_glm::Vec3::new(0.0, 0.0, 1.0));

    let mut transform = LocalTransform::from_translation(pos);
    transform.rotation = quat;
    world.core.set_local_transform(entity, transform);

    let decal = Decal {
        texture: Some(request.texture),
        size: nalgebra_glm::Vec2::new(size[0], size[1]),
        depth: size[2],
        ..Default::default()
    };
    world.core.set_decal(entity, decal);
    world.core.set_name(
        entity,
        crate::ecs::name::components::Name(request.name.clone()),
    );
    world
        .resources
        .entity_names
        .insert(request.name.clone(), entity);

    McpResponse::Success(format!("Spawned decal '{}'", request.name))
}