GFramework/docs/zh-CN/contributing.md
GeWuYou fb14d7122c docs(style): 更新文档中的命名空间导入格式
- 将所有小写的命名空间导入更正为首字母大写格式
- 统一 GFramework 框架的命名空间引用规范
- 修复 core、ecs、godot 等模块的命名空间导入错误
- 标准化文档示例代码中的 using 语句格式
- 确保所有文档中的命名空间引用保持一致性
- 更新 global using 语句以匹配正确的命名空间格式
2026-03-10 07:18:49 +08:00

18 KiB
Raw Blame History

贡献指南

欢迎为 GFramework 贡献代码!本指南将帮助你了解如何参与项目开发。

概述

GFramework 是一个开源的游戏开发框架,我们欢迎所有形式的贡献:

  • 报告 Bug 和提出功能建议
  • 提交代码修复和新功能
  • 改进文档和示例
  • 参与讨论和代码审查

行为准则

社区规范

我们致力于为所有贡献者提供友好、安全和包容的环境。参与本项目时,请遵守以下准则:

  • 尊重他人:尊重不同的观点和经验
  • 建设性沟通:提供有建设性的反馈,避免人身攻击
  • 协作精神:帮助新贡献者融入社区
  • 专业态度:保持专业和礼貌的交流方式

不可接受的行为

  • 使用性别化语言或图像
  • 人身攻击或侮辱性评论
  • 骚扰行为(公开或私下)
  • 未经许可发布他人的私人信息
  • 其他不道德或不专业的行为

如何贡献

报告问题

发现 Bug 或有功能建议时,请通过 GitHub Issues 提交:

  1. 搜索现有 Issue:避免重复提交
  2. 使用清晰的标题:简洁描述问题
  3. 提供详细信息
    • Bug 报告:复现步骤、预期行为、实际行为、环境信息
    • 功能建议:使用场景、预期效果、可能的实现方案

Bug 报告模板

**描述**
简要描述 Bug

**复现步骤**
1. 执行操作 A
2. 执行操作 B
3. 观察到错误

**预期行为**
应该发生什么

**实际行为**
实际发生了什么

**环境信息**
- GFramework 版本:
- .NET 版本:
- 操作系统:
- Godot 版本(如适用):

**附加信息**
日志、截图等

提交 Pull Request

基本流程

  1. Fork 仓库:在 GitHub 上 Fork 本项目
  2. 克隆到本地
    git clone https://github.com/your-username/GFramework.git
    cd GFramework
    
  3. 创建特性分支
    git checkout -b feature/your-feature-name
    # 或
    git checkout -b fix/your-bug-fix
    
  4. 进行开发:编写代码、添加测试、更新文档
  5. 提交更改:遵循提交规范(见下文)
  6. 推送分支
    git push origin feature/your-feature-name
    
  7. 创建 PR:在 GitHub 上创建 Pull Request

PR 要求

  • 清晰的标题:简洁描述变更内容
  • 详细的描述
    • 变更的背景和动机
    • 实现方案说明
    • 测试验证结果
    • 相关 Issue 链接(如有)
  • 代码质量:通过所有 CI 检查
  • 测试覆盖:为新功能添加测试
  • 文档更新:更新相关文档

改进文档

文档改进同样重要:

  • 修正错误:拼写、语法、技术错误
  • 补充示例:添加代码示例和使用场景
  • 完善说明:改进不清晰的描述
  • 翻译工作:帮助翻译文档(如需要)

文档位于 docs/ 目录,使用 Markdown 格式编写。

开发环境设置

前置要求

  • .NET SDK8.0、9.0 或 10.0
  • Git:版本控制工具
  • IDE(推荐):
    • Visual Studio 2022+
    • JetBrains Rider
    • Visual Studio Code + C# Dev Kit

克隆仓库

# 克隆你 Fork 的仓库
git clone https://github.com/your-username/GFramework.git
cd GFramework

# 添加上游仓库
git remote add upstream https://github.com/GeWuYou/GFramework.git

安装依赖

# 恢复 NuGet 包
dotnet restore

# 恢复 .NET 本地工具
dotnet tool restore

构建项目

# 构建所有项目
dotnet build

# 构建特定配置
dotnet build -c Release

运行测试

# 运行所有测试
dotnet test

# 运行特定测试项目
dotnet test GFramework.Core.Tests
dotnet test GFramework.SourceGenerators.Tests

# 生成测试覆盖率报告
dotnet test --collect:"XPlat Code Coverage"

验证代码质量

项目使用 MegaLinter 进行代码质量检查:

# 本地运行 MegaLinter需要 Docker
docker run --rm -v $(pwd):/tmp/lint oxsecurity/megalinter:v9

