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_set_atmosphere(
    world: &mut World,
    request: crate::mcp::SetAtmosphereRequest,
) -> McpResponse {
    use crate::ecs::graphics::resources::Atmosphere;

    let atmo = match request.atmosphere.to_lowercase().as_str() {
        "none" => Atmosphere::None,
        "sky" => Atmosphere::Sky,
        "cloudy" | "cloudy_sky" | "cloudysky" => Atmosphere::CloudySky,
        "space" => Atmosphere::Space,
        "nebula" => Atmosphere::Nebula,
        "sunset" => Atmosphere::Sunset,
        "hdr" => Atmosphere::Hdr,
        _ => {
            return McpResponse::Error(format!(
                "Unknown atmosphere '{}'. Valid: none, sky, cloudy_sky, space, nebula, sunset, hdr",
                request.atmosphere
            ));
        }
    };

    world.resources.graphics.atmosphere = atmo;
    McpResponse::Success(format!("Atmosphere set to {}", request.atmosphere))
}

pub(crate) fn mcp_load_hdr(world: &mut World, request: crate::mcp::LoadHdrRequest) -> McpResponse {
    use crate::ecs::graphics::resources::Atmosphere;

    let path_buf = std::path::PathBuf::from(&request.path);
    if !path_buf.exists() {
        return McpResponse::Error(format!("HDR file not found: {}", request.path));
    }

    crate::ecs::world::commands::load_hdr_skybox_from_path(world, path_buf);
    world.resources.graphics.atmosphere = Atmosphere::Hdr;
    McpResponse::Success(format!("Loading HDR skybox from {}", request.path))
}

pub(crate) fn mcp_set_graphics(
    world: &mut World,
    request: crate::mcp::SetGraphicsRequest,
) -> McpResponse {
    use crate::ecs::graphics::resources::{ColorGradingPreset, Fog, TonemapAlgorithm};

    let graphics = &mut world.resources.graphics;

    if let Some(enabled) = request.bloom_enabled {
        graphics.bloom_enabled = enabled;
    }
    if let Some(intensity) = request.bloom_intensity {
        graphics.bloom_intensity = intensity;
    }
    if let Some(threshold) = request.bloom_threshold {
        graphics.bloom_threshold = threshold;
    }
    if let Some(enabled) = request.ssao_enabled {
        graphics.ssao_enabled = enabled;
    }
    if let Some(radius) = request.ssao_radius {
        graphics.ssao_radius = radius;
    }
    if let Some(intensity) = request.ssao_intensity {
        graphics.ssao_intensity = intensity;
    }
    if let Some(bias) = request.ssao_bias {
        graphics.ssao_bias = bias;
    }
    if let Some(enabled) = request.fog_enabled {
        if enabled {
            let fog = graphics.fog.get_or_insert(Fog::default());
            if let Some(color) = request.fog_color {
                fog.color = color;
            }
            if let Some(start) = request.fog_start {
                fog.start = start;
            }
            if let Some(end) = request.fog_end {
                fog.end = end;
            }
        } else {
            graphics.fog = None;
        }
    } else if let Some(fog) = graphics.fog.as_mut() {
        if let Some(color) = request.fog_color {
            fog.color = color;
        }
        if let Some(start) = request.fog_start {
            fog.start = start;
        }
        if let Some(end) = request.fog_end {
            fog.end = end;
        }
    }
    if let Some(algo) = request.tonemap {
        graphics.color_grading.tonemap_algorithm = match algo.to_lowercase().as_str() {
            "aces" => TonemapAlgorithm::Aces,
            "reinhard" => TonemapAlgorithm::Reinhard,
            "reinhard_extended" => TonemapAlgorithm::ReinhardExtended,
            "uncharted2" => TonemapAlgorithm::Uncharted2,
            "agx" => TonemapAlgorithm::AgX,
            "neutral" => TonemapAlgorithm::Neutral,
            "none" => TonemapAlgorithm::None,
            _ => TonemapAlgorithm::Aces,
        };
        graphics.color_grading.preset = ColorGradingPreset::Custom;
    }
    if let Some(g) = request.gamma {
        graphics.color_grading.gamma = g;
        graphics.color_grading.preset = ColorGradingPreset::Custom;
    }
    if let Some(s) = request.saturation {
        graphics.color_grading.saturation = s;
        graphics.color_grading.preset = ColorGradingPreset::Custom;
    }
    if let Some(b) = request.brightness {
        graphics.color_grading.brightness = b;
        graphics.color_grading.preset = ColorGradingPreset::Custom;
    }
    if let Some(c) = request.contrast {
        graphics.color_grading.contrast = c;
        graphics.color_grading.preset = ColorGradingPreset::Custom;
    }
    if let Some(grid) = request.show_grid {
        graphics.show_grid = grid;
    }
    if let Some(color) = request.clear_color {
        graphics.clear_color = color;
    }
    if let Some(enabled) = request.dof_enabled {
        graphics.depth_of_field.enabled = enabled;
    }
    if let Some(dist) = request.dof_focus_distance {
        graphics.depth_of_field.focus_distance = dist;
    }
    if let Some(range) = request.dof_focus_range {
        graphics.depth_of_field.focus_range = range;
    }
    if let Some(radius) = request.dof_max_blur_radius {
        graphics.depth_of_field.max_blur_radius = radius;
    }
    if let Some(unlit) = request.unlit_mode {
        graphics.unlit_mode = unlit;
    }

    McpResponse::Success("Graphics settings updated".to_string())
}

