|
|
@@ -509,7 +509,8 @@ class ConfigManagerGUI:
|
|
|
continue
|
|
|
|
|
|
# 检查参数是否有效
|
|
|
- if param_name in self.param_types:
|
|
|
+ param_types = self.current_mapping.get('param_types', {})
|
|
|
+ if param_name in param_types:
|
|
|
try:
|
|
|
# 优先使用第3列(默认值),如果不存在则使用第2列
|
|
|
param_value = row.iloc[2] if len(row) > 2 and not pd.isna(row.iloc[2]) else row.iloc[1]
|
|
|
@@ -517,7 +518,7 @@ class ConfigManagerGUI:
|
|
|
if pd.isna(param_value):
|
|
|
continue
|
|
|
|
|
|
- param_type = self.param_types[param_name]
|
|
|
+ param_type = param_types[param_name]
|
|
|
if param_type == bool:
|
|
|
config[param_name] = str(param_value).lower() in ['true', '1', 'yes', 'on']
|
|
|
else:
|
|
|
@@ -526,46 +527,66 @@ class ConfigManagerGUI:
|
|
|
continue
|
|
|
|
|
|
elif format_type == 'horizontal':
|
|
|
- # 横向表格:第一行是参数名,下面是数据行
|
|
|
- # 检查第1行是否为描述行
|
|
|
- # 如果第1行的第一个单元格包含描述性文字,则跳过它
|
|
|
- data_start_row = 1
|
|
|
- if len(df) > 1:
|
|
|
- first_cell = str(df.iloc[1, 0]).strip()
|
|
|
- # 如果第1行第一个单元格是描述性文字,则从第2行开始
|
|
|
- if first_cell in ['唯一标识符', '描述', 'description', 'desc']:
|
|
|
- data_start_row = 2
|
|
|
- else:
|
|
|
- data_start_row = 1
|
|
|
- print(f"横向表格解析: 数据起始行={data_start_row}, 总行数={len(df)}")
|
|
|
+ # 横向表格:第一行是参数名(列名),数据从第0行开始
|
|
|
+ print(f"横向表格解析: 总行数={len(df)}")
|
|
|
print(f"表格列名: {list(df.columns)}")
|
|
|
|
|
|
# 打印前几行数据用于调试
|
|
|
- for i in range(min(5, len(df))):
|
|
|
+ for i in range(min(3, len(df))):
|
|
|
print(f"第{i}行数据: {df.iloc[i].to_dict()}")
|
|
|
|
|
|
- # 解析多行数据(如敌人配置、武器配置等)
|
|
|
+ # 检查第0行是否为有效数据行
|
|
|
+ # 如果第0行第一个单元格是描述性文字或空值,则跳过
|
|
|
+ data_start_row = 0
|
|
|
+ if len(df) > 0:
|
|
|
+ first_cell = str(df.iloc[0, 0]).strip().lower()
|
|
|
+ # 跳过描述行、空行或标题行
|
|
|
+ if (first_cell in ['唯一标识符', '描述', 'description', 'desc', 'nan', ''] or
|
|
|
+ first_cell == df.columns[0].lower()):
|
|
|
+ data_start_row = 1
|
|
|
+ print(f"跳过第0行(描述行或标题行): {first_cell}")
|
|
|
+
|
|
|
+ print(f"数据起始行: {data_start_row}")
|
|
|
+
|
|
|
+ # 解析多行数据(如敌人配置、武器配置、关卡配置等)
|
|
|
config_list = []
|
|
|
for i in range(data_start_row, len(df)):
|
|
|
row_config = {}
|
|
|
+ row_has_data = False
|
|
|
+
|
|
|
+ param_types = self.current_mapping.get('param_types', {})
|
|
|
+ print(f"可用的参数类型: {list(param_types.keys())}")
|
|
|
+
|
|
|
for col_idx, col_name in enumerate(df.columns):
|
|
|
param_name = str(col_name).strip()
|
|
|
- if param_name in self.param_types:
|
|
|
+ print(f"检查列名: '{param_name}' 是否在参数类型中")
|
|
|
+ if param_name in param_types:
|
|
|
try:
|
|
|
param_value = df.iloc[i, col_idx]
|
|
|
- if pd.isna(param_value):
|
|
|
+ if pd.isna(param_value) or str(param_value).strip() == '':
|
|
|
+ print(f"跳过空值: {param_name} = {param_value}")
|
|
|
continue
|
|
|
|
|
|
- param_type = self.param_types[param_name]
|
|
|
+ param_type = param_types[param_name]
|
|
|
if param_type == bool:
|
|
|
row_config[param_name] = str(param_value).lower() in ['true', '1', 'yes', 'on']
|
|
|
else:
|
|
|
row_config[param_name] = param_type(param_value)
|
|
|
- except (ValueError, TypeError, IndexError):
|
|
|
+ row_has_data = True
|
|
|
+ print(f"成功转换字段: {param_name} = {param_value} ({param_type})")
|
|
|
+ except (ValueError, TypeError, IndexError) as e:
|
|
|
+ print(f"转换字段 {param_name} 时出错: {e}")
|
|
|
continue
|
|
|
+ else:
|
|
|
+ print(f"字段 '{param_name}' 不在参数类型定义中,跳过")
|
|
|
|
|
|
- if row_config: # 只添加非空配置
|
|
|
+ if row_config and row_has_data: # 只添加非空且有有效数据的配置
|
|
|
config_list.append(row_config)
|
|
|
+ print(f"成功解析第{i}行,包含{len(row_config)}个字段")
|
|
|
+ else:
|
|
|
+ print(f"跳过第{i}行(无有效数据)")
|
|
|
+
|
|
|
+ print(f"总共解析出{len(config_list)}个有效配置项")
|
|
|
|
|
|
# 对于横向表格,返回配置列表
|
|
|
config = {'items': config_list}
|
|
|
@@ -655,17 +676,31 @@ class ConfigManagerGUI:
|
|
|
return
|
|
|
|
|
|
try:
|
|
|
+ print(f"开始导入配置...")
|
|
|
+ print(f"配置数据: {self.config_data}")
|
|
|
+ print(f"当前映射: {self.current_mapping}")
|
|
|
+ print(f"选中文件: {self.selected_files}")
|
|
|
+
|
|
|
format_type = self.current_mapping['format_type']
|
|
|
+ print(f"格式类型: {format_type}")
|
|
|
|
|
|
if format_type == 'vertical':
|
|
|
# 处理纵向表格(如BallController)
|
|
|
+ print("开始处理纵向表格配置...")
|
|
|
self._import_vertical_config()
|
|
|
elif format_type == 'horizontal':
|
|
|
# 处理横向表格(如敌人配置、武器配置)
|
|
|
+ print("开始处理横向表格配置...")
|
|
|
self._import_horizontal_config()
|
|
|
+ else:
|
|
|
+ raise ValueError(f"未知的格式类型: {format_type}")
|
|
|
|
|
|
except Exception as e:
|
|
|
- messagebox.showerror("错误", f"导入配置失败: {str(e)}")
|
|
|
+ import traceback
|
|
|
+ error_details = traceback.format_exc()
|
|
|
+ print(f"导入配置失败,详细错误信息:")
|
|
|
+ print(error_details)
|
|
|
+ messagebox.showerror("错误", f"导入配置失败: {str(e)}\n\n详细错误信息已输出到控制台,请查看。")
|
|
|
|
|
|
def _import_vertical_config(self):
|
|
|
"""导入纵向表格配置"""
|
|
|
@@ -698,73 +733,204 @@ class ConfigManagerGUI:
|
|
|
|
|
|
def _import_horizontal_config(self):
|
|
|
"""导入横向表格配置"""
|
|
|
+ print(f"横向表格配置导入开始...")
|
|
|
+ print(f"配置数据结构: {list(self.config_data.keys()) if self.config_data else 'None'}")
|
|
|
+
|
|
|
if 'items' not in self.config_data:
|
|
|
- messagebox.showwarning("警告", "横向表格数据格式错误")
|
|
|
+ print(f"错误: 配置数据中缺少'items'字段")
|
|
|
+ print(f"实际配置数据: {self.config_data}")
|
|
|
+ messagebox.showwarning("警告", "横向表格数据格式错误:缺少'items'字段")
|
|
|
return
|
|
|
|
|
|
items = self.config_data['items']
|
|
|
+ print(f"配置项数量: {len(items) if items else 0}")
|
|
|
if not items:
|
|
|
messagebox.showwarning("警告", "没有有效的配置项")
|
|
|
return
|
|
|
|
|
|
+ # 打印前几个配置项用于调试
|
|
|
+ for i, item in enumerate(items[:3]):
|
|
|
+ print(f"配置项{i}: {item}")
|
|
|
+
|
|
|
# 读取现有JSON配置
|
|
|
- if self.json_config_path.exists():
|
|
|
- with open(self.json_config_path, 'r', encoding='utf-8') as f:
|
|
|
- current_config = json.load(f)
|
|
|
- else:
|
|
|
+ print(f"JSON配置文件路径: {self.json_config_path}")
|
|
|
+
|
|
|
+ # 检查是否是关卡配置(目录类型)
|
|
|
+ if str(self.json_config_path).endswith('levels'):
|
|
|
+ print("处理关卡配置目录...")
|
|
|
+ # 关卡配置是目录,确保目录存在
|
|
|
+ if not self.json_config_path.exists():
|
|
|
+ print(f"创建关卡配置目录: {self.json_config_path}")
|
|
|
+ self.json_config_path.mkdir(parents=True, exist_ok=True)
|
|
|
current_config = {}
|
|
|
+ else:
|
|
|
+ # 普通JSON文件配置
|
|
|
+ if self.json_config_path.exists():
|
|
|
+ print("读取现有JSON配置文件...")
|
|
|
+ with open(self.json_config_path, 'r', encoding='utf-8') as f:
|
|
|
+ current_config = json.load(f)
|
|
|
+ else:
|
|
|
+ print("创建新的JSON配置...")
|
|
|
+ current_config = {}
|
|
|
|
|
|
# 根据不同的配置类型处理
|
|
|
+ if not self.selected_files:
|
|
|
+ print("错误: 没有选中的文件")
|
|
|
+ messagebox.showerror("错误", "没有选中的文件")
|
|
|
+ return
|
|
|
+
|
|
|
filename = Path(self.selected_files[0]).name
|
|
|
+ print(f"处理文件: {filename}")
|
|
|
|
|
|
if '敌人配置' in filename:
|
|
|
+ print("处理敌人配置...")
|
|
|
# 敌人配置:更新enemies数组
|
|
|
if 'enemies' not in current_config:
|
|
|
current_config['enemies'] = []
|
|
|
|
|
|
# 将Excel数据转换为JSON格式
|
|
|
updated_enemies = []
|
|
|
- for item in items:
|
|
|
+ for i, item in enumerate(items):
|
|
|
+ print(f"转换敌人数据 {i+1}/{len(items)}: {item}")
|
|
|
enemy_data = self._convert_enemy_data(item)
|
|
|
if enemy_data:
|
|
|
updated_enemies.append(enemy_data)
|
|
|
+ print(f"成功转换敌人数据: {enemy_data['id']}")
|
|
|
+ else:
|
|
|
+ print(f"跳过无效的敌人数据: {item}")
|
|
|
|
|
|
+ print(f"总共转换了 {len(updated_enemies)} 个敌人配置")
|
|
|
current_config['enemies'] = updated_enemies
|
|
|
|
|
|
elif '武器配置' in filename:
|
|
|
+ print("处理武器配置...")
|
|
|
# 武器配置:更新weapons数组
|
|
|
if 'weapons' not in current_config:
|
|
|
current_config['weapons'] = []
|
|
|
|
|
|
# 将Excel数据转换为JSON格式
|
|
|
updated_weapons = []
|
|
|
- for item in items:
|
|
|
+ for i, item in enumerate(items):
|
|
|
+ print(f"转换武器数据 {i+1}/{len(items)}: {item}")
|
|
|
weapon_data = self._convert_weapon_data(item)
|
|
|
if weapon_data:
|
|
|
updated_weapons.append(weapon_data)
|
|
|
+ print(f"成功转换武器数据: {weapon_data.get('id', 'Unknown')}")
|
|
|
+ else:
|
|
|
+ print(f"跳过无效的武器数据: {item}")
|
|
|
|
|
|
+ print(f"总共转换了 {len(updated_weapons)} 个武器配置")
|
|
|
current_config['weapons'] = updated_weapons
|
|
|
|
|
|
elif '技能配置' in filename:
|
|
|
+ print("处理技能配置...")
|
|
|
# 技能配置:更新skills数组
|
|
|
if 'skills' not in current_config:
|
|
|
current_config['skills'] = []
|
|
|
|
|
|
# 将Excel数据转换为JSON格式
|
|
|
updated_skills = []
|
|
|
- for item in items:
|
|
|
+ for i, item in enumerate(items):
|
|
|
+ print(f"转换技能数据 {i+1}/{len(items)}: {item}")
|
|
|
skill_data = self._convert_skill_data(item)
|
|
|
if skill_data:
|
|
|
updated_skills.append(skill_data)
|
|
|
+ print(f"成功转换技能数据: {skill_data.get('id', 'Unknown')}")
|
|
|
+ else:
|
|
|
+ print(f"跳过无效的技能数据: {item}")
|
|
|
|
|
|
+ print(f"总共转换了 {len(updated_skills)} 个技能配置")
|
|
|
current_config['skills'] = updated_skills
|
|
|
+
|
|
|
+ elif '关卡配置' in filename:
|
|
|
+ print("处理关卡配置...")
|
|
|
+ # 关卡配置:为每个关卡创建单独的JSON文件
|
|
|
+ levels_dir = self.json_config_path
|
|
|
+ print(f"关卡配置目录: {levels_dir}")
|
|
|
+
|
|
|
+ try:
|
|
|
+ # 检查并创建目录
|
|
|
+ if not levels_dir.exists():
|
|
|
+ print(f"创建关卡配置目录: {levels_dir}")
|
|
|
+ levels_dir.mkdir(parents=True, exist_ok=True)
|
|
|
+ else:
|
|
|
+ print(f"关卡配置目录已存在: {levels_dir}")
|
|
|
+
|
|
|
+ # 测试目录写入权限
|
|
|
+ test_file = levels_dir / "test_permission.tmp"
|
|
|
+ try:
|
|
|
+ with open(test_file, 'w', encoding='utf-8') as f:
|
|
|
+ f.write("test")
|
|
|
+ test_file.unlink() # 删除测试文件
|
|
|
+ except PermissionError:
|
|
|
+ messagebox.showerror("错误", f"没有写入权限到目录: {levels_dir}\n请检查目录权限或以管理员身份运行")
|
|
|
+ return
|
|
|
+
|
|
|
+ # 将Excel数据转换为JSON格式并保存为单独文件
|
|
|
+ updated_count = 0
|
|
|
+ failed_count = 0
|
|
|
+
|
|
|
+ for item in items:
|
|
|
+ try:
|
|
|
+ level_data = self._convert_level_data(item)
|
|
|
+ if level_data and '关卡ID' in item and item['关卡ID']:
|
|
|
+ level_id = item['关卡ID']
|
|
|
+ level_file = levels_dir / f"{level_id}.json"
|
|
|
+
|
|
|
+ print(f"保存关卡配置: {level_file}")
|
|
|
+ with open(level_file, 'w', encoding='utf-8') as f:
|
|
|
+ json.dump(level_data, f, indent=2, ensure_ascii=False)
|
|
|
+ updated_count += 1
|
|
|
+ else:
|
|
|
+ print(f"跳过无效的关卡数据: {item}")
|
|
|
+ failed_count += 1
|
|
|
+ except Exception as e:
|
|
|
+ print(f"保存关卡配置时出错: {e}")
|
|
|
+ failed_count += 1
|
|
|
+ continue
|
|
|
+
|
|
|
+ if updated_count > 0:
|
|
|
+ message = f"关卡配置导入成功!\n更新了 {updated_count} 个关卡文件"
|
|
|
+ if failed_count > 0:
|
|
|
+ message += f"\n跳过了 {failed_count} 个无效配置"
|
|
|
+ messagebox.showinfo("成功", message)
|
|
|
+ self.status_var.set("关卡配置导入成功")
|
|
|
+ else:
|
|
|
+ messagebox.showerror("错误", "没有成功导入任何关卡配置\n请检查Excel文件格式和数据")
|
|
|
+ self.status_var.set("关卡配置导入失败")
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ error_msg = f"关卡配置导入失败: {str(e)}"
|
|
|
+ print(error_msg)
|
|
|
+ messagebox.showerror("错误", error_msg)
|
|
|
+ self.status_var.set("关卡配置导入失败")
|
|
|
+
|
|
|
+ self.clear_selection()
|
|
|
+ return
|
|
|
|
|
|
- # 写入更新后的配置
|
|
|
- with open(self.json_config_path, 'w', encoding='utf-8') as f:
|
|
|
- json.dump(current_config, f, indent=2, ensure_ascii=False)
|
|
|
+ else:
|
|
|
+ # 未知配置类型
|
|
|
+ print(f"警告: 未知的配置文件类型: {filename}")
|
|
|
+ messagebox.showwarning("警告", f"未知的配置文件类型: {filename}\n支持的类型: 敌人配置、武器配置、技能配置、关卡配置")
|
|
|
+ return
|
|
|
|
|
|
- messagebox.showinfo("成功", f"配置导入成功!\n更新了 {len(items)} 个配置项")
|
|
|
- self.status_var.set("配置导入成功")
|
|
|
+ # 写入更新后的配置(关卡配置已在前面处理,跳过)
|
|
|
+ if not str(self.json_config_path).endswith('levels'):
|
|
|
+ try:
|
|
|
+ print(f"写入配置文件: {self.json_config_path}")
|
|
|
+ print(f"配置内容预览: {str(current_config)[:200]}...")
|
|
|
+
|
|
|
+ with open(self.json_config_path, 'w', encoding='utf-8') as f:
|
|
|
+ json.dump(current_config, f, indent=2, ensure_ascii=False)
|
|
|
+
|
|
|
+ print("配置文件写入成功")
|
|
|
+ messagebox.showinfo("成功", f"配置导入成功!\n更新了 {len(items)} 个配置项")
|
|
|
+ self.status_var.set("配置导入成功")
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ print(f"写入配置文件失败: {e}")
|
|
|
+ messagebox.showerror("错误", f"写入配置文件失败: {str(e)}")
|
|
|
+ return
|
|
|
|
|
|
# 刷新预览
|
|
|
self.clear_selection()
|
|
|
@@ -772,8 +938,10 @@ class ConfigManagerGUI:
|
|
|
def _convert_enemy_data(self, item):
|
|
|
"""转换敌人数据格式"""
|
|
|
try:
|
|
|
+ print(f"开始转换敌人数据: {item}")
|
|
|
enemy_id = item.get('敌人ID', '')
|
|
|
- print(f"正在转换敌人数据: {enemy_id} - {item.get('敌人名称', '')}")
|
|
|
+ enemy_name = item.get('敌人名称', '')
|
|
|
+ print(f"敌人ID: {enemy_id}, 敌人名称: {enemy_name}")
|
|
|
|
|
|
# 检查必要字段
|
|
|
if not enemy_id:
|
|
|
@@ -803,9 +971,14 @@ class ConfigManagerGUI:
|
|
|
def _convert_weapon_data(self, item):
|
|
|
"""转换武器数据格式"""
|
|
|
try:
|
|
|
- return {
|
|
|
- 'id': item.get('ID', ''),
|
|
|
- 'name': item.get('名称', ''),
|
|
|
+ print(f"开始转换武器数据: {item}")
|
|
|
+ weapon_id = item.get('ID', '')
|
|
|
+ weapon_name = item.get('名称', '')
|
|
|
+ print(f"武器ID: {weapon_id}, 武器名称: {weapon_name}")
|
|
|
+
|
|
|
+ result = {
|
|
|
+ 'id': weapon_id,
|
|
|
+ 'name': weapon_name,
|
|
|
'type': item.get('类型', ''),
|
|
|
'rarity': item.get('稀有度', ''),
|
|
|
'weight': item.get('权重', 1),
|
|
|
@@ -814,8 +987,10 @@ class ConfigManagerGUI:
|
|
|
'range': item.get('射程', 100),
|
|
|
'bulletSpeed': item.get('子弹速度', 100)
|
|
|
}
|
|
|
+ print(f"成功转换武器数据: {result}")
|
|
|
+ return result
|
|
|
except Exception as e:
|
|
|
- print(f"转换武器数据失败: {e}")
|
|
|
+ print(f"转换武器数据失败: {e} - 数据: {item}")
|
|
|
return None
|
|
|
|
|
|
def _convert_skill_data(self, item):
|
|
|
@@ -850,6 +1025,31 @@ class ConfigManagerGUI:
|
|
|
print(f"转换技能数据失败: {e} - 数据: {item}")
|
|
|
return None
|
|
|
|
|
|
+ def _convert_level_data(self, item):
|
|
|
+ """转换关卡数据格式"""
|
|
|
+ try:
|
|
|
+ # 处理可用武器字符串,转换为数组
|
|
|
+ available_weapons = []
|
|
|
+ if '可用武器' in item and item['可用武器']:
|
|
|
+ weapons_str = str(item['可用武器'])
|
|
|
+ available_weapons = [weapon.strip() for weapon in weapons_str.split(',')]
|
|
|
+
|
|
|
+ return {
|
|
|
+ "levelId": str(item.get('关卡ID', '')),
|
|
|
+ "name": str(item.get('关卡名称', '')),
|
|
|
+ "scene": str(item.get('场景', '')),
|
|
|
+ "description": str(item.get('描述', '')),
|
|
|
+ "weapons": available_weapons,
|
|
|
+ "timeLimit": int(item.get('时间限制', 300)),
|
|
|
+ "difficulty": str(item.get('难度', 'normal')),
|
|
|
+ "healthMultiplier": float(item.get('生命倍数', 1.0)),
|
|
|
+ "coinReward": int(item.get('金币奖励', 0)),
|
|
|
+ "diamondReward": int(item.get('钻石奖励', 0))
|
|
|
+ }
|
|
|
+ except Exception as e:
|
|
|
+ print(f"转换关卡数据时出错: {e}")
|
|
|
+ return None
|
|
|
+
|
|
|
def restore_default_config(self):
|
|
|
"""恢复默认配置"""
|
|
|
result = messagebox.askyesno("确认", "确定要恢复默认配置吗?\n当前配置将被覆盖!")
|