---
title: 可视化配置文件
order: 2
---

## 概述

本系统提供了一套完整的游戏配置文件可视化编辑解决方案，支持多种配置文件格式的解析、编辑和保存。系统由**后端解析器**、**前端可视化组件**和**配置模板**三部分组成。

## 系统架构

::: tabs
@tab 后端解析器
- 负责配置文件的读取、解析和保存，基于 TypeScript 实现。
- 支持多种解析器：
  - **configobj**（INI 格式，默认）
  - **yaml/ruamel.yaml**（YAML 格式）
  - **properties**（Java Properties 格式）
  - **json**（JSON 格式）
- ⚠️ 当前不支持 HOCON 和 TOML，如需支持需自行扩展。

@tab 前端组件
- 提供用户友好的可视化编辑界面。
- 支持双列布局（左侧说明，右侧输入控件）、多种输入类型、嵌套字段、表单验证和类型转换。

@tab 配置模板
- 使用 `.yml` 文件定义配置结构、字段类型和默认值。
- 模板自动检测路径：
  1. `data/gameconfig/`（打包路径）
  2. `server/data/gameconfig/`（开发环境）
  3. `../server/data/gameconfig/`（其他情况）
:::

## 核心类与接口

### GameConfigManager 主要方法

- `getAvailableGameConfigs()`：获取所有可用的游戏配置模板
- `getGameConfigSchema(gameName: string)`：获取指定游戏的配置模板
- `readGameConfig(serverPath: string, configSchema: GameConfigSchema)`：读取配置文件
- `saveGameConfig(serverPath: string, configSchema: GameConfigSchema, configData: ParsedConfigData)`：保存配置文件
- `getDefaultValues(configSchema: GameConfigSchema)`：获取默认值

### 主要接口定义

```typescript
interface GameConfigField {
  name: string
  display: string
  default: any
  type: 'string' | 'number' | 'boolean' | 'select' | 'nested'
  description?: string
  options?: Array<{ value: any; label: string }>
  nested_fields?: GameConfigField[]
}

interface GameConfigSection {
  key: string
  fields: GameConfigField[]
}

interface GameConfigMeta {
  game_name: string
  config_file: string
  parser?: string
}

interface GameConfigSchema {
  meta: GameConfigMeta
  sections: GameConfigSection[]
}
```

## 添加新游戏配置支持

### 1. 创建配置模板文件

在 `server/data/gameconfig/` 目录下创建新的 YAML 模板文件，命名格式：`游戏名称.yml`

::: tip
系统会自动扫描该目录下所有 `.yml` 和 `.yaml` 文件，并缓存模板以提升性能。
:::

#### 模板文件结构示例

```yaml
meta:
  game_name: "游戏显示名称"
  config_file: "相对于服务器根目录的配置文件路径"
  parser: "解析器类型" # 可选，默认为 configobj

sections:
  - key: "配置文件中的 section 名称"
    fields:
      - name: "字段名称"
        display: "显示名称"
        default: 默认值
        type: "字段类型"
        description: "字段描述"
        options: # 仅 type 为 select 时需要
          - value: "选项值"
            label: "选项显示名称"
```

#### 支持的字段类型

- `string`：文本输入框
- `number`：数字输入框
- `boolean`：开关控件
- `select`：下拉选择框（需配置 options）
- `nested`：嵌套字段，包含多个子字段

#### 嵌套字段示例

```yaml
- name: "OptionSettings"
  display: "选项设置"
  type: "nested"
  description: "嵌套的选项设置"
  nested_fields:
    - name: "Difficulty"
      display: "游戏难度"
      default: "None"
      type: "select"
      options:
        - value: "None"
          label: "默认"
        - value: "Easy"
          label: "简单"
    - name: "ExpRate"
      display: "经验倍率"
      default: 1.0
      type: "number"
      description: "玩家获得经验的倍率"
```

### 2. 配置解析器选择