pub(crate) fn mcp_spawn_water(
    world: &mut World,
    request: crate::mcp::SpawnWaterRequest,
) -> McpResponse {
    use crate::ecs::mesh::components::create_subdivided_plane_mesh;
    use crate::ecs::prefab::resources::mesh_cache_insert;
    use crate::ecs::water::Water;
    use crate::ecs::world::{
        GLOBAL_TRANSFORM, LOCAL_TRANSFORM, LOCAL_TRANSFORM_DIRTY, NAME, RENDER_MESH, VISIBILITY,
        WATER,
    };

    if world.resources.entity_names.contains_key(&request.name) {
        return McpResponse::Error(format!("Entity '{}' already exists", request.name));
    }

    let entity = world.spawn_entities(
        NAME | LOCAL_TRANSFORM
            | GLOBAL_TRANSFORM
            | LOCAL_TRANSFORM_DIRTY
            | RENDER_MESH
            | VISIBILITY
            | WATER,
        1,
    )[0];

    let scale_vec = request.scale.unwrap_or([10.0, 1.0, 10.0]);
    world.core.set_name(
        entity,
        crate::ecs::name::components::Name(request.name.clone()),
    );
    world.core.set_local_transform(
        entity,
        crate::ecs::transform::components::LocalTransform {
            translation: nalgebra_glm::Vec3::new(
                request.position[0],
                request.position[1],
                request.position[2],
            ),
            scale: nalgebra_glm::Vec3::new(scale_vec[0], scale_vec[1], scale_vec[2]),
            rotation: nalgebra_glm::Quat::identity(),
        },
    );
    world.core.set_global_transform(
        entity,
        crate::ecs::transform::components::GlobalTransform::default(),
    );
    world.core.set_local_transform_dirty(
        entity,
        crate::ecs::transform::components::LocalTransformDirty,
    );
    world.core.set_visibility(
        entity,
        crate::ecs::visibility::components::Visibility { visible: true },
    );

    let mesh_name = "WaterPlane";
    if !world
        .resources
        .mesh_cache
        .registry
        .name_to_index
        .contains_key(mesh_name)
    {
        let mesh = create_subdivided_plane_mesh(20.0, 1);
        mesh_cache_insert(&mut world.resources.mesh_cache, mesh_name.to_string(), mesh);
    }
    world.core.set_render_mesh(
        entity,
        crate::ecs::mesh::components::RenderMesh::new(mesh_name),
    );
    world.resources.mesh_render_state.mark_entity_added(entity);

    let mut water = Water::default();
    if let Some(bc) = request.base_color {
        water.base_color = bc;
    }
    if let Some(wc) = request.water_color {
        water.water_color = wc;
    }
    if let Some(wh) = request.wave_height {
        water.wave_height = wh;
    }
    if let Some(c) = request.choppy {
        water.choppy = c;
    }
    if let Some(s) = request.speed {
        water.speed = s;
    }
    if let Some(f) = request.frequency {
        water.frequency = f;
    }
    world.core.set_water(entity, water);

    world
        .resources
        .entity_names
        .insert(request.name.clone(), entity);
    McpResponse::Success(format!("Spawned water plane '{}'", request.name))
}