| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- BallController配置管理器
- 从config_manager.py中提取的BallController相关配置管理功能
- 支持从Excel读取BallController配置并与现有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 BallControllerConfigManager:
- """BallController配置管理器"""
-
- def __init__(self, excel_file_path=None, json_file_path=None):
- """初始化BallController配置管理器
-
- 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 / "BallController标准配置表.xlsx"
- else:
- self.excel_file = Path(excel_file_path)
-
- if json_file_path is None:
- self.json_file = self.script_dir.parent / "ballController.json"
- else:
- self.json_file = Path(json_file_path)
-
- print(f"Excel文件路径: {self.excel_file}")
- print(f"JSON文件路径: {self.json_file}")
-
- # BallController配置映射
- self.ball_controller_mapping = {
- 'format_type': 'vertical',
- 'param_types': {
- 'baseSpeed': float,
- 'maxReflectionRandomness': float,
- 'antiTrapTimeWindow': int,
- 'antiTrapHitThreshold': int,
- 'deflectionAttemptThreshold': int,
- 'antiTrapDeflectionMultiplier': int,
- 'FIRE_COOLDOWN': float,
- 'ballRadius': int,
- 'gravityScale': int,
- 'linearDamping': int,
- 'angularDamping': int,
- 'colliderGroup': int,
- 'colliderTag': int,
- 'friction': int,
- 'restitution': int,
- 'safeDistance': int,
- 'edgeOffset': int,
- 'sensor': bool,
- 'maxAttempts': int
- }
- }
-
- 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配置,包含 {len(config)} 个参数")
- return config
- else:
- print(f"JSON文件不存在,将创建新配置: {self.json_file}")
- return {}
- except Exception as e:
- print(f"加载JSON配置失败: {e}")
- return {}
-
- 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文件
- df = pd.read_excel(self.excel_file)
- print(f"成功读取Excel文件,包含 {len(df)} 行数据")
- return df
- except Exception as e:
- raise Exception(f"读取Excel文件失败: {e}")
-
- def parse_ball_controller_data(self, df):
- """解析BallController配置数据"""
- try:
- config = {}
-
- # 检查数据格式 - 纵向表格格式(参数名在第一列,数值在第二列)
- for index, row in df.iterrows():
- if len(row) >= 2:
- param_name = str(row.iloc[0]).strip()
- param_value = row.iloc[1]
-
- # 跳过表头行
- if param_name in ['参数名', 'Parameter', 'Name']:
- continue
-
- # 根据映射转换数据类型
- if param_name in self.ball_controller_mapping['param_types']:
- param_type = self.ball_controller_mapping['param_types'][param_name]
- try:
- if param_type == bool:
- # 处理布尔值
- if isinstance(param_value, str):
- config[param_name] = param_value.lower() in ['true', '1', 'yes', 'on']
- else:
- config[param_name] = bool(param_value)
- elif param_type == int:
- config[param_name] = int(float(param_value))
- elif param_type == float:
- config[param_name] = float(param_value)
- else:
- config[param_name] = str(param_value).strip()
- except (ValueError, TypeError):
- print(f"警告: 参数 {param_name} 的值 {param_value} 无法转换为 {param_type.__name__},使用字符串类型")
- config[param_name] = str(param_value).strip()
- else:
- # 未知参数,尝试自动推断类型
- try:
- if str(param_value).lower() in ['true', 'false']:
- config[param_name] = str(param_value).lower() == 'true'
- elif '.' in str(param_value):
- config[param_name] = float(param_value)
- else:
- config[param_name] = int(float(param_value))
- except (ValueError, TypeError):
- config[param_name] = str(param_value).strip()
-
- print(f"成功解析 {len(config)} 个BallController参数")
- return config
-
- except Exception as e:
- print(f"解析BallController配置数据失败: {e}")
- return {}
-
- def merge_ball_controller_configs(self, existing_config, excel_config):
- """合并现有配置和Excel配置"""
- try:
- # 创建合并后的配置
- merged_config = existing_config.copy()
-
- # 更新或添加Excel中的配置
- for key, value in excel_config.items():
- if key in merged_config:
- print(f"更新参数: {key} = {value} (原值: {merged_config[key]})")
- else:
- print(f"添加参数: {key} = {value}")
- merged_config[key] = value
-
- print(f"配置合并完成,共 {len(merged_config)} 个参数")
- 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_ball_controller_config(self):
- """导入BallController配置的主方法"""
- try:
- print("开始导入BallController配置...")
-
- # 1. 加载现有JSON配置
- existing_config = self.load_existing_json_config()
-
- # 2. 读取Excel配置
- excel_df = self.read_excel_config()
-
- # 3. 解析Excel数据
- excel_config = self.parse_ball_controller_data(excel_df)
-
- # 4. 合并配置
- merged_config = self.merge_ball_controller_configs(existing_config, excel_config)
-
- # 5. 备份现有配置
- self.backup_json_config()
-
- # 6. 保存新配置
- if self.save_json_config(merged_config):
- print("BallController配置导入成功!")
- return True
- else:
- print("BallController配置保存失败!")
- return False
-
- except Exception as e:
- print(f"导入BallController配置失败: {e}")
- return False
- def main():
- """主函数"""
- print("BallController配置管理器")
- print("=" * 50)
-
- # 创建BallController配置管理器
- manager = BallControllerConfigManager()
-
- # 导入配置
- success = manager.import_ball_controller_config()
-
- if success:
- print("\n✓ BallController配置导入完成")
- else:
- print("\n✗ BallController配置导入失败")
- if __name__ == "__main__":
- main()
|