根据目标游戏配置文件格式选择解析器：

- INI 格式（推荐，默认）：
  ```yaml
  meta:
    parser: "configobj"
  ```
- YAML 格式：
  ```yaml
  meta:
    parser: "yaml"
  # 或
  meta:
    parser: "ruamel.yaml"
  ```
- Properties 格式：
  ```yaml
  meta:
    parser: "properties"
  ```
- JSON 格式：
  ```yaml
  meta:
    parser: "json"
  ```

::: warning
如未指定 `parser` 字段，系统默认使用 configobj。
:::

### 3. 测试配置

1. 重启后端服务
2. 前端界面选择新添加的游戏配置
3. 测试读取、编辑和保存功能

## 特殊配置处理

### 嵌套字段的数据格式

- 读取时：将括号格式字符串解析为键值对对象
- 保存时：将表单数据组合为原始格式
- 显示时：每个子字段独立显示和编辑

```typescript
// 示例：将 "(Difficulty=None,ExpRate=1.0)" 解析为对象
{
  "Difficulty": "None",
  "ExpRate": 1.0
}
```

### JSON 格式特殊处理

- 读取：直接解析 JSON 对象结构，保持原有类型
- 保存：格式化为 JSON 字符串，2 空格缩进

```json
{
  "server": {
    "port": 8080,
    "name": "My Game Server",
    "options": {
      "difficulty": "normal",
      "max_players": 20,
      "pvp": true
    }
  }
}
```

### 数据类型转换

- 布尔值：`"true"/"false"` 或 `"1"/"0"` → `true/false`
- 数字：字符串 → 数值类型（失败返回 0）
- 字符串：保持原样

## 前端组件扩展

### 新增输入控件类型

在 `GameConfigManager.tsx` 的 `renderInputComponent` 函数中扩展：

```typescript
else if (fieldType === 'custom_type') {
  inputComponent = <CustomComponent style={{ textAlign: 'center' }} />;
}
```

### 自定义样式

采用双列布局，可通过样式自定义：

```typescript
// 左侧信息列
<Col span={12} style={{ 
  display: 'flex', 
  flexDirection: 'column', 
  justifyContent: 'center' 
}}>

// 右侧输入列
<Col span={12} style={{ 
  display: 'flex', 
  justifyContent: 'center', 
  alignItems: 'center' 
}}>
```

## 后端解析器扩展

### 添加新解析器

1. 在 `GameConfigManager` 构造函数注册：

```typescript
this.supportedParsers = new Map([
  ['properties', this.parseWithProperties.bind(this)],
  ['configobj', this.parseWithConfigObj.bind(this)],
  ['yaml', this.parseWithYaml.bind(this)],
  ['ruamel.yaml', this.parseWithYaml.bind(this)],
  ['json', this.parseWithJson.bind(this)],
  ['new_parser', this.parseWithNewParser.bind(this)] // 新增解析器
])
```

2. 实现解析方法：

```typescript
private async parseWithNewParser(configPath: string, configSchema: GameConfigSchema): Promise<ParsedConfigData> {
  try {
    // 实现解析逻辑
    const content = await fs.readFile(configPath, 'utf-8')
    // ... 解析逻辑
    return result
  } catch (error) {
    logger.error('新解析器解析失败:', error)
    throw error
  }
}
```

3. 在 `saveGameConfig` 方法添加保存逻辑：

```typescript
switch (parserType) {
  case 'properties':
    await this.saveWithProperties(fullConfigPath, configData, configSchema)
    break
  // ... 其他 case
  case 'new_parser':
    await this.saveWithNewParser(fullConfigPath, configData, configSchema)
    break
  default:
    throw new Error(`不支持的解析器类型: ${parserType}`)
}
```

4. 实现保存方法：

```typescript
private async saveWithNewParser(configPath: string, configData: ParsedConfigData, configSchema: GameConfigSchema): Promise<void> {
  // 实现保存逻辑
  const content = this.formatConfigData(configData, configSchema)
  await fs.writeFile(configPath, content, 'utf-8')
}
```

