| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- #!/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()
|