use std::collections::HashMap;
use serde_yaml::Value;
use crate::core::Component;
use crate::math::Vec2;
use super::manifest::{yaml_keys, yaml_utils};
#[derive(Debug, thiserror::Error)]
pub enum FactoryError {
#[error("Unknown component type: {0}")]
UnknownComponent(String),
#[error("Invalid component data: {0}")]
InvalidData(String),
#[error("YAML parsing error: {0}")]
YamlParse(#[from] yaml_utils::YamlParseError),
}
pub trait ComponentFactory: Send + Sync {
fn create_component(&self, yaml_value: &Value) -> Result<Box<dyn Component>, FactoryError>;
}
pub struct ComponentRegistry {
factories: HashMap<String, Box<dyn ComponentFactory>>,
}
impl ComponentRegistry {
pub fn new() -> Self {
let mut registry = Self {
factories: HashMap::new(),
};
registry.register("Transform", TransformFactory);
registry.register("Sprite", SpriteFactory);
registry.register("Text", TextFactory);
registry
}
pub fn register<F: ComponentFactory + 'static>(&mut self, name: &str, factory: F) {
self.factories.insert(name.to_string(), Box::new(factory));
}
pub fn create(&self, component_name: &str, yaml: &Value) -> Result<Box<dyn Component>, FactoryError> {
self.factories
.get(component_name)
.ok_or_else(|| FactoryError::UnknownComponent(component_name.to_string()))?
.create_component(yaml)
}
}
pub struct TransformFactory;
impl ComponentFactory for TransformFactory {
fn create_component(&self, yaml: &Value) -> Result<Box<dyn Component>, FactoryError> {
use crate::components::Transform;
use yaml_keys::transform::*;
use yaml_utils::*;
let position = if yaml[POSITION].is_null() {
Vec2::zero()
} else {
parse_vec2_array(&yaml[POSITION], POSITION)?
};
let rotation = yaml[ROTATION].as_f64().unwrap_or(0.0) as f32;
let scale = if yaml[SCALE].is_null() {
Vec2::one()
} else {
parse_vec2_array(&yaml[SCALE], SCALE)?
};
Ok(Box::new(Transform { position, rotation, scale }))
}
}
pub struct SpriteFactory;
impl ComponentFactory for SpriteFactory {
fn create_component(&self, yaml: &Value) -> Result<Box<dyn Component>, FactoryError> {
use crate::components::{Sprite, Color};
use yaml_keys::sprite::*;
use yaml_utils::*;
let texture_path = yaml[TEXTURE].as_str().unwrap_or("").to_string();
let size = if yaml[SIZE].is_null() {
Vec2::new(32.0, 32.0)
} else {
parse_vec2_array(&yaml[SIZE], SIZE)?
};
let visible = yaml[VISIBLE].as_bool().unwrap_or(true);
let color = if yaml[TINT].is_null() {
Color::white()
} else {
parse_color_array(&yaml[TINT])?
};
let flip_x = yaml[FLIP_X].as_bool().unwrap_or(false);
let flip_y = yaml[FLIP_Y].as_bool().unwrap_or(false);
let layer = yaml[LAYER].as_i64().unwrap_or(0) as i32;
Ok(Box::new(Sprite {
texture_path,
visible,
size,
color,
flip_x,
flip_y,
layer,
}))
}
}
pub struct TextFactory;
impl ComponentFactory for TextFactory {
fn create_component(&self, yaml: &Value) -> Result<Box<dyn Component>, FactoryError> {
use crate::components::{Text, Color, TextAlignment};
use yaml_keys::text::*;
use yaml_utils::*;
let content = yaml[CONTENT].as_str().unwrap_or("").to_string();
let font_path = yaml[FONT].as_str().unwrap_or("").to_string();
let font_size = yaml[FONT_SIZE].as_f64().unwrap_or(16.0) as f32;
let visible = yaml[VISIBLE].as_bool().unwrap_or(true);
let color = if yaml[COLOR].is_null() {
Color::white()
} else {
parse_color_array(&yaml[COLOR])?
};
let alignment = match yaml[ALIGNMENT].as_str().unwrap_or("left") {
"center" => TextAlignment::Center,
"right" => TextAlignment::Right,
_ => TextAlignment::Left,
};
let line_spacing = yaml[LINE_SPACING].as_f64().unwrap_or(1.0) as f32;
let layer = yaml[LAYER].as_i64().unwrap_or(0) as i32;
Ok(Box::new(Text {
content,
font_path,
font_size,
color,
visible,
alignment,
line_spacing,
layer,
}))
}
}