mirror of
https://github.com/GSManagerXZ/GameServerManager.git
synced 2025-10-04 22:02:03 +08:00
454 lines
No EOL
11 KiB
Markdown
454 lines
No EOL
11 KiB
Markdown
---
|
||
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` 添加依赖。
|
||
|
||
---
|
||
|
||
通过本页文档,开发者可快速为新游戏添加配置文件可视化支持。模块化设计便于扩展解析器和模板,正确配置模板、选择解析器并遵循最佳实践可保障系统稳定与体验。 |