#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 技能配置管理器 从config_manager.py中提取的局外技能配置相关管理功能 支持从Excel读取局外技能配置并与现有JSON配置合并 """ import json import os from pathlib import Path from datetime import datetime try: import pandas as pd PANDAS_AVAILABLE = True except ImportError: PANDAS_AVAILABLE = False print("警告: pandas未安装,无法处理Excel文件") class SkillConfigManager: """技能配置管理器""" def __init__(self, excel_file_path=None, json_file_path=None): """初始化技能配置管理器 Args: excel_file_path: Excel配置文件路径 json_file_path: JSON配置文件路径 """ self.script_dir = Path(__file__).parent # 设置默认路径 if excel_file_path is None: self.excel_file = self.script_dir / "局外技能配置表.xlsx" else: self.excel_file = Path(excel_file_path) if json_file_path is None: self.json_file = self.script_dir.parent / "skill_config.json" else: self.json_file = Path(json_file_path) print(f"Excel文件路径: {self.excel_file}") print(f"JSON文件路径: {self.json_file}") # 默认配置结构 self.default_config = { "skillTypes": [], "skillGroups": [], "totalGroups": 12, "skillsPerGroup": 3 } def load_existing_json_config(self): """加载现有的JSON配置文件""" try: if self.json_file.exists(): with open(self.json_file, 'r', encoding='utf-8') as f: config = json.load(f) print(f"成功加载现有JSON配置") return config else: print(f"JSON文件不存在,将创建新配置: {self.json_file}") return self.default_config.copy() except Exception as e: print(f"加载JSON配置失败: {e}") return self.default_config.copy() def read_excel_config(self): """读取Excel配置文件""" if not PANDAS_AVAILABLE: raise Exception("pandas未安装,无法读取Excel文件") if not self.excel_file.exists(): raise Exception(f"Excel文件不存在: {self.excel_file}") try: # 读取所有工作表 excel_data = pd.read_excel(self.excel_file, sheet_name=None) print(f"成功读取Excel文件,包含工作表: {list(excel_data.keys())}") return excel_data except Exception as e: raise Exception(f"读取Excel文件失败: {e}") def parse_skill_types(self, df): """解析技能类型配置""" skill_types = [] try: for index, row in df.iterrows(): # 跳过表头,但允许ID为0的有效数据 if index == 0 and str(row.iloc[0]).strip() in ['ID', 'id', '技能类型ID']: continue # 检查是否为有效数据行 if pd.isna(row.iloc[0]) or str(row.iloc[0]).strip() == '': continue skill_type = { "id": int(row.iloc[0]) if pd.notna(row.iloc[0]) else 0, "name": str(row.iloc[1]).strip() if pd.notna(row.iloc[1]) else "", "displayName": str(row.iloc[2]).strip() if pd.notna(row.iloc[2]) else "", "nameTemplate": str(row.iloc[3]).strip() if pd.notna(row.iloc[3]) else "", "type": str(row.iloc[4]).strip() if pd.notna(row.iloc[4]) else "" } skill_types.append(skill_type) print(f"解析到 {len(skill_types)} 个技能类型") return skill_types except Exception as e: print(f"解析技能类型失败: {e}") return [] def parse_skill_groups(self, df): """解析技能组配置""" skill_groups = [] try: for index, row in df.iterrows(): # 跳过表头,但允许group为1的有效数据 if index == 0 and str(row.iloc[0]).strip() in ['组别', 'group', '技能组']: continue # 检查是否为有效数据行 if pd.isna(row.iloc[0]) or str(row.iloc[0]).strip() == '': continue skill_group = { "group": int(row.iloc[0]) if pd.notna(row.iloc[0]) else 0, "effectPercent": int(row.iloc[1]) if pd.notna(row.iloc[1]) else 0, "diamondCost": int(row.iloc[2]) if pd.notna(row.iloc[2]) else 0 } skill_groups.append(skill_group) print(f"解析到 {len(skill_groups)} 个技能组") return skill_groups except Exception as e: print(f"解析技能组失败: {e}") return [] def parse_basic_config(self, df): """解析基本配置""" basic_config = {} try: for index, row in df.iterrows(): # 跳过表头 if index == 0 or str(row.iloc[0]).strip() in ['配置项', 'config']: continue config_name = str(row.iloc[0]).strip() config_value = row.iloc[1] if config_name == '总组数': basic_config['totalGroups'] = int(config_value) if pd.notna(config_value) else 12 elif config_name == '每组技能数': basic_config['skillsPerGroup'] = int(config_value) if pd.notna(config_value) else 3 print(f"解析基本配置: {basic_config}") return basic_config except Exception as e: print(f"解析基本配置失败: {e}") return {} def parse_skill_config_data(self, excel_data): """解析技能配置数据""" try: config = self.default_config.copy() # 读取技能类型配置 if "技能类型配置" in excel_data: skill_types = self.parse_skill_types(excel_data["技能类型配置"]) config["skillTypes"] = skill_types elif "JSON技能类型配置" in excel_data: skill_types = self.parse_skill_types(excel_data["JSON技能类型配置"]) config["skillTypes"] = skill_types # 读取技能组配置 if "技能组配置" in excel_data: skill_groups = self.parse_skill_groups(excel_data["技能组配置"]) config["skillGroups"] = skill_groups # 读取基本配置 if "基本配置" in excel_data: basic_config = self.parse_basic_config(excel_data["基本配置"]) config.update(basic_config) return config except Exception as e: print(f"解析技能配置数据失败: {e}") return self.default_config.copy() def validate_config(self, config): """验证配置数据""" try: # 检查必要字段 required_fields = ['skillTypes', 'skillGroups', 'totalGroups', 'skillsPerGroup'] for field in required_fields: if field not in config: print(f"警告: 缺少必要字段 {field}") return False # 检查技能类型 if not isinstance(config['skillTypes'], list): print("错误: skillTypes 必须是列表") return False # 检查技能组 if not isinstance(config['skillGroups'], list): print("错误: skillGroups 必须是列表") return False print("配置验证通过") return True except Exception as e: print(f"配置验证失败: {e}") return False def merge_skill_configs(self, existing_config, excel_config): """合并现有配置和Excel配置""" try: # 创建合并后的配置,保持原有结构 merged_config = existing_config.copy() # 确保保持原有的skills数组(如果存在) if 'skills' not in merged_config: merged_config['skills'] = [] # 更新技能类型,保持原有格式 if 'skillTypes' in excel_config and excel_config['skillTypes']: merged_config['skillTypes'] = excel_config['skillTypes'] print(f"更新技能类型配置,共 {len(excel_config['skillTypes'])} 个类型") # 更新技能组,保持原有格式 if 'skillGroups' in excel_config and excel_config['skillGroups']: merged_config['skillGroups'] = excel_config['skillGroups'] print(f"更新技能组配置,共 {len(excel_config['skillGroups'])} 个组") # 更新基本配置,保持原有字段 if 'totalGroups' in excel_config: merged_config['totalGroups'] = excel_config['totalGroups'] print(f"更新总组数: {excel_config['totalGroups']}") if 'skillsPerGroup' in excel_config: merged_config['skillsPerGroup'] = excel_config['skillsPerGroup'] print(f"更新每组技能数: {excel_config['skillsPerGroup']}") print("配置合并完成") return merged_config except Exception as e: print(f"合并配置失败: {e}") return existing_config def backup_json_config(self): """备份现有JSON配置""" try: if self.json_file.exists(): timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") backup_file = self.json_file.parent / f"{self.json_file.stem}_backup_{timestamp}.json" with open(self.json_file, 'r', encoding='utf-8') as src: with open(backup_file, 'w', encoding='utf-8') as dst: dst.write(src.read()) print(f"配置已备份到: {backup_file}") return backup_file else: print("JSON文件不存在,无需备份") return None except Exception as e: print(f"备份配置失败: {e}") return None def save_json_config(self, config): """保存配置到JSON文件""" try: # 确保目录存在 self.json_file.parent.mkdir(parents=True, exist_ok=True) with open(self.json_file, 'w', encoding='utf-8') as f: json.dump(config, f, ensure_ascii=False, indent=2) print(f"配置已保存到: {self.json_file}") return True except Exception as e: print(f"保存JSON文件失败: {e}") return False def import_skill_config(self): """导入技能配置的主方法""" try: print("开始导入技能配置...") # 1. 加载现有JSON配置 existing_config = self.load_existing_json_config() # 2. 读取Excel配置 excel_data = self.read_excel_config() # 3. 解析Excel数据 excel_config = self.parse_skill_config_data(excel_data) # 4. 验证配置 if not self.validate_config(excel_config): print("配置验证失败,使用默认配置") excel_config = self.default_config.copy() # 5. 合并配置 merged_config = self.merge_skill_configs(existing_config, excel_config) # 6. 备份现有配置 self.backup_json_config() # 7. 保存新配置 if self.save_json_config(merged_config): print("技能配置导入成功!") return True, "技能配置导入成功" else: print("技能配置保存失败!") return False, "技能配置保存失败" except Exception as e: error_msg = f"导入技能配置失败: {e}" print(error_msg) return False, error_msg def main(): """主函数""" print("技能配置管理器") print("=" * 50) # 创建技能配置管理器 manager = SkillConfigManager() # 导入配置 success, message = manager.import_skill_config() if success: print(f"\n✓ {message}") else: print(f"\n✗ {message}") if __name__ == "__main__": main()