moltrun 1.7.2

High-performance game engine library with AI capabilities, built on wgpu for modern 3D graphics and physics simulation
Documentation
use std::sync::Arc;
use std::path::PathBuf;
use crate::core::{SystemError, InputState};
use super::world::World;
use super::asset::AssetManager;
use super::scene::manifest::{load_project_manifest, ProjectManifest};
use super::scene::SceneManager;
use super::input::InputManager;

/// MoltRun 엔진의 메인 구조체
/// 외부 프로젝트에서 쉽게 사용할 수 있도록 통합된 API 제공
pub struct Engine {
    pub world: World,
    pub input_manager: InputManager,
    pub asset_manager: AssetManager,
    scene_manager: Option<SceneManager>,
    project_root: PathBuf,
    project_manifest: Option<ProjectManifest>,
    initialized: bool,
}

impl Engine {
    /// 새 엔진 인스턴스 생성
    /// project_root: project.yaml이 있는 프로젝트 루트 경로
    pub fn new<P: Into<PathBuf>>(project_root: P) -> Self {
        let project_root = project_root.into();
        
        // project.yaml 로드
        let project_yaml = project_root.join("project.yaml");
        let manifest = load_project_manifest(&project_yaml)
            .map_err(|e| SystemError::RuntimeError(format!("Failed: {}", e)))
            .unwrap();
        
        log::info!("✅ Project loaded: {} v{}", manifest.name, manifest.version);
        
        // asset_root 결정 (config.asset_root 또는 기본값 "assets")
        let asset_root = manifest.config.as_ref()
            .and_then(|c| c.asset_root.as_ref())
            .map(|s| s.as_str())
            .unwrap_or("assets");
        
        let asset_root_path = project_root.join(asset_root);
        
        Self {
            world: World::new(),
            input_manager: InputManager::new(),
            asset_manager: AssetManager::new(asset_root_path),
            scene_manager: Some(SceneManager::new(project_root.clone())),
            project_root,
            project_manifest: Some(manifest),
            initialized: false,
        }
    }
    
    /// 엔진 초기화 (비동기)
    /// winit Window가 준비된 후에 호출해야 함
    pub async fn initialize(&mut self, window: Arc<winit::window::Window>) -> Result<(), SystemError> {
        // 월드 초기화 (RenderSystem 포함)
        self.world.initialize(window).await?;
        
        // entry_scene 자동 로드
        if let Some(manifest) = &self.project_manifest {
            if let Some(config) = &manifest.config {
                let entry_scene = &config.entry_scene;
                log::info!("🎬 Loading entry scene: {}", entry_scene);
                
                if let Some(scene_manager) = &mut self.scene_manager {
                    scene_manager.load_scene(entry_scene, &mut self.world)
                        .map_err(|e| SystemError::RuntimeError(format!("Failed to load entry scene: {}", e)))?;
                }
            }
        }
        
        self.initialized = true;
        log::info!("✅ MoltRun Engine 초기화 완료");
        Ok(())
    }
    
    /// 한 프레임 업데이트
    /// 게임 루프에서 매 프레임 호출
    pub fn update(&mut self, delta_time: f32) -> Result<(), SystemError> {
        if !self.initialized {
            return Err(SystemError::RuntimeError("Engine not initialized. Call initialize() first.".to_string()));
        }
        
        // 입력 프레임 시작
        self.input_manager.begin_frame();
        
        // 월드 업데이트 (시스템들 실행) - InputState 전달
        self.world.update(delta_time, self.input_manager.state(), &mut self.asset_manager)?;
        
        // 입력 프레임 종료
        self.input_manager.end_frame();
        
        Ok(())
    }
    
    /// AssetManager 참조 가져오기
    pub fn asset_manager(&self) -> &AssetManager {
        &self.asset_manager
    }
    
    /// AssetManager 가변 참조 가져오기
    pub fn asset_manager_mut(&mut self) -> &mut AssetManager {
        &mut self.asset_manager
    }
    
    /// 엔진 종료 및 리소스 정리
    pub fn shutdown(&mut self) -> Result<(), SystemError> {
        if self.initialized {
            self.world.shutdown()?;
            self.initialized = false;
            log::info!("MoltRun Engine 종료됨");
        }
        Ok(())
    }
    
    /// 초기화 상태 확인
    pub fn is_initialized(&self) -> bool {
        self.initialized
    }
    
    /// ProjectManifest 참조 가져오기
    pub fn project_manifest(&self) -> Option<&ProjectManifest> {
        self.project_manifest.as_ref()
    }
    
    /// 프로젝트 루트 경로 가져오기
    pub fn project_root(&self) -> &PathBuf {
        &self.project_root
    }
    
    /// SceneManager 가변 참조 가져오기
    pub fn scene_manager_mut(&mut self) -> Option<&mut SceneManager> {
        self.scene_manager.as_mut()
    }
    
    /// 씬 전환
    pub fn load_scene(&mut self, scene_name: &str) -> Result<(), SystemError> {
        if let Some(scene_manager) = &mut self.scene_manager {
            scene_manager.load_scene(scene_name, &mut self.world)
                .map_err(|e| SystemError::RuntimeError(format!("Failed to load scene: {}", e)))?;
        }
        Ok(())
    }
    
    /// winit WindowEvent 처리 (입력 이벤트를 InputManager로 전달)
    /// preview_runner 등 외부 이벤트 루프에서 호출
    pub fn handle_window_event(&mut self, event: &winit::event::WindowEvent) {
        self.input_manager.process_window_event(event);
    }
    
    /// InputState 읽기 전용 참조 가져오기
    pub fn input_state(&self) -> &InputState {
        self.input_manager.state()
    }
    
    /// 현재 씬을 디스크에서 다시 로드
    pub fn reload_current_scene(&mut self) -> Result<(), SystemError> {
        if let Some(scene_manager) = &mut self.scene_manager {
            if let Some(scene_name) = scene_manager.current_scene().map(|s| s.to_string()) {
                scene_manager.load_scene(&scene_name, &mut self.world)
                    .map_err(|e| SystemError::RuntimeError(format!("Failed to reload scene: {}", e)))?;
                Ok(())
            } else {
                Err(SystemError::RuntimeError("No scene loaded".to_string()))
            }
        } else {
            Err(SystemError::RuntimeError("SceneManager not available".to_string()))
        }
    }
}

impl Default for Engine {
    fn default() -> Self {
        Self::new(".")
    }
}