# 或使用 CI 流程验证
git push origin your-branch

代码规范

命名规范

遵循 C# 标准命名约定:

  • 类、接口、方法PascalCase

    public class PlayerController { }
    public interface IEventBus { }
    public void ProcessInput() { }
    
  • 私有字段_camelCase下划线前缀

    private int _health;
    private readonly ILogger _logger;
    
  • 参数、局部变量camelCase

    public void SetHealth(int newHealth)
    {
        var oldHealth = _health;
        _health = newHealth;
    }
    
  • 常量PascalCase

    public const int MaxPlayers = 4;
    private const string DefaultName = "Player";
    
  • 接口I 前缀

    public interface IArchitecture { }
    public interface ICommand<TInput> { }
    

代码风格

  • 缩进4 个空格(不使用 Tab

  • 大括号Allman 风格(独占一行)

    if (condition)
    {
        DoSomething();
    }
    
  • using 指令:文件顶部,按字母顺序排列

    using System;
    using System.Collections.Generic;
    using GFramework.Core.Abstractions;
    
  • 空行

    • 命名空间后空一行
    • 类成员之间空一行
    • 逻辑块之间适当空行
  • 行长度:建议不超过 120 字符

注释规范

XML 文档注释

所有公共 API 必须包含 XML 文档注释:

/// <summary>
///     架构基类,提供系统、模型、工具等组件的注册与管理功能。
/// </summary>
/// <typeparam name="TModel">模型类型</typeparam>
/// <param name="configuration">架构配置</param>
/// <returns>注册的模型实例</returns>
/// <exception cref="ArgumentNullException">当 model 为 null 时抛出</exception>
public TModel RegisterModel<TModel>(TModel model) where TModel : IModel
{
    // 实现代码
}

代码注释

  • 何时添加注释

    • 复杂的算法逻辑
    • 非显而易见的设计决策
    • 临时解决方案(使用 TODO 或 HACK 标记)
    • 性能关键代码的优化说明
  • 注释风格

    // 单行注释使用双斜杠
    
    // 多行注释可以使用多个单行注释
    // 每行都以双斜杠开始
    
    /* 或使用块注释
     * 适用于较长的说明
     */
    
  • 避免无用注释

    // 不好:注释重复代码内容
    // 设置健康值为 100
    health = 100;
    
    // 好:解释为什么这样做
    // 初始化时设置满血,避免首次战斗时的边界情况
    health = MaxHealth;
    

设计原则

  • SOLID 原则:遵循面向对象设计原则
  • 依赖注入:优先使用构造函数注入
  • 接口隔离:定义小而专注的接口
  • 不可变性:优先使用 readonly 和不可变类型
  • 异步编程I/O 操作使用 async/await

提交规范

Commit 消息格式

使用 Conventional Commits 规范:

<type>(<scope>): <subject>

<body>

<footer>

Type类型

  • feat:新功能
  • fixBug 修复
  • docs:文档更新
  • style:代码格式调整(不影响功能)
  • refactor:重构(不是新功能也不是修复)
  • perf:性能优化
  • test:添加或修改测试
  • chore:构建过程或辅助工具的变动
  • ciCI 配置文件和脚本的变动

Scope范围

指明变更影响的模块:

  • coreGFramework.Core
  • gameGFramework.Game
  • godotGFramework.Godot
  • generators:源码生成器
  • docs:文档
  • tests:测试

Subject主题

  • 使用祈使句,现在时态:"add" 而不是 "added" 或 "adds"
  • 首字母小写
  • 结尾不加句号
  • 限制在 50 字符以内

Body正文

  • 详细描述变更的动机和实现细节
  • 与主题空一行
  • 每行不超过 72 字符

Footer页脚

  • 关联 IssueCloses #123
  • 破坏性变更:BREAKING CHANGE: 描述

示例

# 简单提交
git commit -m "feat(core): add event priority support"

# 详细提交
git commit -m "fix(godot): resolve scene loading race condition

修复了在快速切换场景时可能出现的资源加载竞态条件。
通过引入场景加载锁机制,确保同一时间只有一个场景在加载。

Closes #456"

# 破坏性变更
git commit -m "refactor(core): change IArchitecture interface

BREAKING CHANGE: IArchitecture.Init() 现在返回 Task 而不是 void。
所有继承 Architecture 的类需要更新为异步初始化。

Migration guide: 将 Init() 改为 async Task Init()
"

分支策略

  • main:主分支,保持稳定
  • feature/*:新功能分支
    • feature/event-priority
    • feature/godot-ui-system
  • fix/*Bug 修复分支
    • fix/memory-leak
    • fix/null-reference
  • docs/*:文档更新分支
    • docs/api-reference
    • docs/tutorial-update
  • refactor/*:重构分支
    • refactor/logging-system

分支命名规范

  • 使用小写字母和连字符
  • 简洁描述分支目的
  • 避免使用个人名称

测试要求

单元测试

所有新功能和 Bug 修复都应包含单元测试:

using Xunit;

namespace GFramework.Core.Tests.Events;

public class EventBusTests
{
    [Fact]
    public void Subscribe_ShouldReceiveEvent()
    {
        // Arrange
        var eventBus = new EventBus();
        var received = false;

        // Act
        eventBus.Subscribe&lt;TestEvent&gt;(e =&gt; received = true);
        eventBus.Publish(new TestEvent());

        // Assert
        Assert.True(received);
    }

    [Theory]
    [InlineData(1)]
    [InlineData(10)]
    [InlineData(100)]
    public void Subscribe_MultipleEvents_ShouldReceiveAll(int count)
    {
        // 测试实现
    }
}

测试组织

  • 测试项目*.Tests 后缀
  • 测试类*Tests 后缀,与被测试类对应
  • 测试方法MethodName_Scenario_ExpectedResult 格式
  • 测试数据:使用 [Theory][InlineData] 进行参数化测试

测试覆盖率

  • 目标:新代码覆盖率 > 80%
  • 关键路径:核心功能覆盖率 > 90%
  • 边界情况:测试异常情况和边界值

集成测试

对于涉及多个组件交互的功能,添加集成测试:

public class ArchitectureIntegrationTests
{
    [Fact]
    public async Task Architecture_FullLifecycle_ShouldWork()
    {
        // Arrange
        var architecture = new TestArchitecture();

        // Act
        await architecture.InitAsync();
        var result = architecture.GetModel&lt;TestModel&gt;();
        await architecture.DestroyAsync();

        // Assert
        Assert.NotNull(result);
    }
}

性能测试

对性能敏感的代码,添加基准测试:

using BenchmarkDotNet.Attributes;

[MemoryDiagnoser]
public class EventBusBenchmarks
{
    private EventBus _eventBus;

    [GlobalSetup]
    public void Setup()
    {
        _eventBus = new EventBus();
    }

    [Benchmark]
    public void Publish_1000Events()
    {
        for (int i = 0; i &lt; 1000; i++)
        {
            _eventBus.Publish(new TestEvent());
        }
    }
}

文档要求

XML 注释

所有公共 API 必须包含完整的 XML 文档注释:

/// &lt;summary&gt;
///     事件总线接口,提供事件的发布和订阅功能。
/// &lt;/summary&gt;
/// &lt;remarks&gt;
///     事件总线使用观察者模式实现,支持类型安全的事件分发。
///     所有订阅都是弱引用,避免内存泄漏。
/// &lt;/remarks&gt;
public interface IEventBus
{
    /// &lt;summary&gt;
    ///     订阅指定类型的事件。
    /// &lt;/summary&gt;
    /// &lt;typeparam name="TEvent"&gt;事件类型&lt;/typeparam&gt;
    /// &lt;param name="handler"&gt;事件处理器&lt;/param&gt;
    /// &lt;returns&gt;取消订阅的句柄&lt;/returns&gt;
    /// &lt;exception cref="ArgumentNullException"&gt;当 handler 为 null 时抛出&lt;/exception&gt;
    /// &lt;example&gt;
    /// &lt;code&gt;
    /// var unregister = eventBus.Subscribe&amp;lt;PlayerDiedEvent&amp;gt;(e =&amp;gt;
    /// {
    ///     Console.WriteLine($"Player {e.PlayerId} died");
    /// });
    ///
    /// // 取消订阅
    /// unregister.Dispose();
    /// &lt;/code&gt;
    /// &lt;/example&gt;
    IUnRegister Subscribe&lt;TEvent&gt;(Action&lt;TEvent&gt; handler) where TEvent : IEvent;
}

Markdown 文档

文档结构

# 标题

简要介绍模块功能和用途。

## 核心概念

解释关键概念和术语。

## 快速开始

提供最简单的使用示例。

## 详细用法

### 功能 A

详细说明和代码示例。

### 功能 B

详细说明和代码示例。

## 最佳实践

推荐的使用模式和注意事项。

## 常见问题

FAQ 列表。

## 相关资源

链接到相关文档和示例。

代码示例

  • 完整性:示例代码应该可以直接运行
  • 注释:关键步骤添加注释说明
  • 格式化:使用正确的语法高亮
// 创建架构实例
var architecture = new GameArchitecture();

// 初始化架构
await architecture.InitAsync();

// 注册模型
var playerModel = architecture.GetModel&lt;PlayerModel&gt;();

// 发送命令
await architecture.SendCommandAsync(new AttackCommand
{
    TargetId = enemyId
});

图表

使用 Mermaid 或 ASCII 图表说明复杂概念:

```mermaid
graph TD
    A[Controller] --&gt; B[Command]
    B --&gt; C[System]
    C --&gt; D[Model]

## PR 流程

### 创建 PR

1. **确保分支最新**
   ```bash
   git fetch upstream
   git rebase upstream/main
  1. 推送到 Fork

    git push origin feature/your-feature
    
  2. 创建 PR

    • 在 GitHub 上点击 "New Pull Request"
    • 选择 base: main ← compare: your-branch
    • 填写 PR 模板

PR 模板

## 变更说明

简要描述本 PR 的变更内容。

## 变更类型

- [ ] Bug 修复
- [ ] 新功能
- [ ] 破坏性变更
- [ ] 文档更新
- [ ] 性能优化
- [ ] 代码重构

## 相关 Issue

Closes #123

## 测试

描述如何测试这些变更:

- [ ] 添加了单元测试
- [ ] 添加了集成测试
- [ ] 手动测试通过

## 检查清单

- [ ] 代码遵循项目规范
- [ ] 添加了必要的注释
- [ ] 更新了相关文档
- [ ] 所有测试通过
- [ ] 没有引入新的警告

## 截图(如适用)

添加截图或 GIF 展示变更效果。

## 附加说明

其他需要说明的内容。

代码审查

PR 提交后,维护者会进行代码审查:

  • 响应反馈:及时回复审查意见
  • 修改代码:根据建议进行调整
  • 讨论方案:对有争议的地方进行讨论
  • 保持耐心:审查可能需要时间

审查关注点

  • 功能正确性:代码是否实现了预期功能
  • 代码质量:是否遵循项目规范
  • 测试覆盖:是否有足够的测试
  • 性能影响:是否有性能问题
  • 向后兼容:是否破坏现有 API

合并流程

  1. 通过 CI 检查:所有自动化测试通过
  2. 代码审查通过:至少一位维护者批准
  3. 解决冲突:如有冲突需先解决
  4. 合并方式
    • 功能分支Squash and merge
    • 修复分支Merge commit
    • 文档更新Squash and merge

常见问题

如何同步上游更新?

# 获取上游更新
git fetch upstream

# 合并到本地 main
git checkout main
git merge upstream/main

# 更新你的 Fork
git push origin main

# 更新特性分支
git checkout feature/your-feature
git rebase main

如何解决合并冲突?

# 拉取最新代码
git fetch upstream
git rebase upstream/main

# 如果有冲突,手动解决后
git add .
git rebase --continue

# 强制推送(因为 rebase 改变了历史)
git push origin feature/your-feature --force-with-lease

提交了错误的代码怎么办?

# 修改最后一次提交
git add .
git commit --amend

# 或者撤销最后一次提交
git reset --soft HEAD~1
# 修改后重新提交
git add .
git commit -m "fix: correct implementation"

如何运行特定的测试?

# 运行单个测试类
dotnet test --filter "FullyQualifiedName~EventBusTests"

# 运行单个测试方法
dotnet test --filter "FullyQualifiedName~EventBusTests.Subscribe_ShouldReceiveEvent"

# 运行特定类别的测试
dotnet test --filter "Category=Integration"

如何生成文档?

# 安装 VitePress如果还没安装
cd docs
npm install

# 本地预览文档
npm run docs:dev

# 构建文档
npm run docs:build

代码审查需要多长时间?

  • 简单修复:通常 1-3 天
  • 新功能:可能需要 1-2 周
  • 大型重构:可能需要更长时间

请耐心等待,维护者会尽快审查。

我的 PR 被拒绝了怎么办?

不要气馁!被拒绝的原因可能是:

  • 不符合项目方向
  • 需要更多讨论
  • 实现方式需要调整

你可以:

  • 在 Issue 中讨论方案
  • 根据反馈调整实现
  • 寻求维护者的建议

如何成为维护者?

持续贡献高质量的代码和文档,积极参与社区讨论,帮助其他贡献者。维护者会邀请活跃且负责任的贡献者加入维护团队。

获取帮助

如果你在贡献过程中遇到问题:

  • GitHub Issues:提问或报告问题
  • GitHub Discussions:参与讨论
  • 代码注释:查看现有代码的注释和文档

致谢

感谢所有为 GFramework 做出贡献的开发者!你们的努力让这个项目变得更好。

许可证

通过向本项目提交代码,你同意你的贡献将在 Apache License 2.0 下发布。