""" 预设管理器 管理植被和生态系统插件的预设配置 """ import json import os from typing import Dict, Any, List, Optional import time class PresetManager: """ 预设管理器 管理植被和生态系统插件的预设配置,包括创建、保存、加载和应用预设 """ def __init__(self, plugin): """ 初始化预设管理器 Args: plugin: 植被和生态系统插件实例 """ self.plugin = plugin self.enabled = False self.initialized = False # 预设配置 self.preset_config = { 'presets_directory': 'presets/ecosystem', 'default_preset': 'default', 'auto_save_enabled': True, 'max_presets': 100 } # 预设数据 self.presets = {} self.current_preset = None # 预设类别 self.preset_categories = { 'vegetation': {'name': '植被', 'description': '植被配置预设'}, 'animals': {'name': '动物', 'description': '动物配置预设'}, 'environment': {'name': '环境', 'description': '环境配置预设'}, 'ecosystem': {'name': '生态系统', 'description': '生态系统配置预设'}, 'seasons': {'name': '季节', 'description': '季节配置预设'}, 'mixed': {'name': '混合', 'description': '混合配置预设'} } # 统计信息 self.stats = { 'presets_loaded': 0, 'presets_saved': 0, 'presets_applied': 0, 'total_load_time': 0.0, 'total_save_time': 0.0 } print("✓ 预设管理器已创建") def initialize(self) -> bool: """ 初始化预设管理器 Returns: 是否初始化成功 """ try: # 创建预设目录 presets_dir = self.preset_config['presets_directory'] if not os.path.exists(presets_dir): os.makedirs(presets_dir) # 加载默认预设 self._load_default_presets() # 加载用户预设 self._load_user_presets() self.initialized = True print("✓ 预设管理器初始化完成") return True except Exception as e: print(f"✗ 预设管理器初始化失败: {e}") import traceback traceback.print_exc() return False def enable(self) -> bool: """ 启用预设管理器 Returns: 是否启用成功 """ try: if not self.initialized: print("✗ 预设管理器未初始化") return False self.enabled = True print("✓ 预设管理器已启用") return True except Exception as e: print(f"✗ 预设管理器启用失败: {e}") import traceback traceback.print_exc() return False def disable(self): """禁用预设管理器""" try: self.enabled = False print("✓ 预设管理器已禁用") except Exception as e: print(f"✗ 预设管理器禁用失败: {e}") import traceback traceback.print_exc() def finalize(self): """清理预设管理器资源""" try: self.disable() # 自动保存当前预设 if self.preset_config['auto_save_enabled'] and self.current_preset: self.save_preset(self.current_preset) self.initialized = False print("✓ 预设管理器资源已清理") except Exception as e: print(f"✗ 预设管理器资源清理失败: {e}") import traceback traceback.print_exc() def update(self, dt: float): """ 更新预设管理器状态 Args: dt: 时间增量 """ # 处理更新逻辑 pass def _load_default_presets(self): """加载默认预设""" try: # 创建默认植被预设 self.presets['default_vegetation'] = { 'name': '默认植被', 'category': 'vegetation', 'description': '默认的植被配置参数', 'parameters': { 'grass_density': 0.8, 'tree_density': 0.3, 'flower_density': 0.2 }, 'timestamp': time.time(), 'is_default': True } # 创建默认动物预设 self.presets['default_animals'] = { 'name': '默认动物', 'category': 'animals', 'description': '默认的动物配置参数', 'parameters': { 'rabbit_population': 20, 'deer_population': 5, 'bird_population': 30 }, 'timestamp': time.time(), 'is_default': True } # 创建默认环境预设 self.presets['default_environment'] = { 'name': '默认环境', 'category': 'environment', 'description': '默认的环境配置参数', 'parameters': { 'temperature': 20.0, 'humidity': 60.0, 'soil_fertility': 0.5 }, 'timestamp': time.time(), 'is_default': True } # 创建默认生态系统预设 self.presets['default_ecosystem'] = { 'name': '默认生态系统', 'category': 'ecosystem', 'description': '默认的生态系统配置参数', 'parameters': { 'biodiversity_index': 0.6, 'stability_index': 0.7, 'productivity_rate': 1.0 }, 'timestamp': time.time(), 'is_default': True } # 创建默认季节预设 self.presets['default_seasons'] = { 'name': '默认季节', 'category': 'seasons', 'description': '默认的季节配置参数', 'parameters': { 'spring_duration': 90, 'summer_duration': 90, 'autumn_duration': 90, 'winter_duration': 90 }, 'timestamp': time.time(), 'is_default': True } # 创建默认混合预设 self.presets['default_mixed'] = { 'name': '默认混合', 'category': 'mixed', 'description': '默认的混合配置参数', 'parameters': { 'vegetation_config': 'default_vegetation', 'animal_config': 'default_animals', 'environment_config': 'default_environment' }, 'timestamp': time.time(), 'is_default': True } print("✓ 默认预设加载完成") except Exception as e: print(f"✗ 默认预设加载失败: {e}") import traceback traceback.print_exc() def _load_user_presets(self): """加载用户预设""" try: load_start_time = time.time() presets_dir = self.preset_config['presets_directory'] if not os.path.exists(presets_dir): print("✓ 用户预设目录不存在,跳过加载") return # 遍历预设目录 for filename in os.listdir(presets_dir): if filename.endswith('.json'): try: filepath = os.path.join(presets_dir, filename) with open(filepath, 'r', encoding='utf-8') as f: preset_data = json.load(f) # 使用文件名(不含扩展名)作为预设ID preset_id = os.path.splitext(filename)[0] self.presets[preset_id] = preset_data except Exception as e: print(f"✗ 预设文件加载失败 {filename}: {e}") load_time = time.time() - load_start_time self.stats['presets_loaded'] = len(self.presets) self.stats['total_load_time'] = load_time print(f"✓ 用户预设加载完成,共加载 {len(self.presets)} 个预设,耗时: {load_time:.3f}秒") except Exception as e: print(f"✗ 用户预设加载失败: {e}") import traceback traceback.print_exc() def save_preset(self, preset_id: str, preset_data: Dict[str, Any] = None) -> bool: """ 保存预设 Args: preset_id: 预设ID preset_data: 预设数据(如果为None,则保存当前配置) Returns: 是否保存成功 """ try: save_start_time = time.time() if not self.enabled: print("✗ 预设管理器未启用") return False # 如果未提供预设数据,则创建当前配置的快照 if preset_data is None: preset_data = self._create_current_preset_snapshot(preset_id) # 保存预设数据 self.presets[preset_id] = preset_data # 保存到文件 presets_dir = self.preset_config['presets_directory'] filepath = os.path.join(presets_dir, f"{preset_id}.json") with open(filepath, 'w', encoding='utf-8') as f: json.dump(preset_data, f, ensure_ascii=False, indent=2) # 更新统计信息 save_time = time.time() - save_start_time self.stats['presets_saved'] += 1 self.stats['total_save_time'] += save_time print(f"✓ 预设 '{preset_id}' 保存完成,耗时: {save_time:.3f}秒") return True except Exception as e: print(f"✗ 预设保存失败: {e}") import traceback traceback.print_exc() return False def _create_current_preset_snapshot(self, preset_id: str) -> Dict[str, Any]: """ 创建当前配置的预设快照 Args: preset_id: 预设ID Returns: 预设数据字典 """ try: # 获取当前插件配置 preset_data = { 'name': preset_id, 'category': 'mixed', # 默认类别 'description': '用户自定义预设', 'parameters': {}, 'timestamp': time.time(), 'is_default': False } # 添加植被管理器配置 if self.plugin.vegetation_manager: vm = self.plugin.vegetation_manager preset_data['parameters'].update({ 'environment_factors': vm.get_environment_factors(), 'distribution_config': vm.get_distribution_config() }) # 添加动物模拟器配置 if self.plugin.animal_simulator: asim = self.plugin.animal_simulator preset_data['parameters'].update({ 'animal_environment_factors': asim.get_environment_factors(), 'animal_behavior_config': asim.get_behavior_config() }) # 添加生态系统管理器配置 if self.plugin.ecosystem_manager: em = self.plugin.ecosystem_manager preset_data['parameters'].update({ 'ecosystem_parameters': em.get_ecosystem_parameters(), 'time_config': em.get_time_config() }) # 添加季节效应配置 if self.plugin.seasonal_effects: se = self.plugin.seasonal_effects preset_data['parameters'].update({ 'season_config': se.get_time_config(), 'current_season': se.get_current_season() }) return preset_data except Exception as e: print(f"✗ 预设快照创建失败: {e}") import traceback traceback.print_exc() return { 'name': preset_id, 'category': 'mixed', 'description': '默认预设', 'parameters': {}, 'timestamp': time.time(), 'is_default': False } def load_preset(self, preset_id: str) -> Optional[Dict[str, Any]]: """ 加载预设 Args: preset_id: 预设ID Returns: 预设数据字典或None """ try: if not self.enabled: print("✗ 预设管理器未启用") return None if preset_id not in self.presets: print(f"✗ 预设不存在: {preset_id}") return None preset_data = self.presets[preset_id] # 更新统计信息 self.stats['presets_applied'] += 1 self.current_preset = preset_id print(f"✓ 预设 '{preset_id}' 加载完成") return preset_data except Exception as e: print(f"✗ 预设加载失败: {e}") import traceback traceback.print_exc() return None def apply_preset(self, preset_id: str) -> bool: """ 应用预设到当前配置 Args: preset_id: 预设ID Returns: 是否应用成功 """ try: if not self.enabled: print("✗ 预设管理器未启用") return False preset_data = self.load_preset(preset_id) if preset_data is None: return False parameters = preset_data.get('parameters', {}) # 应用参数到各个组件 self._apply_parameters_to_components(parameters) # 更新统计信息 self.stats['presets_applied'] += 1 self.current_preset = preset_id print(f"✓ 预设 '{preset_id}' 应用完成") return True except Exception as e: print(f"✗ 预设应用失败: {e}") import traceback traceback.print_exc() return False def _apply_parameters_to_components(self, parameters: Dict[str, Any]): """ 应用参数到各个组件 Args: parameters: 参数字典 """ try: # 应用到植被管理器 if self.plugin.vegetation_manager: if 'environment_factors' in parameters: self.plugin.vegetation_manager.update_environment_factors(parameters['environment_factors']) if 'distribution_config' in parameters: self.plugin.vegetation_manager.set_distribution_config(parameters['distribution_config']) # 应用到动物模拟器 if self.plugin.animal_simulator: if 'animal_environment_factors' in parameters: self.plugin.animal_simulator.update_environment_factors(parameters['animal_environment_factors']) if 'animal_behavior_config' in parameters: self.plugin.animal_simulator.set_behavior_config(parameters['animal_behavior_config']) # 应用到生态系统管理器 if self.plugin.ecosystem_manager: if 'ecosystem_parameters' in parameters: for param_name, param_value in parameters['ecosystem_parameters'].items(): self.plugin.ecosystem_manager.set_ecosystem_parameter(param_name, param_value) if 'time_config' in parameters: self.plugin.ecosystem_manager.set_time_config(parameters['time_config']) # 应用到季节效应系统 if self.plugin.seasonal_effects: if 'season_config' in parameters: self.plugin.seasonal_effects.set_time_config(parameters['season_config']) if 'current_season' in parameters: self.plugin.seasonal_effects.set_current_season(parameters['current_season']) except Exception as e: print(f"✗ 参数应用失败: {e}") import traceback traceback.print_exc() def delete_preset(self, preset_id: str) -> bool: """ 删除预设 Args: preset_id: 预设ID Returns: 是否删除成功 """ try: if not self.enabled: print("✗ 预设管理器未启用") return False if preset_id not in self.presets: print(f"✗ 预设不存在: {preset_id}") return False # 检查是否为默认预设 if self.presets[preset_id].get('is_default', False): print(f"✗ 无法删除默认预设: {preset_id}") return False # 从内存中删除 del self.presets[preset_id] # 从文件系统中删除 presets_dir = self.preset_config['presets_directory'] filepath = os.path.join(presets_dir, f"{preset_id}.json") if os.path.exists(filepath): os.remove(filepath) # 如果删除的是当前预设,清空当前预设 if self.current_preset == preset_id: self.current_preset = None print(f"✓ 预设 '{preset_id}' 删除完成") return True except Exception as e: print(f"✗ 预设删除失败: {e}") import traceback traceback.print_exc() return False def list_presets(self, category: str = None) -> List[str]: """ 列出预设 Args: category: 预设类别(如果为None,则列出所有预设) Returns: 预设ID列表 """ try: if category is None: return list(self.presets.keys()) else: return [preset_id for preset_id, preset_data in self.presets.items() if preset_data.get('category') == category] except Exception as e: print(f"✗ 预设列表获取失败: {e}") import traceback traceback.print_exc() return [] def get_preset_info(self, preset_id: str) -> Optional[Dict[str, Any]]: """ 获取预设信息 Args: preset_id: 预设ID Returns: 预设信息字典或None """ try: if preset_id not in self.presets: return None preset_data = self.presets[preset_id] return { 'name': preset_data.get('name', preset_id), 'category': preset_data.get('category', 'unknown'), 'description': preset_data.get('description', ''), 'timestamp': preset_data.get('timestamp', 0), 'is_default': preset_data.get('is_default', False), 'parameters_count': len(preset_data.get('parameters', {})) } except Exception as e: print(f"✗ 预设信息获取失败: {e}") import traceback traceback.print_exc() return None def get_preset_categories(self) -> Dict[str, Dict[str, str]]: """ 获取预设类别 Returns: 预设类别字典 """ return self.preset_categories.copy() def create_preset_category(self, category_id: str, name: str, description: str = '') -> bool: """ 创建预设类别 Args: category_id: 类别ID name: 类别名称 description: 类别描述 Returns: 是否创建成功 """ try: self.preset_categories[category_id] = { 'name': name, 'description': description } print(f"✓ 预设类别 '{name}' 创建完成") return True except Exception as e: print(f"✗ 预设类别创建失败: {e}") import traceback traceback.print_exc() return False def export_preset(self, preset_id: str, filepath: str) -> bool: """ 导出预设到文件 Args: preset_id: 预设ID filepath: 导出文件路径 Returns: 是否导出成功 """ try: if preset_id not in self.presets: print(f"✗ 预设不存在: {preset_id}") return False preset_data = self.presets[preset_id] # 保存到指定文件 with open(filepath, 'w', encoding='utf-8') as f: json.dump(preset_data, f, ensure_ascii=False, indent=2) print(f"✓ 预设 '{preset_id}' 导出到 {filepath}") return True except Exception as e: print(f"✗ 预设导出失败: {e}") import traceback traceback.print_exc() return False def import_preset(self, filepath: str, preset_id: str = None) -> bool: """ 从文件导入预设 Args: filepath: 导入文件路径 preset_id: 预设ID(如果为None,则使用文件名) Returns: 是否导入成功 """ try: # 读取预设文件 with open(filepath, 'r', encoding='utf-8') as f: preset_data = json.load(f) # 确定预设ID if preset_id is None: preset_id = os.path.splitext(os.path.basename(filepath))[0] # 保存预设 self.presets[preset_id] = preset_data # 保存到预设目录 presets_dir = self.preset_config['presets_directory'] save_filepath = os.path.join(presets_dir, f"{preset_id}.json") with open(save_filepath, 'w', encoding='utf-8') as f: json.dump(preset_data, f, ensure_ascii=False, indent=2) print(f"✓ 预设从 {filepath} 导入完成,ID: {preset_id}") return True except Exception as e: print(f"✗ 预设导入失败: {e}") import traceback traceback.print_exc() return False def set_preset_config(self, config: Dict[str, Any]): """ 设置预设配置 Args: config: 配置字典 """ self.preset_config.update(config) print(f"✓ 预设配置已更新: {self.preset_config}") def get_stats(self) -> Dict[str, Any]: """ 获取统计信息 Returns: 统计信息字典 """ return self.stats.copy() def reset_stats(self): """重置统计信息""" self.stats = { 'presets_loaded': 0, 'presets_saved': 0, 'presets_applied': 0, 'total_load_time': 0.0, 'total_save_time': 0.0 } print("✓ 预设管理器统计信息已重置") def get_current_preset(self) -> Optional[str]: """ 获取当前预设 Returns: 当前预设ID或None """ return self.current_preset def set_current_preset(self, preset_id: str): """ 设置当前预设 Args: preset_id: 预设ID """ if preset_id in self.presets: self.current_preset = preset_id print(f"✓ 当前预设设置为: {preset_id}") else: print(f"✗ 预设不存在: {preset_id}") def create_terrain_preset_from_current(self, preset_name: str, description: str = '') -> str: """ 从当前配置创建预设 Args: preset_name: 预设名称 description: 预设描述 Returns: 预设ID """ try: # 生成预设ID preset_id = preset_name.lower().replace(' ', '_') # 创建预设数据 preset_data = { 'name': preset_name, 'category': 'mixed', 'description': description, 'parameters': {}, 'timestamp': time.time(), 'is_default': False } # 获取当前配置参数 if self.plugin.vegetation_manager: vm = self.plugin.vegetation_manager preset_data['parameters'].update({ 'environment_factors': vm.get_environment_factors(), 'distribution_config': vm.get_distribution_config() }) if self.plugin.ecosystem_manager: em = self.plugin.ecosystem_manager preset_data['parameters'].update({ 'ecosystem_parameters': em.get_ecosystem_parameters() }) # 保存预设 self.save_preset(preset_id, preset_data) print(f"✓ 从当前配置创建预设: {preset_name}") return preset_id except Exception as e: print(f"✗ 从当前配置创建预设失败: {e}") import traceback traceback.print_exc() return '' def batch_apply_presets(self, preset_ids: List[str]) -> bool: """ 批量应用预设 Args: preset_ids: 预设ID列表 Returns: 是否应用成功 """ try: if not self.enabled: print("✗ 预设管理器未启用") return False success_count = 0 for preset_id in preset_ids: if self.apply_preset(preset_id): success_count += 1 print(f"✓ 批量应用预设完成: {success_count}/{len(preset_ids)} 个预设应用成功") return success_count == len(preset_ids) except Exception as e: print(f"✗ 批量应用预设失败: {e}") import traceback traceback.print_exc() return False def search_presets(self, keyword: str, category: str = None) -> List[str]: """ 搜索预设 Args: keyword: 搜索关键词 category: 预设类别(可选) Returns: 匹配的预设ID列表 """ try: matching_presets = [] for preset_id, preset_data in self.presets.items(): # 检查类别筛选 if category and preset_data.get('category') != category: continue # 检查关键词匹配 if (keyword.lower() in preset_data.get('name', '').lower() or keyword.lower() in preset_data.get('description', '').lower()): matching_presets.append(preset_id) return matching_presets except Exception as e: print(f"✗ 预设搜索失败: {e}") import traceback traceback.print_exc() return [] def duplicate_preset(self, source_preset_id: str, new_preset_id: str, new_name: str = None) -> bool: """ 复制预设 Args: source_preset_id: 源预设ID new_preset_id: 新预设ID new_name: 新预设名称(如果为None,则使用源预设名称) Returns: 是否复制成功 """ try: if source_preset_id not in self.presets: print(f"✗ 源预设不存在: {source_preset_id}") return False # 复制预设数据 preset_data = self.presets[source_preset_id].copy() # 更新名称 if new_name: preset_data['name'] = new_name else: preset_data['name'] = f"{preset_data['name']} (副本)" # 更新时间戳 preset_data['timestamp'] = time.time() # 标记为非默认预设 preset_data['is_default'] = False # 保存新预设 return self.save_preset(new_preset_id, preset_data) except Exception as e: print(f"✗ 预设复制失败: {e}") import traceback traceback.print_exc() return False def update_preset_parameters(self, preset_id: str, parameters: Dict[str, Any]) -> bool: """ 更新预设参数 Args: preset_id: 预设ID parameters: 要更新的参数 Returns: 是否更新成功 """ try: if preset_id not in self.presets: print(f"✗ 预设不存在: {preset_id}") return False # 更新参数 self.presets[preset_id]['parameters'].update(parameters) # 更新时间戳 self.presets[preset_id]['timestamp'] = time.time() # 保存到文件 presets_dir = self.preset_config['presets_directory'] filepath = os.path.join(presets_dir, f"{preset_id}.json") with open(filepath, 'w', encoding='utf-8') as f: json.dump(self.presets[preset_id], f, ensure_ascii=False, indent=2) print(f"✓ 预设 '{preset_id}' 参数更新完成") return True except Exception as e: print(f"✗ 预设参数更新失败: {e}") import traceback traceback.print_exc() return False def get_preset_parameters(self, preset_id: str) -> Optional[Dict[str, Any]]: """ 获取预设参数 Args: preset_id: 预设ID Returns: 参数字典或None """ try: if preset_id not in self.presets: return None return self.presets[preset_id].get('parameters', {}).copy() except Exception as e: print(f"✗ 预设参数获取失败: {e}") import traceback traceback.print_exc() return None def validate_preset(self, preset_id: str) -> bool: """ 验证预设完整性 Args: preset_id: 预设ID Returns: 预设是否有效 """ try: if preset_id not in self.presets: return False preset_data = self.presets[preset_id] # 检查必需字段 required_fields = ['name', 'category', 'parameters'] for field in required_fields: if field not in preset_data: print(f"✗ 预设 '{preset_id}' 缺少必需字段: {field}") return False # 检查类别有效性 if preset_data['category'] not in self.preset_categories: print(f"✗ 预设 '{preset_id}' 包含无效类别: {preset_data['category']}") return False return True except Exception as e: print(f"✗ 预设验证失败: {e}") import traceback traceback.print_exc() return False def backup_presets(self, backup_dir: str = 'presets_backup') -> bool: """ 备份所有预设 Args: backup_dir: 备份目录 Returns: 是否备份成功 """ try: if not os.path.exists(backup_dir): os.makedirs(backup_dir) backup_count = 0 for preset_id, preset_data in self.presets.items(): try: filepath = os.path.join(backup_dir, f"{preset_id}.json") with open(filepath, 'w', encoding='utf-8') as f: json.dump(preset_data, f, ensure_ascii=False, indent=2) backup_count += 1 except Exception as e: print(f"✗ 预设 '{preset_id}' 备份失败: {e}") print(f"✓ 预设备份完成: {backup_count}/{len(self.presets)} 个预设已备份到 {backup_dir}") return True except Exception as e: print(f"✗ 预设备份失败: {e}") import traceback traceback.print_exc() return False def restore_presets(self, backup_dir: str = 'presets_backup') -> bool: """ 从备份恢复预设 Args: backup_dir: 备份目录 Returns: 是否恢复成功 """ try: if not os.path.exists(backup_dir): print(f"✗ 备份目录不存在: {backup_dir}") return False restore_count = 0 for filename in os.listdir(backup_dir): if filename.endswith('.json'): try: filepath = os.path.join(backup_dir, filename) with open(filepath, 'r', encoding='utf-8') as f: preset_data = json.load(f) preset_id = os.path.splitext(filename)[0] self.presets[preset_id] = preset_data restore_count += 1 except Exception as e: print(f"✗ 预设文件 '{filename}' 恢复失败: {e}") print(f"✓ 预设恢复完成: {restore_count} 个预设已从 {backup_dir} 恢复") return True except Exception as e: print(f"✗ 预设恢复失败: {e}") import traceback traceback.print_exc() return False