## 错误处理与日志

- 配置文件不存在、解析器不支持、文件解析失败、保存失败均有详细报错
- 日志记录 INFO/WARN/ERROR/DEBUG，便于排查
- 配置模板缓存机制，提升性能

## 常见问题与解决方案

::: details 配置文件读取失败
- 路径不正确、文件不存在、权限问题、解析器不匹配
- 检查路径、权限、解析器类型，查看日志
:::

::: details 嵌套字段显示异常
- 模板 `nested_fields` 配置不正确、数据格式异常、类型定义错误
- 检查模板结构和字段类型
:::

::: details 保存后配置无效
- 数据格式不符、类型转换错误、权限问题
- 检查保存格式、类型转换、写入权限
:::

::: details 配置模板加载失败
- YAML 格式错误、路径不对、编码问题
- 使用 YAML 校验工具，检查目录和编码
:::

## 最佳实践

- 字段描述清晰、默认值合理、数值字段标注范围、显示名称友好
- 优先用成熟解析器，匹配格式，关注性能
- 模板提供 fallback 默认值，优雅降级，详细日志
- 前端表单验证、显示说明、支持重置
- TypeScript 类型定义、统一代码风格、详细注释、依赖常更新
- 缓存机制、异步文件操作、内存优化

## 示例：Minecraft 配置模板

```yaml
meta:
  game_name: "Minecraft服务器"
  config_file: "server.properties"
  parser: "properties"

sections:
  - key: "server"
    fields:
      - name: "server-port"
        display: "服务器端口"
        default: 25565
        type: "number"
        description: "服务器监听端口，范围1024-65535"
      - name: "max-players"
        display: "最大玩家数"
        default: 20
        type: "number"
        description: "服务器最大同时在线玩家数"
      - name: "gamemode"
        display: "游戏模式"
        default: "survival"
        type: "select"
        options:
          - value: "survival"
            label: "生存模式"
          - value: "creative"
            label: "创造模式"
          - value: "adventure"
            label: "冒险模式"
          - value: "spectator"
            label: "观察者模式"
        description: "默认游戏模式"
      - name: "pvp"
        display: "PVP模式"
        default: true
        type: "boolean"
        description: "是否启用玩家对战"
```

## 示例：JSON 格式游戏配置

```yaml
meta:
  game_name: "示例JSON游戏"
  config_file: "config.json"
  parser: "json"

sections:
  - key: "server"
    fields:
      - name: "port"
        display: "服务器端口"
        default: 8080
        type: "number"
        description: "服务器监听端口"
      - name: "name"
        display: "服务器名称"
        default: "My Game Server"
        type: "string"
        description: "服务器显示名称"
      - name: "settings"
        display: "游戏设置"
        type: "nested"
        description: "嵌套的游戏设置"
        nested_fields:
          - name: "difficulty"
            display: "难度"
            default: "normal"
            type: "select"
            options:
              - value: "easy"
                label: "简单"
              - value: "normal"
                label: "普通"
              - value: "hard"
                label: "困难"
          - name: "max_players"
            display: "最大玩家数"
            default: 10
            type: "number"
```

对应 JSON 配置文件：

```json
{
  "server": {
    "port": 8080,
    "name": "My Game Server",
    "settings": {
      "difficulty": "normal",
      "max_players": 10
    }
  }
}
```

## 依赖库说明

- **yaml**：YAML 文件解析与生成
- **properties-reader**：Java Properties 文件解析
- **fs/promises**：异步文件系统操作

如需添加新解析器，请在 `package.json` 添加依赖。

---

通过本页文档，开发者可快速为新游戏添加配置文件可视化支持。模块化设计便于扩展解析器和模板，正确配置模板、选择解析器并遵循最佳实践可保障系统稳定与体验。