nightshade-editor 0.13.4

An interactive editor for the Nightshade game engine
use crate::app_context::AssetKey;
#[cfg(not(target_arch = "wasm32"))]
use crate::app_context::PrefabMetadata;
#[cfg(not(target_arch = "wasm32"))]
use crate::app_context::ProjectEditState;
#[cfg(not(target_arch = "wasm32"))]
use crate::mosaic::ToastKind;
#[cfg(not(target_arch = "wasm32"))]
use crate::mosaic::Toasts;
use crate::project_io::{EditorProjectFile, ProjectState, project_data_mut};
#[cfg(not(target_arch = "wasm32"))]
use nightshade::prelude::tracing;

pub fn update_asset_path(
    project: &mut Option<EditorProjectFile>,
    project_state: &mut ProjectState,
    #[cfg(not(target_arch = "wasm32"))] toasts: &mut Toasts,
    key: &AssetKey,
    new_path: &str,
) {
    if let Some(project) = project
        && let Some(map) = project_data_mut(project).scenes.get_mut(&key.scene_name)
        && key.asset_name == "HDR Skybox"
        && let Some(nightshade::ecs::scene::SceneHdrSkybox::Reference { path }) =
            &mut map.hdr_skybox
    {
        *path = new_path.to_string();
        project_state.mark_modified();
        #[cfg(not(target_arch = "wasm32"))]
        toasts.push(
            ToastKind::Success,
            format!("Updated HDR skybox path in scene '{}'", key.scene_name),
            3.0,
        );
    }
}

#[cfg(not(target_arch = "wasm32"))]
pub fn scan_assets_directory(
    project_edit: &ProjectEditState,
    prefabs: &mut Vec<PrefabMetadata>,
    toasts: &mut Toasts,
) {
    let Some(project_path) = &project_edit.current_path else {
        toasts.push(ToastKind::Warning, "No project path set", 3.0);
        return;
    };

    let Some(project_dir) = project_path.parent() else {
        toasts.push(
            ToastKind::Warning,
            "Could not determine project directory",
            3.0,
        );
        return;
    };

    let assets_dir = project_dir.join("assets");
    if !assets_dir.exists() {
        toasts.push(
            ToastKind::Warning,
            format!("Assets directory not found: {}", assets_dir.display()),
            3.0,
        );
        return;
    }

    let mut found_assets: Vec<std::path::PathBuf> = Vec::new();

    if let Ok(entries) = std::fs::read_dir(&assets_dir) {
        for entry in entries.flatten() {
            let path = entry.path();
            if let Some(ext) = path.extension() {
                let ext_lower = ext.to_string_lossy().to_lowercase();
                if ext_lower == "gltf" || ext_lower == "glb" {
                    found_assets.push(path);
                }
            }
        }
    }

    if found_assets.is_empty() {
        toasts.push(
            ToastKind::Info,
            "No GLTF/GLB files found in assets directory",
            3.0,
        );
        return;
    }

    let existing_paths: std::collections::HashSet<String> = prefabs
        .iter()
        .filter_map(|metadata| metadata.source_path.clone())
        .collect();

    let mut imported_count = 0;
    for asset_path in found_assets {
        let path_str = asset_path
            .canonicalize()
            .ok()
            .and_then(|p| p.to_str().map(|s| s.to_string()))
            .unwrap_or_else(|| asset_path.display().to_string());

        if existing_paths.contains(&path_str) {
            continue;
        }

        match nightshade::ecs::prefab::import_gltf_from_path(&asset_path) {
            Ok(result) => {
                for prefab in result.prefabs {
                    prefabs.push(PrefabMetadata {
                        prefab,
                        animations: result.animations.clone(),
                        source_path: Some(path_str.clone()),
                    });
                    imported_count += 1;
                }
            }
            Err(error) => {
                tracing::warn!("Failed to import {}: {}", asset_path.display(), error);
            }
        }
    }

    if imported_count > 0 {
        toasts.push(
            ToastKind::Success,
            format!(
                "Imported {} new prefabs from assets directory",
                imported_count
            ),
            3.0,
        );
    } else {
        toasts.push(
            ToastKind::Info,
            "No new assets to import (all already loaded)",
            3.0,
        );
    }
}