use std::{
cell::{RefCell, RefMut},
collections::HashMap,
fs::File,
io::Write,
};
use crate::{Component, Entity, System, World};
use ron::{
de::from_reader,
from_str,
ser::{to_string_pretty, PrettyConfig},
Error,
};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Scene {
systems: Option<HashMap<String, Vec<Box<dyn System>>>>,
entities: Vec<RefCell<Entity>>,
}
impl Scene {
pub fn new() -> Self {
return Self {
systems: Some(HashMap::new()),
entities: vec![],
};
}
pub fn add_entity(&mut self, mut entity: Entity) {
entity.id = self.entities.len();
self.entities.push(RefCell::new(entity));
}
pub fn add_system<T: 'static + System>(mut self, tag: &str, system: T) {
let systems = self.systems.as_mut().unwrap();
if systems.contains_key(tag) {
systems.get_mut(tag).unwrap().push(Box::new(system));
return;
}
systems.insert(String::from(tag), vec![Box::new(system)]);
}
pub fn get_entity(&self, id: usize) -> Option<RefMut<Entity>> {
if let Some(e) = self.entities.get(id) {
return Some(e.borrow_mut());
}
return None;
}
pub fn get_entities(&self) -> Vec<RefMut<Entity>> {
return self.entities.iter().map(|e| e.borrow_mut()).collect();
}
pub fn tick_systems(&mut self, tag: &str, world: &mut World) {
let mut systems = self.systems.take().unwrap();
if !systems.contains_key(tag) {
println!("Scene doesnt include system with secified tag: {}", tag);
return;
}
for system in systems.get_mut(tag).unwrap().iter_mut() {
system.tick(self, world);
}
self.systems = Some(systems);
}
pub fn dispatch_event(&mut self, tag: &str, world: &mut World, data: &dyn std::any::Any) {
let systems = self.systems.take().unwrap();
for system_list in systems.iter() {
for system in system_list.1.iter() {
system.on_event(self, world, tag, data);
}
}
self.systems = Some(systems);
}
pub fn to_ron(&self) -> Result<String, Error> {
return to_string_pretty(&self, PrettyConfig::default());
}
pub fn export_ron(&self, path: &str) -> std::io::Result<()> {
let mut file = File::create(path)?;
let ron = to_string_pretty(&self, PrettyConfig::default()).unwrap();
file.write_all(ron.as_bytes())?;
return Ok(());
}
pub fn from_ron(ron: String) -> Result<Self, Error> {
return from_str(&ron);
}
pub fn import_ron(path: &str) -> std::io::Result<Self> {
let f = File::open(path)?;
let s: Scene = match from_reader(f) {
Ok(s) => s,
Err(e) => panic!("Failed to deserialize scene: {}", e),
};
return Ok(s);
}
}
pub struct SceneBuilder {
systems: HashMap<String, Vec<Box<dyn System>>>,
entities: Vec<RefCell<Entity>>,
}
impl SceneBuilder {
pub fn new() -> Self {
return Self {
entities: vec![],
systems: HashMap::new(),
};
}
pub fn with_entity(mut self, mut entity: Entity) -> Self {
entity.id = self.entities.len();
self.entities.push(RefCell::new(entity));
return self;
}
pub fn with_system<T: 'static + System>(mut self, tag: &str, system: T) -> Self {
if self.systems.contains_key(tag) {
self.systems.get_mut(tag).unwrap().push(Box::new(system));
return self;
}
self.systems
.insert(String::from(tag), vec![Box::new(system)]);
return self;
}
pub fn build(self) -> Scene {
return Scene {
entities: self.entities,
systems: Some(self.systems),
};
}
}
pub trait EntityList {
fn are_active(self) -> Self;
fn with_component<T: 'static + Component>(self) -> Self;
}
impl EntityList for Vec<RefMut<'_, Entity>> {
fn are_active(self) -> Self {
return self
.into_iter()
.filter_map(move |e| if e.is_active { Some(e) } else { None })
.collect();
}
fn with_component<T: 'static + Component>(self) -> Self {
return self
.into_iter()
.filter_map(move |e| {
if e.has_component::<T>() {
Some(e)
} else {
None
}
})
.collect();
}
}