GameServerManager/server/data/gameconfig/可视化配置文件.md
2025-09-08 23:14:40 +08:00

11 KiB
Raw Permalink Blame History

title order
可视化配置文件 2

概述

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

系统架构

::: tabs @tab 后端解析器

  • 负责配置文件的读取、解析和保存,基于 TypeScript 实现。
  • 支持多种解析器:
    • configobjINI 格式,默认)
    • yaml/ruamel.yamlYAML 格式)
    • propertiesJava Properties 格式)
    • jsonJSON 格式)
  • ⚠️ 当前不支持 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):获取默认值

主要接口定义

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 文件,并缓存模板以提升性能。 :::

模板文件结构示例

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:嵌套字段,包含多个子字段

嵌套字段示例

- 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 格式(推荐,默认):
    meta:
      parser: "configobj"
    
  • YAML 格式:
    meta:
      parser: "yaml"
    # 或
    meta:
      parser: "ruamel.yaml"
    
  • Properties 格式:
    meta:
      parser: "properties"
    
  • JSON 格式:
    meta:
      parser: "json"
    

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

3. 测试配置

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

特殊配置处理

嵌套字段的数据格式

  • 读取时:将括号格式字符串解析为键值对对象
  • 保存时:将表单数据组合为原始格式
  • 显示时:每个子字段独立显示和编辑
// 示例:将 "(Difficulty=None,ExpRate=1.0)" 解析为对象
{
  "Difficulty": "None",
  "ExpRate": 1.0
}

JSON 格式特殊处理

  • 读取:直接解析 JSON 对象结构,保持原有类型
  • 保存:格式化为 JSON 字符串2 空格缩进
{
  "server": {
    "port": 8080,
    "name": "My Game Server",
    "options": {
      "difficulty": "normal",
      "max_players": 20,
      "pvp": true
    }
  }
}

数据类型转换

  • 布尔值:"true"/"false""1"/"0"true/false
  • 数字:字符串 → 数值类型(失败返回 0
  • 字符串:保持原样

前端组件扩展

新增输入控件类型

GameConfigManager.tsxrenderInputComponent 函数中扩展:

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

自定义样式

采用双列布局,可通过样式自定义:

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

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

后端解析器扩展

添加新解析器

  1. GameConfigManager 构造函数注册:
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)] // 新增解析器
])
  1. 实现解析方法:
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
  }
}
  1. saveGameConfig 方法添加保存逻辑:
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}`)
}
  1. 实现保存方法:
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 配置模板

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 格式游戏配置

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 配置文件:

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

依赖库说明

  • yamlYAML 文件解析与生成
  • properties-readerJava Properties 文件解析
  • fs/promises:异步文件系统操作

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


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