use super::hook::{DefaultSaveLoadHook, SaveLoadHook};
use super::system::SaveLoadSystem;
use crate::plugin::{Plugin, PluginBuilder, PluginBuilderExt};
use crate::resources::Resource;
use async_trait::async_trait;
use std::path::PathBuf;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct SaveLoadConfig {
pub save_directory: PathBuf,
pub format: SaveFormat,
pub enable_auto_save: bool,
pub auto_save_interval: u64,
}
impl Resource for SaveLoadConfig {}
impl Default for SaveLoadConfig {
fn default() -> Self {
Self {
save_directory: PathBuf::from("saves"),
format: SaveFormat::Json,
enable_auto_save: true,
auto_save_interval: 300, }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SaveFormat {
Json,
Ron,
}
pub struct SaveLoadPlugin {
hook: Arc<dyn SaveLoadHook>,
config: SaveLoadConfig,
}
impl SaveLoadPlugin {
pub fn new() -> Self {
Self {
hook: Arc::new(DefaultSaveLoadHook),
config: SaveLoadConfig::default(),
}
}
pub fn with_hook<H: SaveLoadHook + 'static>(mut self, hook: H) -> Self {
self.hook = Arc::new(hook);
self
}
pub fn with_config(mut self, config: SaveLoadConfig) -> Self {
self.config = config;
self
}
pub fn with_save_directory(mut self, directory: PathBuf) -> Self {
self.config.save_directory = directory;
self
}
pub fn with_format(mut self, format: SaveFormat) -> Self {
self.config.format = format;
self
}
pub fn with_auto_save(mut self, enabled: bool, interval_seconds: u64) -> Self {
self.config.enable_auto_save = enabled;
self.config.auto_save_interval = interval_seconds;
self
}
}
impl Default for SaveLoadPlugin {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl Plugin for SaveLoadPlugin {
fn name(&self) -> &'static str {
"save_load_plugin"
}
fn build(&self, builder: &mut dyn PluginBuilder) {
builder.register_resource(self.config.clone());
builder.register_system(Box::new(SaveLoadSystem::new(
self.hook.clone(),
self.config.clone(),
)));
}
async fn initialize(&mut self) {
if let Err(e) = tokio::fs::create_dir_all(&self.config.save_directory).await {
eprintln!(
"Warning: Failed to create save directory {:?}: {}",
self.config.save_directory, e
);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::plugin::save_load::hook::SaveLoadHook;
#[test]
fn test_plugin_creation() {
let plugin = SaveLoadPlugin::new();
assert_eq!(plugin.name(), "save_load_plugin");
assert_eq!(plugin.config.format, SaveFormat::Json);
assert!(plugin.config.enable_auto_save);
}
#[test]
fn test_plugin_with_config() {
let config = SaveLoadConfig {
save_directory: PathBuf::from("test_saves"),
format: SaveFormat::Ron,
enable_auto_save: false,
auto_save_interval: 60,
};
let plugin = SaveLoadPlugin::new().with_config(config.clone());
assert_eq!(plugin.config.save_directory, config.save_directory);
assert_eq!(plugin.config.format, SaveFormat::Ron);
assert!(!plugin.config.enable_auto_save);
assert_eq!(plugin.config.auto_save_interval, 60);
}
#[test]
fn test_plugin_with_hook() {
struct CustomHook;
#[async_trait::async_trait]
impl SaveLoadHook for CustomHook {}
let plugin = SaveLoadPlugin::new().with_hook(CustomHook);
assert_eq!(plugin.name(), "save_load_plugin");
}
#[test]
fn test_plugin_convenience_methods() {
let plugin = SaveLoadPlugin::new()
.with_save_directory(PathBuf::from("custom"))
.with_format(SaveFormat::Ron)
.with_auto_save(false, 42);
assert_eq!(plugin.config.save_directory, PathBuf::from("custom"));
assert_eq!(plugin.config.format, SaveFormat::Ron);
assert!(!plugin.config.enable_auto_save);
assert_eq!(plugin.config.auto_save_interval, 42);
}
#[test]
fn test_default_config() {
let config = SaveLoadConfig::default();
assert_eq!(config.save_directory, PathBuf::from("saves"));
assert_eq!(config.format, SaveFormat::Json);
assert!(config.enable_auto_save);
assert_eq!(config.auto_save_interval, 300);
}
}