mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
Merge pull request #271 from GeWuYou/docs/sdk-update-documentation
Docs/sdk update documentation
This commit is contained in:
commit
3f95843d59
@ -12,7 +12,9 @@ Shortcut: `$gframework-pr-review`
|
||||
## Workflow
|
||||
|
||||
1. Read `AGENTS.md` before deciding how to validate or fix anything.
|
||||
2. Resolve the current branch with Windows Git from WSL, following the repository worktree rule.
|
||||
2. Resolve the current branch following the repository worktree rule:
|
||||
- prefer Linux `git` with explicit `--git-dir` / `--work-tree` binding in WSL worktrees
|
||||
- only fall back to `git.exe` when that executable is available and actually runnable in the current session
|
||||
3. Run `scripts/fetch_current_pr_review.py` to:
|
||||
- locate the PR for the current branch through the GitHub PR API
|
||||
- fetch PR metadata, issue comments, reviews, and review comments through the GitHub API
|
||||
@ -31,20 +33,20 @@ Shortcut: `$gframework-pr-review`
|
||||
## Commands
|
||||
|
||||
- Default:
|
||||
- `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py`
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py`
|
||||
- Recommended machine-readable workflow:
|
||||
- `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 265 --json-output /tmp/pr265-review.json`
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 265 --json-output /tmp/pr265-review.json`
|
||||
- `jq '.coderabbit_review.outside_diff_comments' /tmp/pr265-review.json`
|
||||
- Force a PR number:
|
||||
- `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253`
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253`
|
||||
- Machine-readable output:
|
||||
- `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json`
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --format json`
|
||||
- Write machine-readable output to a file instead of stdout:
|
||||
- `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253 --format json --json-output /tmp/pr253-review.json`
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253 --format json --json-output /tmp/pr253-review.json`
|
||||
- Inspect only a high-signal section:
|
||||
- `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253 --section outside-diff`
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253 --section outside-diff`
|
||||
- Narrow text output to one path fragment:
|
||||
- `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253 --section outside-diff --path GFramework.Core/Events/Event.cs`
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --pr 253 --section outside-diff --path GFramework.Core/Events/Event.cs`
|
||||
|
||||
## Output Expectations
|
||||
|
||||
@ -67,6 +69,7 @@ The script should produce:
|
||||
|
||||
- If the current branch has no matching public PR, report that clearly instead of guessing.
|
||||
- If GitHub access fails because of proxy configuration, rerun the fetch with proxy variables removed.
|
||||
- If the current WSL session resolves `git.exe` but cannot execute it cleanly, keep using the explicit Linux worktree binding instead of retrying Windows Git.
|
||||
- Prefer GitHub API results over PR HTML. The PR HTML page is now a fallback/debugging source, not the primary source of truth.
|
||||
- If the summary block and the latest head review threads disagree, trust the latest unresolved head-review threads and treat older summary findings as stale until re-verified locally.
|
||||
- Do not assume every AI reviewer behaves like CodeRabbit. `greptile-apps[bot]` findings may exist only as latest-head review threads, without CodeRabbit-style issue comments or folded review-body sections.
|
||||
|
||||
@ -21,8 +21,11 @@ from typing import Any
|
||||
|
||||
OWNER = "GeWuYou"
|
||||
REPO = "GFramework"
|
||||
WORKTREE_ROOT_DIRECTORY_NAME = "GFramework-WorkTree"
|
||||
DEFAULT_WINDOWS_GIT = "/mnt/d/Tool/Development Tools/Git/cmd/git.exe"
|
||||
GIT_ENVIRONMENT_KEY = "GFRAMEWORK_WINDOWS_GIT"
|
||||
GIT_DIR_ENVIRONMENT_KEY = "GFRAMEWORK_GIT_DIR"
|
||||
WORK_TREE_ENVIRONMENT_KEY = "GFRAMEWORK_WORK_TREE"
|
||||
USER_AGENT = "codex-gframework-pr-review"
|
||||
CODERABBIT_LOGIN = "coderabbitai[bot]"
|
||||
GREPTILE_LOGIN = "greptile-apps[bot]"
|
||||
@ -83,6 +86,43 @@ def resolve_git_command() -> str:
|
||||
raise RuntimeError(f"No usable git executable found. Set {GIT_ENVIRONMENT_KEY} to override it.")
|
||||
|
||||
|
||||
def find_repository_root(start_path: Path) -> Path | None:
|
||||
"""Locate the repository root by walking parent directories for repo markers."""
|
||||
for candidate in (start_path, *start_path.parents):
|
||||
if (candidate / "AGENTS.md").exists() and (candidate / ".ai/environment/tools.ai.yaml").exists():
|
||||
return candidate
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def resolve_worktree_git_dir(repository_root: Path) -> Path | None:
|
||||
"""Resolve the main-repository worktree gitdir for this WSL worktree layout."""
|
||||
if repository_root.parent.name != WORKTREE_ROOT_DIRECTORY_NAME:
|
||||
return None
|
||||
|
||||
primary_repository_root = repository_root.parent.parent / REPO
|
||||
candidate_git_dir = primary_repository_root / ".git" / "worktrees" / repository_root.name
|
||||
return candidate_git_dir if candidate_git_dir.exists() else None
|
||||
|
||||
|
||||
def resolve_git_invocation() -> list[str]:
|
||||
"""Resolve the git command arguments, preferring explicit WSL worktree binding."""
|
||||
configured_git_dir = os.environ.get(GIT_DIR_ENVIRONMENT_KEY)
|
||||
configured_work_tree = os.environ.get(WORK_TREE_ENVIRONMENT_KEY)
|
||||
linux_git = shutil.which("git")
|
||||
|
||||
if configured_git_dir and configured_work_tree and linux_git:
|
||||
return [linux_git, f"--git-dir={configured_git_dir}", f"--work-tree={configured_work_tree}"]
|
||||
|
||||
repository_root = find_repository_root(Path.cwd())
|
||||
if repository_root is not None and linux_git:
|
||||
worktree_git_dir = resolve_worktree_git_dir(repository_root)
|
||||
if worktree_git_dir is not None:
|
||||
return [linux_git, f"--git-dir={worktree_git_dir}", f"--work-tree={repository_root}"]
|
||||
|
||||
return [resolve_git_command()]
|
||||
|
||||
|
||||
def resolve_request_timeout_seconds() -> int:
|
||||
"""Return the GitHub request timeout in seconds."""
|
||||
configured_timeout = os.environ.get(REQUEST_TIMEOUT_ENVIRONMENT_KEY)
|
||||
@ -113,7 +153,7 @@ def run_command(args: list[str]) -> str:
|
||||
|
||||
def get_current_branch() -> str:
|
||||
"""Return the current git branch name."""
|
||||
return run_command([resolve_git_command(), "rev-parse", "--abbrev-ref", "HEAD"])
|
||||
return run_command([*resolve_git_invocation(), "rev-parse", "--abbrev-ref", "HEAD"])
|
||||
|
||||
|
||||
def open_url(url: str, accept: str) -> tuple[str, Any]:
|
||||
|
||||
23
AGENTS.md
23
AGENTS.md
@ -10,14 +10,21 @@ All AI agents and contributors must follow these rules when writing, reviewing,
|
||||
- Use `@.ai/environment/tools.raw.yaml` only when you need the full collected facts behind the AI-facing hints.
|
||||
- Prefer the project-relevant tools listed there instead of assuming every installed system tool is fair game.
|
||||
- If the real environment differs from the inventory, use the project-relevant installed tool and report the mismatch.
|
||||
- When working in WSL against this repository's Windows-backed worktree, prefer Windows Git from WSL (for example
|
||||
`git.exe`) instead of the Linux `git` binary.
|
||||
- If a Git command in WSL fails with a worktree-style “not a git repository” path translation error, rerun it with the
|
||||
Windows Git executable and treat that as the repository-default Git path for the rest of the task.
|
||||
- If the shell does not currently resolve `git.exe` to the host Windows Git installation, prepend that installation's
|
||||
command directory to `PATH` and reset shell command hashing for the current session before continuing.
|
||||
- After resolving the host Windows Git path, prefer an explicit session-local binding for subsequent commands so the
|
||||
shell does not fall back to Linux `/usr/bin/git` later in the same WSL session.
|
||||
- When working in WSL against this repository's Windows-backed worktree, first prefer Linux `git` with an explicit
|
||||
`--git-dir=<repo>/.git/worktrees/<worktree-name>` and `--work-tree=<worktree-root>` binding for every repository
|
||||
command. Treat that explicit binding as higher priority than `git.exe`, because it avoids WSL worktree path
|
||||
translation mistakes and still works in sessions where Windows `.exe` execution is unavailable.
|
||||
- If a plain Linux `git` command in WSL fails with a worktree-style “not a git repository” path translation error,
|
||||
rerun it with the explicit `--git-dir` / `--work-tree` binding before trying `git.exe`.
|
||||
- Only prefer Windows Git from WSL (for example `git.exe`) when that executable is both resolvable and executable in the
|
||||
current session, and when the explicit Linux `git` binding is unavailable or has already failed.
|
||||
- If the shell resolves `git.exe` but the current WSL session cannot execute it cleanly (for example `Exec format
|
||||
error`), keep using the explicit Linux `git` binding for the rest of the task instead of retrying Windows Git.
|
||||
- If the shell does not currently resolve `git.exe` to the host Windows Git installation and you still need Windows Git
|
||||
as a fallback, prepend that installation's command directory to `PATH` and reset shell command hashing for the
|
||||
current session before continuing.
|
||||
- After resolving either strategy, prefer a session-local binding or command wrapper for subsequent Git commands so the
|
||||
shell does not silently fall back to the wrong repository context later in the same WSL session.
|
||||
|
||||
## Git Workflow Rules
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
`GFramework.Core.Abstractions` 承载 `Core` 运行时对应的接口、枚举和值对象,用来定义跨模块协作边界。
|
||||
|
||||
它只描述契约,不提供默认的架构、事件、状态、资源或 IoC 实现;这些实现都在 `GFramework.Core` 中。
|
||||
|
||||
## 什么时候单独依赖它
|
||||
|
||||
- 你在做插件、适配层或扩展包,只想依赖契约,不想把完整运行时拉进来
|
||||
@ -20,23 +22,34 @@
|
||||
|
||||
## 契约地图
|
||||
|
||||
| 目录 | 作用 |
|
||||
| 目录族 | 作用 |
|
||||
| --- | --- |
|
||||
| `Architectures/` | `IArchitecture`、模块、阶段监听与服务管理契约 |
|
||||
| `Command/` / `Query/` | 旧版命令与查询执行器接口 |
|
||||
| `Controller/` | `IController` |
|
||||
| `Events/` | 事件契约、解绑接口与传播上下文 |
|
||||
| `Model/` / `Systems/` / `Utility/` | 核心组件接口 |
|
||||
| `State/` / `StateManagement/` | 状态机、Store、reducer、selector 契约 |
|
||||
| `Property/` | `IBindableProperty` 与只读属性接口 |
|
||||
| `Resource/` | 资源管理与释放策略契约 |
|
||||
| `Localization/` | 本地化表、格式化与异常类型 |
|
||||
| `Logging/` | logger、log entry、factory 相关契约 |
|
||||
| `Ioc/` | `IIocContainer` |
|
||||
| `Lifecycle/` | 初始化 / 销毁生命周期契约 |
|
||||
| `Coroutine/` | 时间源、yield 指令与协程状态枚举 |
|
||||
| `Pause/` | 暂停栈、token 与状态事件 |
|
||||
| `Storage/` / `Serializer/` / `Versioning/` | 通用存储、序列化与版本化契约 |
|
||||
| `Architectures/` `Lifecycle/` `Registries/` | `IArchitecture`、上下文、模块、服务模块、阶段监听、注册表基类与生命周期契约 |
|
||||
| `Bases/` `Controller/` `Model/` `Systems/` `Utility/` `Rule/` | 组件角色接口、优先级 / key 值对象、上下文感知约束与扩展边界 |
|
||||
| `Command/` `Query/` `Cqrs/` | 旧版命令 / 查询执行器接口,以及 `ICqrsRuntime` 这类新请求模型接线契约 |
|
||||
| `Events/` `Property/` `State/` `StateManagement/` | 事件总线、解绑对象、可绑定属性、状态机、Store / reducer / middleware 契约 |
|
||||
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | 协程状态、时间源、暂停栈、键控异步锁和统计对象 |
|
||||
| `Resource/` `Pool/` `Logging/` `Localization/` | 资源句柄、对象池、日志、日志工厂、本地化表与格式化契约 |
|
||||
| `Configuration/` `Environment/` | 配置管理器、环境对象与运行时环境访问契约 |
|
||||
| `Data/` `Serializer/` `Storage/` `Versioning/` | 数据装载、序列化、存储与版本化契约 |
|
||||
| `Enums/` `Properties/` | 架构阶段枚举,以及架构 / logger 相关属性键 |
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
截至 `2026-04-22`,已按顶层目录对 `GFramework.Core.Abstractions` 的公开 / 内部类型声明做过一轮轻量盘点;当前契约目录族的类型声明都已带
|
||||
XML 注释。这里记录的是类型族级基线,成员级契约细节仍需要在后续波次继续审计。
|
||||
|
||||
| 类型族 | 基线状态 | 代表类型 |
|
||||
| --- | --- | --- |
|
||||
| `Architectures/` `Lifecycle/` `Registries/` | `20/20` 个类型声明已带 XML 注释 | `IArchitecture`、`IArchitectureContext`、`IServiceModule`、`KeyValueRegistryBase<TKey, TValue>` |
|
||||
| `Command/` `Query/` `Cqrs/` | `10/10` 个类型声明已带 XML 注释 | `ICommandExecutor`、`IAsyncQueryExecutor`、`ICqrsRuntime` |
|
||||
| `Events/` `Property/` `State/` `StateManagement/` | `25/25` 个类型声明已带 XML 注释 | `IEventBus`、`IBindableProperty<T>`、`IStateMachine`、`IStore<TState>` |
|
||||
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | `17/17` 个类型声明已带 XML 注释 | `IYieldInstruction`、`ITimeProvider`、`IPauseStackManager`、`IAsyncKeyLockManager` |
|
||||
| `Resource/` `Pool/` `Logging/` `Localization/` | `27/27` 个类型声明已带 XML 注释 | `IResourceManager`、`IObjectPoolSystem`、`ILogger`、`ILocalizationManager` |
|
||||
| `Configuration/` `Environment/` `Data/` `Serializer/` `Storage/` `Versioning/` | `7/7` 个类型声明已带 XML 注释 | `IConfigurationManager`、`IEnvironment`、`ILoadableFrom<T>`、`ISerializer`、`IStorage` |
|
||||
| `Bases/` `Controller/` `Model/` `Systems/` `Utility/` `Rule/` `Enums/` `Properties/` | `19/19` 个类型声明已带 XML 注释 | `IPrioritized`、`IController`、`IModel`、`ISystem`、`IContextUtility`、`ArchitecturePhase` |
|
||||
|
||||
完整 inventory 与阅读顺序见 `docs/zh-CN/abstractions/core-abstractions.md`。
|
||||
|
||||
## 采用建议
|
||||
|
||||
@ -44,8 +57,18 @@
|
||||
- 若你只需要对接口编程,可以仅引用本包,再在应用层自行提供实现
|
||||
- 若你在写上层模块,优先把公共契约放在 `*.Abstractions`,实现放在对应 runtime 包
|
||||
|
||||
## 重点 XML 关注点
|
||||
|
||||
如果你在做契约审计、模块拆分或测试替身,优先看这些类型族的 XML 文档:
|
||||
|
||||
- 架构与模块入口:`IArchitecture`、`IArchitectureContext`、`IServiceModule`
|
||||
- 运行时基础设施:`IIocContainer`、`ILogger`、`IResourceManager`、`IConfigurationManager`
|
||||
- 状态与并发能力:`IStateMachine`、`IStore`、`IAsyncKeyLockManager`、`ITimeProvider`
|
||||
- 迁移与组合边界:`ICommandExecutor`、`IQueryExecutor`、`ICqrsRuntime`
|
||||
|
||||
## 对应文档
|
||||
|
||||
- 抽象接口栏目:[`../docs/zh-CN/abstractions/index.md`](../docs/zh-CN/abstractions/index.md)
|
||||
- Core 抽象页:[`../docs/zh-CN/abstractions/core-abstractions.md`](../docs/zh-CN/abstractions/core-abstractions.md)
|
||||
- Core 运行时入口:[`../GFramework.Core/README.md`](../GFramework.Core/README.md)
|
||||
- API 参考入口:[`../docs/zh-CN/api-reference/index.md`](../docs/zh-CN/api-reference/index.md)
|
||||
|
||||
@ -10,9 +10,10 @@
|
||||
|
||||
- `Architecture` 与 `ArchitectureContext`
|
||||
- `Model` / `System` / `Utility` 运行时
|
||||
- 旧版 `Command` / `Query` 执行器
|
||||
- 事件、属性、状态机、状态管理
|
||||
- 资源、日志、协程、并发、环境与本地化
|
||||
- 旧版 `Command` / `Query` 执行器,以及与新版 `CQRS` runtime 的接线入口
|
||||
- 事件、属性、状态机、状态管理、规则与上下文扩展
|
||||
- 资源、对象池、日志、协程、并发、环境、配置与本地化
|
||||
- 服务模块管理、时间提供器与默认的 IoC 容器适配
|
||||
|
||||
它不负责:
|
||||
|
||||
@ -37,6 +38,7 @@
|
||||
| 目录 | 作用 |
|
||||
| --- | --- |
|
||||
| `Architectures/` | 架构入口、上下文、生命周期、模块安装与组件注册 |
|
||||
| `Services/` | 服务模块注册、生命周期协调与模块管理 |
|
||||
| `Command/` | 旧版命令执行器与同步 / 异步命令基类 |
|
||||
| `Query/` | 旧版查询执行器与同步 / 异步查询基类 |
|
||||
| `Events/` | 事件总线、事件作用域、统计与过滤 |
|
||||
@ -44,15 +46,37 @@
|
||||
| `State/` | 状态机与状态切换事件 |
|
||||
| `StateManagement/` | Store、selector、middleware 与状态诊断 |
|
||||
| `Coroutine/` | 协程调度、快照、统计与优先级 |
|
||||
| `Time/` | 默认时间提供器与协程时间源 |
|
||||
| `Resource/` | 资源缓存、句柄和释放策略 |
|
||||
| `Pool/` | 对象池系统与常用池化辅助实现 |
|
||||
| `Logging/` | logger、factory、配置与组合日志器 |
|
||||
| `Ioc/` | 基于 `Microsoft.Extensions.DependencyInjection` 的容器适配 |
|
||||
| `Concurrency/` | 键控异步锁与统计 |
|
||||
| `Configuration/` | 配置管理器与配置监听解绑对象 |
|
||||
| `Environment/` | 运行环境对象与上下文环境扩展 |
|
||||
| `Pause/` | 暂停栈和暂停范围 |
|
||||
| `Localization/` | 本地化表与格式化入口 |
|
||||
| `Rule/` | `ContextAwareBase` 等上下文感知基类 |
|
||||
| `Functional/` | `Option`、`Result` 等轻量函数式工具 |
|
||||
| `Extensions/` | 上下文与集合等扩展方法 |
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
截至 `2026-04-22`,已按顶层目录对 `GFramework.Core` 的公开 / 内部类型声明做过一轮轻量盘点;当前主目录族的类型声明都已带
|
||||
XML 注释。这里先保留阅读基线,成员级 ``<param>`` / ``<returns>`` / 生命周期语义审计仍属于后续治理项。
|
||||
|
||||
| 类型族 | 基线状态 | 代表类型 |
|
||||
| --- | --- | --- |
|
||||
| `Architectures/` `Services/` | `22/22` 个类型声明已带 XML 注释 | `Architecture`、`ArchitectureContext`、`ArchitectureLifecycle`、`ServiceModuleManager` |
|
||||
| `Command/` `Query/` | `15/15` 个类型声明已带 XML 注释 | `CommandExecutor`、`AsyncQueryExecutor`、`AbstractCommand<TInput>`、`AbstractQuery<TResult>` |
|
||||
| `Events/` `Property/` `State/` `StateManagement/` | `29/29` 个类型声明已带 XML 注释 | `EventBus`、`BindableProperty<T>`、`StateMachine`、`Store<TState>` |
|
||||
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | `43/43` 个类型声明已带 XML 注释 | `CoroutineScheduler`、`CoroutineHandle`、`PauseStackManager`、`AsyncKeyLockManager` |
|
||||
| `Resource/` `Pool/` | `8/8` 个类型声明已带 XML 注释 | `ResourceManager`、`AutoReleaseStrategy`、`AbstractObjectPoolSystem<TKey, TObject>` |
|
||||
| `Logging/` `Localization/` `Configuration/` `Environment/` `Ioc/` | `31/31` 个类型声明已带 XML 注释 | `ConsoleLogger`、`LocalizationManager`、`ConfigurationManager`、`DefaultEnvironment`、`MicrosoftDiContainer` |
|
||||
| `Model/` `Systems/` `Utility/` `Rule/` `Extensions/` `Functional/` | `34/34` 个类型声明已带 XML 注释 | `AbstractModel`、`AbstractSystem`、`NumericDisplayFormatter`、`ContextAwareBase`、`Result<T>` |
|
||||
|
||||
完整的模块化阅读顺序和 inventory 说明见 `docs/zh-CN/core/index.md`。
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
```bash
|
||||
@ -80,5 +104,7 @@ dotnet add package GeWuYou.GFramework.Core.Abstractions
|
||||
## 对应文档
|
||||
|
||||
- Core 栏目:[`../docs/zh-CN/core/index.md`](../docs/zh-CN/core/index.md)
|
||||
- Core 抽象层:[`../docs/zh-CN/abstractions/core-abstractions.md`](../docs/zh-CN/abstractions/core-abstractions.md)
|
||||
- API 参考入口:[`../docs/zh-CN/api-reference/index.md`](../docs/zh-CN/api-reference/index.md)
|
||||
- CQRS:[`../docs/zh-CN/core/cqrs.md`](../docs/zh-CN/core/cqrs.md)
|
||||
- 入门指南:[`../docs/zh-CN/getting-started/index.md`](../docs/zh-CN/getting-started/index.md)
|
||||
|
||||
@ -1144,6 +1144,13 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
||||
string HandlerInterfaceDisplayName,
|
||||
string HandlerInterfaceLogName);
|
||||
|
||||
/// <summary>
|
||||
/// 标记某条 handler 注册语句在生成阶段采用的表达策略。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该枚举只服务于输出排序与代码分支选择,用来保证生成注册器在“直接注册”
|
||||
/// “反射实现类型查找”和“精确运行时类型解析”之间保持稳定顺序。
|
||||
/// </remarks>
|
||||
private enum OrderedRegistrationKind
|
||||
{
|
||||
Direct,
|
||||
@ -1151,6 +1158,14 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
||||
PreciseReflected
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 描述生成注册器中某个运行时类型引用的构造方式。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 某些 handler 服务类型可以直接以 <c>typeof(...)</c> 输出,某些则需要在运行时补充
|
||||
/// 反射查找、数组/指针封装或泛型实参重建。该记录把这些差异收敛为统一的递归结构,
|
||||
/// 供源码输出阶段生成稳定的类型解析语句。
|
||||
/// </remarks>
|
||||
private sealed record RuntimeTypeReferenceSpec(
|
||||
string? TypeDisplayName,
|
||||
string? ReflectionTypeMetadataName,
|
||||
@ -1161,18 +1176,27 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
||||
RuntimeTypeReferenceSpec? GenericTypeDefinitionReference,
|
||||
ImmutableArray<RuntimeTypeReferenceSpec> GenericTypeArguments)
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个可直接通过 <c>typeof(...)</c> 表达的类型引用。
|
||||
/// </summary>
|
||||
public static RuntimeTypeReferenceSpec FromDirectReference(string typeDisplayName)
|
||||
{
|
||||
return new RuntimeTypeReferenceSpec(typeDisplayName, null, null, null, 0, null, null,
|
||||
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个需要从当前消费端程序集反射解析的类型引用。
|
||||
/// </summary>
|
||||
public static RuntimeTypeReferenceSpec FromReflectionLookup(string reflectionTypeMetadataName)
|
||||
{
|
||||
return new RuntimeTypeReferenceSpec(null, reflectionTypeMetadataName, null, null, 0, null, null,
|
||||
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个需要从被引用程序集反射解析的类型引用。
|
||||
/// </summary>
|
||||
public static RuntimeTypeReferenceSpec FromExternalReflectionLookup(
|
||||
string reflectionAssemblyName,
|
||||
string reflectionTypeMetadataName)
|
||||
@ -1182,18 +1206,27 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator
|
||||
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个数组类型引用。
|
||||
/// </summary>
|
||||
public static RuntimeTypeReferenceSpec FromArray(RuntimeTypeReferenceSpec elementTypeReference, int arrayRank)
|
||||
{
|
||||
return new RuntimeTypeReferenceSpec(null, null, null, elementTypeReference, arrayRank, null, null,
|
||||
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个指针类型引用。
|
||||
/// </summary>
|
||||
public static RuntimeTypeReferenceSpec FromPointer(RuntimeTypeReferenceSpec pointedAtTypeReference)
|
||||
{
|
||||
return new RuntimeTypeReferenceSpec(null, null, null, null, 0, pointedAtTypeReference, null,
|
||||
ImmutableArray<RuntimeTypeReferenceSpec>.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个封闭泛型类型引用。
|
||||
/// </summary>
|
||||
public static RuntimeTypeReferenceSpec FromConstructedGeneric(
|
||||
RuntimeTypeReferenceSpec genericTypeDefinitionReference,
|
||||
ImmutableArray<RuntimeTypeReferenceSpec> genericTypeArguments)
|
||||
|
||||
@ -651,32 +651,70 @@ internal static class CqrsHandlerRegistrar
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 描述某个程序集在生成注册器之后仍需运行时补扫的 handler 元数据。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该对象把“是否存在精确 fallback 类型列表”与“是否只能回退到整程序集扫描”收敛为同一份内部状态,
|
||||
/// 供注册流水线后续阶段统一判断。
|
||||
/// </remarks>
|
||||
private sealed class ReflectionFallbackMetadata(IReadOnlyList<Type> types)
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取需要通过运行时反射补充注册的 handler 类型集合。
|
||||
/// </summary>
|
||||
public IReadOnlyList<Type> Types { get; } = types ?? throw new ArgumentNullException(nameof(types));
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前是否持有精确的 fallback 类型清单。
|
||||
/// </summary>
|
||||
public bool HasExplicitTypes => Types.Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 描述单个程序集在注册阶段提取到的 generated registry 与 reflection fallback 元数据。
|
||||
/// </summary>
|
||||
private sealed class AssemblyRegistrationMetadata(
|
||||
IReadOnlyList<Type> registryTypes,
|
||||
ReflectionFallbackMetadata? reflectionFallbackMetadata)
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取程序集上声明的 generated registry 类型集合。
|
||||
/// </summary>
|
||||
public IReadOnlyList<Type> RegistryTypes { get; } =
|
||||
registryTypes ?? throw new ArgumentNullException(nameof(registryTypes));
|
||||
|
||||
/// <summary>
|
||||
/// 获取该程序集是否还要求运行时补充 reflection fallback。
|
||||
/// </summary>
|
||||
public ReflectionFallbackMetadata? ReflectionFallbackMetadata { get; } = reflectionFallbackMetadata;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存 generated registry 激活所需的类型判定结果与工厂委托。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该缓存把“是否实现契约”“是否为抽象类型”“是否已构建激活委托”封装为不可变快照,
|
||||
/// 避免对同一 registry 类型重复执行反射分析。
|
||||
/// </remarks>
|
||||
private sealed class RegistryActivationMetadata(
|
||||
bool implementsRegistryContract,
|
||||
bool isAbstract,
|
||||
Func<ICqrsHandlerRegistry>? factory)
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取目标类型是否实现了 <see cref="ICqrsHandlerRegistry" />。
|
||||
/// </summary>
|
||||
public bool ImplementsRegistryContract { get; } = implementsRegistryContract;
|
||||
|
||||
/// <summary>
|
||||
/// 获取目标类型是否为抽象类型。
|
||||
/// </summary>
|
||||
public bool IsAbstract { get; } = isAbstract;
|
||||
|
||||
/// <summary>
|
||||
/// 获取可用于实例化 registry 的工厂委托。
|
||||
/// </summary>
|
||||
public Func<ICqrsHandlerRegistry>? Factory { get; } = factory;
|
||||
}
|
||||
}
|
||||
|
||||
103
GFramework.Ecs.Arch.Abstractions/README.md
Normal file
103
GFramework.Ecs.Arch.Abstractions/README.md
Normal file
@ -0,0 +1,103 @@
|
||||
# GFramework.Ecs.Arch.Abstractions
|
||||
|
||||
`GFramework.Ecs.Arch.Abstractions` 承载 Arch ECS 集成层的最小契约,用来让共享业务层、宿主循环或扩展模块在不依赖
|
||||
`GFramework.Ecs.Arch` 默认实现的前提下,仍然可以约定 ECS 模块边界。
|
||||
|
||||
如果你需要的是 `UseArch(...)` 扩展、`ArchSystemAdapter<T>` 基类、`World` 注册和默认模块实现,请改为依赖
|
||||
`GFramework.Ecs.Arch`。
|
||||
|
||||
## 包定位
|
||||
|
||||
- 这是 `Ecs.Arch` 的契约层,不是默认实现层。
|
||||
- 适合让上层模块只面向 `IArchEcsModule`、`IArchSystemAdapter<T>` 和 `ArchOptions` 编程。
|
||||
- 常见场景:
|
||||
- 共享宿主循环只依赖更新契约,不直接引用 Arch runtime 实现
|
||||
- 多程序集之间需要共享 ECS 配置对象或接口边界
|
||||
- 测试替身、编辑器工具或外部适配层希望复用契约,但自行决定底层实现
|
||||
|
||||
## 与相邻包的关系
|
||||
|
||||
- `GFramework.Core.Abstractions`
|
||||
- 本包直接依赖它,并复用 `IServiceModule`、`ISystem` 等基础契约。
|
||||
- `GFramework.Ecs.Arch.Abstractions`
|
||||
- 只定义 Arch ECS 集成相关的最小契约和配置对象。
|
||||
- `GFramework.Ecs.Arch`
|
||||
- 本包的默认实现层。
|
||||
- 负责 `UseArch(...)` 扩展、默认模块注册、Arch `World` 装配,以及系统适配器基类。
|
||||
|
||||
## 契约地图
|
||||
|
||||
| 文件 | 作用 |
|
||||
| --- | --- |
|
||||
| `IArchEcsModule.cs` | ECS 模块服务契约,负责统一驱动系统更新 |
|
||||
| `IArchSystemAdapter.cs` | 让 ECS 系统适配到 GFramework `ISystem` 生命周期的接口 |
|
||||
| `ArchOptions.cs` | `WorldCapacity`、`EnableStatistics`、`Priority` 等配置对象 |
|
||||
|
||||
## XML 阅读基线
|
||||
|
||||
下表记录当前契约包的类型声明级 XML 基线,方便把 README、站内抽象页与源码阅读顺序对齐。
|
||||
|
||||
| 类型族 | 代表类型 | XML 状态 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| 模块契约 | `IArchEcsModule` | 已覆盖 | 宿主循环如何统一驱动 ECS 更新 |
|
||||
| 系统桥接契约 | `IArchSystemAdapter<T>` | 已覆盖 | 外部模块怎样只依赖更新接口而不绑定默认实现 |
|
||||
| 配置对象 | `ArchOptions` | 已覆盖 | 跨程序集共享 ECS 配置边界 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
### 1. 只想约定宿主循环与 ECS 模块边界
|
||||
|
||||
```csharp
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
public sealed class EcsUpdateLoop
|
||||
{
|
||||
private readonly IArchEcsModule _ecsModule;
|
||||
|
||||
public EcsUpdateLoop(IArchEcsModule ecsModule)
|
||||
{
|
||||
_ecsModule = ecsModule;
|
||||
}
|
||||
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
_ecsModule.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 只想共享配置对象
|
||||
|
||||
```csharp
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
var options = new ArchOptions
|
||||
{
|
||||
WorldCapacity = 2048,
|
||||
EnableStatistics = true,
|
||||
Priority = 40
|
||||
};
|
||||
```
|
||||
|
||||
### 3. 什么时候要升级到 `GFramework.Ecs.Arch`
|
||||
|
||||
一旦你需要下面任一项,就不该只停留在本包:
|
||||
|
||||
- `UseArch(...)` 或其他 runtime 装配入口
|
||||
- `ArchSystemAdapter<T>` 等默认基类
|
||||
- Arch `World` 的创建、注册和查询能力
|
||||
- 与 `GFramework` 架构生命周期绑定的默认模块实现
|
||||
|
||||
## 边界说明
|
||||
|
||||
- 本包不提供 Arch `World` 的默认构造与注册逻辑。
|
||||
- 本包不提供系统基类、扩展方法或默认服务实现。
|
||||
- 它回答的是“外部模块怎样与 Arch ECS 集成层约定边界”,不是“Arch ECS 默认怎么接入到项目里”。
|
||||
|
||||
## 对应文档入口
|
||||
|
||||
- 抽象接口总览:[`../docs/zh-CN/abstractions/index.md`](../docs/zh-CN/abstractions/index.md)
|
||||
- Ecs.Arch 抽象层说明:[`../docs/zh-CN/abstractions/ecs-arch-abstractions.md`](../docs/zh-CN/abstractions/ecs-arch-abstractions.md)
|
||||
- ECS 模块入口:[`../docs/zh-CN/ecs/index.md`](../docs/zh-CN/ecs/index.md)
|
||||
- Arch ECS 集成:[`../docs/zh-CN/ecs/arch.md`](../docs/zh-CN/ecs/arch.md)
|
||||
- 运行时实现入口:[`../GFramework.Ecs.Arch/README.md`](../GFramework.Ecs.Arch/README.md)
|
||||
@ -1,16 +1,30 @@
|
||||
# GFramework.Ecs.Arch
|
||||
|
||||
GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component System)支持。
|
||||
`GFramework.Ecs.Arch` 是 `GFramework` 当前 Arch ECS family 的默认运行时实现包。
|
||||
|
||||
## 特性
|
||||
它负责把 Arch `World`、GFramework 的服务模块生命周期,以及 `ArchSystemAdapter<T>` 系统桥接到同一条采用路径中。
|
||||
如果你需要的只是共享契约,请改为依赖 `GFramework.Ecs.Arch.Abstractions`。
|
||||
|
||||
- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式
|
||||
- 🔌 **零依赖** - 不使用时,Core 包无 Arch 依赖
|
||||
- 🎯 **类型安全** - 完整的类型系统和编译时检查
|
||||
- ⚡ **高性能** - 基于 Arch ECS 的高性能实现
|
||||
- 🔧 **易扩展** - 简单的系统适配器模式
|
||||
## 包定位
|
||||
|
||||
## 快速开始
|
||||
- 这是运行时实现层,不是纯契约层。
|
||||
- 适合需要 `UseArch(...)`、`World` 自动注册、默认模块生命周期和系统桥接基类的项目。
|
||||
- 常见场景:
|
||||
- 在架构实例上显式接入 Arch ECS
|
||||
- 让 `World` 由默认模块创建并放入容器
|
||||
- 让 ECS 系统复用 `ArchSystemAdapter<float>` 生命周期桥接
|
||||
- 通过 `IArchEcsModule.Update(deltaTime)` 统一驱动 ECS 帧更新
|
||||
|
||||
## 与相邻包的关系
|
||||
|
||||
- `GFramework.Core`
|
||||
- 提供架构、容器、生命周期和系统注册基础设施。
|
||||
- `GFramework.Ecs.Arch.Abstractions`
|
||||
- 提供 `IArchEcsModule`、`IArchSystemAdapter<T>` 和契约层 `ArchOptions`。
|
||||
- `GFramework.Ecs.Arch`
|
||||
- 提供 `UseArch(...)`、默认 `ArchEcsModule`、`World` 注册,以及系统适配器基类与示例类型。
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
### 1. 安装包
|
||||
|
||||
@ -18,53 +32,43 @@ GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component
|
||||
dotnet add package GeWuYou.GFramework.Ecs.Arch
|
||||
```
|
||||
|
||||
### 2. 注册 ECS 模块
|
||||
### 2. 在 `Initialize()` 之前显式接入 Arch runtime
|
||||
|
||||
按当前实现,`UseArch(...)` 会把 `ArchEcsModule` 提前登记到 `ArchitectureModuleRegistry`,因此调用时机应早于
|
||||
`Initialize()`。
|
||||
|
||||
```csharp
|
||||
// 在架构初始化时添加 Arch ECS 支持
|
||||
var architecture = new GameArchitecture(config)
|
||||
.UseArch(); // 添加 ECS 支持
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Ecs.Arch.Extensions;
|
||||
|
||||
architecture.Initialize();
|
||||
```
|
||||
public sealed class GameArchitecture : Architecture
|
||||
{
|
||||
public GameArchitecture() : base(new ArchitectureConfiguration())
|
||||
{
|
||||
}
|
||||
|
||||
### 3. 带配置的注册
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
RegisterSystem<MovementSystem>();
|
||||
}
|
||||
}
|
||||
|
||||
```csharp
|
||||
var architecture = new GameArchitecture(config)
|
||||
var architecture = new GameArchitecture()
|
||||
.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000;
|
||||
options.EnableStatistics = true;
|
||||
options.WorldCapacity = 2048;
|
||||
options.Priority = 50;
|
||||
});
|
||||
|
||||
architecture.Initialize();
|
||||
```
|
||||
|
||||
```csharp
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Velocity(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 创建系统
|
||||
### 3. 编写并注册系统
|
||||
|
||||
```csharp
|
||||
using Arch.Core;
|
||||
using GFramework.Ecs.Arch;
|
||||
using GFramework.Ecs.Arch.Components;
|
||||
|
||||
public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
@ -78,115 +82,57 @@ public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
World.Query(in _query, (ref Position pos, ref Velocity vel) =>
|
||||
var frameDelta = deltaTime;
|
||||
|
||||
World.Query(in _query, (ref Position position, ref Velocity velocity) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
position.X += velocity.X * frameDelta;
|
||||
position.Y += velocity.Y * frameDelta;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 注册系统
|
||||
### 4. 初始化后获取 `World` 与 ECS 模块
|
||||
|
||||
```csharp
|
||||
public class MyArchitecture : Architecture
|
||||
{
|
||||
protected override void OnRegisterSystem(IIocContainer container)
|
||||
{
|
||||
container.Register<MovementSystem>();
|
||||
}
|
||||
}
|
||||
using Arch.Core;
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
var world = architecture.Context.GetService<World>();
|
||||
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
```
|
||||
|
||||
### 7. 创建实体
|
||||
### 5. 由宿主循环驱动更新
|
||||
|
||||
```csharp
|
||||
var world = this.GetService<World>();
|
||||
var entity = world.Create(
|
||||
new Position(0, 0),
|
||||
new Velocity(1, 1)
|
||||
);
|
||||
```
|
||||
|
||||
### 8. 更新系统
|
||||
|
||||
```csharp
|
||||
var ecsModule = this.GetService<IArchEcsModule>();
|
||||
ecsModule.Update(deltaTime);
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
## 运行时职责地图
|
||||
|
||||
### 代码配置
|
||||
| 文件 | 作用 |
|
||||
| --- | --- |
|
||||
| `Extensions/ArchExtensions.cs` | 通过 `UseArch(...)` 把默认模块注册到 `ArchitectureModuleRegistry` |
|
||||
| `ArchEcsModule.cs` | 创建并注册 `World`,按优先级收集 `ArchSystemAdapter<float>`,负责初始化、销毁和逐帧更新 |
|
||||
| `ArchSystemAdapter.cs` | 把 GFramework 系统生命周期桥接到 Arch `ISystem<T>` 生命周期 |
|
||||
| `ArchOptions.cs` | 承载 `WorldCapacity`、`EnableStatistics`、`Priority` 这组运行时配置 |
|
||||
| `Components/*.cs`、`Systems/*.cs` | 提供最小组件与系统示例,帮助对照查询写法和更新模式 |
|
||||
|
||||
```csharp
|
||||
var architecture = new GameArchitecture(config)
|
||||
.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000;
|
||||
options.EnableStatistics = true;
|
||||
options.Priority = 50;
|
||||
});
|
||||
```
|
||||
## XML 阅读基线
|
||||
|
||||
### 配置说明
|
||||
下表记录当前模块 README 与源码可对照的类型声明级 XML 基线。
|
||||
|
||||
- `WorldCapacity` - World 初始容量(默认:1000)
|
||||
- `EnableStatistics` - 是否启用统计信息(默认:false)
|
||||
- `Priority` - 模块优先级(默认:50)
|
||||
| 类型族 | 代表类型 | XML 状态 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| 装配入口 | `ArchExtensions` | 已覆盖 | `UseArch(...)` 的时机与返回值 |
|
||||
| 运行时模块 | `ArchEcsModule` | 已覆盖 | `World` 注册、系统排序、销毁顺序 |
|
||||
| 系统桥接层 | `ArchSystemAdapter<T>` | 已覆盖 | `OnArchInitialize`、`OnUpdate`、`OnArchDispose` |
|
||||
| 示例类型 | `Position`、`Velocity`、`MovementSystem` | 已覆盖 | 组件布局、查询写法、最小示例 |
|
||||
|
||||
## 架构说明
|
||||
## 对应文档入口
|
||||
|
||||
### 显式注册模式
|
||||
|
||||
本包采用 .NET 生态标准的显式注册模式,基于架构实例:
|
||||
|
||||
**优点:**
|
||||
|
||||
- ✅ 符合 .NET 生态习惯
|
||||
- ✅ 显式、可控
|
||||
- ✅ 易于测试和调试
|
||||
- ✅ 支持配置
|
||||
- ✅ 支持链式调用
|
||||
- ✅ 避免"魔法"行为
|
||||
|
||||
**使用方式:**
|
||||
```csharp
|
||||
// 在架构初始化时添加
|
||||
var architecture = new GameArchitecture(config)
|
||||
.UseArch(); // 显式注册
|
||||
|
||||
architecture.Initialize();
|
||||
```
|
||||
|
||||
详见:[INTEGRATION_PATTERN.md](INTEGRATION_PATTERN.md)
|
||||
|
||||
### 系统适配器
|
||||
|
||||
`ArchSystemAdapter<T>` 桥接 Arch.System.ISystem<T> 到 GFramework 架构:
|
||||
|
||||
- 自动获取 World 实例
|
||||
- 集成到框架生命周期
|
||||
- 支持上下文感知(Context-Aware)
|
||||
|
||||
### 生命周期
|
||||
|
||||
1. **注册阶段** - 模块自动注册到架构
|
||||
2. **初始化阶段** - 创建 World,初始化系统
|
||||
3. **运行阶段** - 每帧调用 Update
|
||||
4. **销毁阶段** - 清理资源,销毁 World
|
||||
|
||||
## 示例
|
||||
|
||||
完整示例请参考 `GFramework.Ecs.Arch.Tests` 项目。
|
||||
|
||||
## 依赖
|
||||
|
||||
- GFramework.Core >= 1.0.0
|
||||
- Arch >= 2.1.0
|
||||
- Arch.System >= 1.1.0
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
- ECS 总览:[`../docs/zh-CN/ecs/index.md`](../docs/zh-CN/ecs/index.md)
|
||||
- Arch ECS 集成:[`../docs/zh-CN/ecs/arch.md`](../docs/zh-CN/ecs/arch.md)
|
||||
- 抽象契约页:[`../docs/zh-CN/abstractions/ecs-arch-abstractions.md`](../docs/zh-CN/abstractions/ecs-arch-abstractions.md)
|
||||
- 统一 API / XML 导航:[`../docs/zh-CN/api-reference/index.md`](../docs/zh-CN/api-reference/index.md)
|
||||
|
||||
@ -131,6 +131,20 @@ Scene 与 UI 路由共享这套基础约定。
|
||||
- `Enums/`
|
||||
- UI/Scene 转场、UI 层级、输入动作、存储类型等公共枚举
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
下面这份 inventory 记录的是 `2026-04-23` 对 `GFramework.Game.Abstractions` 做的一轮轻量 XML 盘点结果:只统计公开 /
|
||||
内部类型声明是否带 XML 注释,用来建立契约层阅读入口;成员级参数、返回值、异常和生命周期说明仍需要在后续 API 波次继续细化。
|
||||
|
||||
| 契约族 | 基线状态 | 代表类型 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Config/` | `7/7` 个类型声明已带 XML 注释 | `IConfigLoader`、`IConfigRegistry`、`IConfigTable<TKey, TValue>`、`ConfigLoadException` | 看配置表注册、读取约定和失败诊断模型 |
|
||||
| `Data/` | `14/14` 个类型声明已带 XML 注释 | `IDataRepository`、`ISettingsDataRepository`、`ISaveRepository<TSaveData>`、`DataRepositoryOptions` | 看业务数据、设置持久化、槽位存档和版本迁移契约 |
|
||||
| `Setting/` | `12/12` 个类型声明已带 XML 注释 | `ISettingsData`、`ISettingsModel`、`ISettingsSystem`、`LocalizationSettings` | 看设置数据、应用语义、迁移接口和内置设置对象 |
|
||||
| `Scene/` | `14/14` 个类型声明已带 XML 注释 | `IScene`、`ISceneRouter`、`ISceneFactory`、`SceneTransitionEvent` | 看场景行为、路由、工厂 / root 边界与转场事件模型 |
|
||||
| `UI/` | `19/19` 个类型声明已带 XML 注释 | `IUiPage`、`IUiRouter`、`IUiFactory`、`UiInteractionProfile`、`UiTransitionHandlerOptions` | 看页面栈、层级 UI、输入动作与 UI 转场契约 |
|
||||
| `Routing/` `Storage/` `Asset/` `Enums/` | `13/13` 个类型声明已带 XML 注释 | `IRoute`、`IRouteContext`、`IFileStorage`、`IAssetRegistry<T>`、`UiLayer`、`SceneTransitionType` | 看公共路由上下文、存储角色、资源注册表与跨层共享枚举 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
### 1. 只想在公共业务层声明游戏对象
|
||||
|
||||
@ -44,6 +44,15 @@ GameProject/
|
||||
|
||||
默认情况下,打包产物会通过 `targets` 把 `schemas/**/*.schema.json` 纳入 `AdditionalFiles`。
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
下面这份 inventory 记录的是 `2026-04-23` 对 `GFramework.Game.SourceGenerators` 做的一轮轻量 XML 盘点结果:只统计公开类型声明是否带 XML 注释,用来建立生成器入口;具体诊断消息、生成输出和兼容性语义仍需要回到源码与测试继续核对。
|
||||
|
||||
| 类型族 | 基线状态 | 代表类型 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Config/` | `1/1` 个类型声明已带 XML 注释 | `SchemaConfigGenerator` | 看 schema 到配置类型 / 表包装 / 注册辅助代码的生成入口 |
|
||||
| `Diagnostics/` | `1/1` 个类型声明已带 XML 注释 | `ConfigSchemaDiagnostics` | 看生成器会抛出的诊断类别与失败边界 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
```xml
|
||||
|
||||
@ -169,6 +169,19 @@
|
||||
|
||||
这两部分一般被上层子系统消费,不是多数项目的第一接入点。
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
下面这份 inventory 记录的是 `2026-04-23` 对 `GFramework.Game` 做的一轮轻量 XML 盘点结果:只统计公开 /
|
||||
内部类型声明是否带 XML 注释,用来建立运行时阅读入口;成员级参数、返回值、异常和生命周期说明仍需要在后续 API 波次继续细化。
|
||||
|
||||
| 子系统 | 基线状态 | 代表类型 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Config/` | `26/26` 个类型声明已带 XML 注释 | `YamlConfigLoader`、`ConfigRegistry`、`GameConfigBootstrap`、`YamlConfigSchemaValidator` | 看 YAML 加载、schema 校验、模块接入与热重载边界 |
|
||||
| `Data/` `Storage/` `Serializer/` | `8/8` 个类型声明已带 XML 注释 | `DataRepository`、`SaveRepository<TSaveData>`、`UnifiedSettingsDataRepository`、`FileStorage`、`JsonSerializer` | 看持久化布局、槽位存档、统一设置文件和底层序列化 / 存储实现 |
|
||||
| `Setting/` | `9/9` 个类型声明已带 XML 注释 | `SettingsModel<TRepository>`、`SettingsSystem`、`SettingsAppliedEvent<T>` | 看初始化、应用、保存、重置等设置生命周期编排 |
|
||||
| `Scene/` `UI/` `Routing/` | `10/10` 个类型声明已带 XML 注释 | `SceneRouterBase`、`UiRouterBase`、`SceneTransitionPipeline`、`UiTransitionPipeline`、`RouterBase<TRoute, TContext>` | 看路由基类、转换处理器和项目层需要自己提供的 factory / root 边界 |
|
||||
| `Extensions/` `Internal/` `State/` | `3/3` 个类型声明已带 XML 注释 | `DataLocationExtensions`、`VersionedMigrationRunner`、`GameStateMachineSystem` | 看辅助扩展、内部迁移执行逻辑和游戏态状态机封装 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
下面按最常见的四种接入目标给出最短路径。
|
||||
|
||||
14
README.md
14
README.md
@ -27,11 +27,22 @@
|
||||
| `GFramework.Game.Abstractions` | `Game` 对应的契约层 | [README](GFramework.Game.Abstractions/README.md) |
|
||||
| `GFramework.Godot` | Godot 集成层,负责把框架能力接入节点、场景、UI、设置与存储 | [README](GFramework.Godot/README.md) |
|
||||
| `GFramework.Ecs.Arch` | Arch ECS 集成 | [README](GFramework.Ecs.Arch/README.md) |
|
||||
| `GFramework.Ecs.Arch.Abstractions` | Arch ECS 集成对应的契约层,适合共享宿主循环与 ECS 模块边界 | [README](GFramework.Ecs.Arch.Abstractions/README.md) |
|
||||
| `GFramework.Core.SourceGenerators` | Core 侧通用源码生成器与分析器 | [README](GFramework.Core.SourceGenerators/README.md) |
|
||||
| `GFramework.Game.SourceGenerators` | 游戏内容配置 schema 生成器 | [README](GFramework.Game.SourceGenerators/README.md) |
|
||||
| `GFramework.Cqrs.SourceGenerators` | CQRS handler registry 生成器 | [README](GFramework.Cqrs.SourceGenerators/README.md) |
|
||||
| `GFramework.Godot.SourceGenerators` | Godot 场景专用源码生成器 | [README](GFramework.Godot.SourceGenerators/README.md) |
|
||||
|
||||
## 内部支撑模块
|
||||
|
||||
以下目录目前不是独立采用入口,而是跟随所属模块维护的内部支撑组件:
|
||||
|
||||
| 目录 | 定位 | 跟随入口 |
|
||||
| --- | --- | --- |
|
||||
| `GFramework.Core.SourceGenerators.Abstractions` | `Core.SourceGenerators` 的内部契约层 | [GFramework.Core.SourceGenerators/README.md](GFramework.Core.SourceGenerators/README.md) |
|
||||
| `GFramework.Godot.SourceGenerators.Abstractions` | `Godot.SourceGenerators` 的内部契约层 | [GFramework.Godot.SourceGenerators/README.md](GFramework.Godot.SourceGenerators/README.md) |
|
||||
| `GFramework.SourceGenerators.Common` | 生成器家族共享的公共支撑代码 | [docs/zh-CN/source-generators/index.md](docs/zh-CN/source-generators/index.md) |
|
||||
|
||||
## 文档导航
|
||||
|
||||
仓库根 README 与文档站点保持同一套栏目命名:
|
||||
@ -119,10 +130,13 @@ GFramework.sln
|
||||
├─ GFramework.Game.Abstractions/
|
||||
├─ GFramework.Godot/
|
||||
├─ GFramework.Ecs.Arch/
|
||||
├─ GFramework.Ecs.Arch.Abstractions/
|
||||
├─ GFramework.Core.SourceGenerators/
|
||||
├─ GFramework.Core.SourceGenerators.Abstractions/
|
||||
├─ GFramework.Game.SourceGenerators/
|
||||
├─ GFramework.Cqrs.SourceGenerators/
|
||||
├─ GFramework.Godot.SourceGenerators/
|
||||
├─ GFramework.Godot.SourceGenerators.Abstractions/
|
||||
├─ GFramework.SourceGenerators.Common/
|
||||
└─ docs/
|
||||
```
|
||||
|
||||
@ -25,6 +25,11 @@ help the current worktree land on the right recovery documents without scanning
|
||||
- Purpose: continue the AI-First config runtime, generator, and consumer DX work for `GFramework.Game`.
|
||||
- Tracking: `ai-plan/public/ai-first-config-system/todos/ai-first-config-system-tracking.md`
|
||||
- Trace: `ai-plan/public/ai-first-config-system/traces/ai-first-config-system-trace.md`
|
||||
- `documentation-full-coverage-governance`
|
||||
- Purpose: govern full-coverage documentation inventory, module-wave remediation, and the README / docs / XML /
|
||||
API-reference alignment baseline.
|
||||
- Tracking: `ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md`
|
||||
- Trace: `ai-plan/public/documentation-full-coverage-governance/traces/documentation-full-coverage-governance-trace.md`
|
||||
- `coroutine-optimization`
|
||||
- Purpose: continue the coroutine semantics, host integration, observability, regression coverage, and migration-doc
|
||||
follow-up work.
|
||||
@ -38,10 +43,6 @@ help the current worktree land on the right recovery documents without scanning
|
||||
- Purpose: continue the data repository persistence hardening plus the settings / serialization follow-up backlog.
|
||||
- Tracking: `ai-plan/public/data-repository-persistence/todos/data-repository-persistence-tracking.md`
|
||||
- Trace: `ai-plan/public/data-repository-persistence/traces/data-repository-persistence-trace.md`
|
||||
- `documentation-governance-and-refresh`
|
||||
- Purpose: continue the documentation governance, README hardening, and `docs/zh-CN` accuracy refresh work.
|
||||
- Tracking: `ai-plan/public/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md`
|
||||
- Trace: `ai-plan/public/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md`
|
||||
|
||||
## Worktree To Active Topic Map
|
||||
|
||||
@ -64,10 +65,12 @@ help the current worktree land on the right recovery documents without scanning
|
||||
- Priority 1: `data-repository-persistence`
|
||||
- Branch: `docs/sdk-update-documentation`
|
||||
- Worktree hint: `GFramework-update-documentation`
|
||||
- Priority 1: `documentation-governance-and-refresh`
|
||||
|
||||
- Priority 1: `documentation-full-coverage-governance`
|
||||
## Archived Topics
|
||||
|
||||
- `cqrs-cache-docs-hardening`
|
||||
- Archive root: `ai-plan/public/archive/cqrs-cache-docs-hardening/`
|
||||
- Note: archived topics stay outside the default `boot` context until a user explicitly requests historical review.
|
||||
- `documentation-governance-and-refresh`
|
||||
- Archive root: `ai-plan/public/archive/documentation-governance-and-refresh/`
|
||||
- Note: PR #268 已合并;文档治理与 Godot 栏目刷新阶段已完成,后续仅作为历史恢复材料保留。
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
# Documentation Governance And Refresh 跟踪
|
||||
|
||||
## 目标
|
||||
|
||||
继续以“文档必须可追溯到源码、测试与真实接入方式”为原则,维护 `GFramework` 的仓库入口、模块入口与
|
||||
`docs/zh-CN` 采用链路,避免 README、专题页与教程再次偏离当前实现。
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`DOCUMENTATION-GOVERNANCE-REFRESH-RP-019`
|
||||
- 当前阶段:`Completed`
|
||||
- 当前焦点:
|
||||
- 用户已确认 PR #268 合并,本 topic 对应的文档治理收口工作完成
|
||||
- 当前目录将在本轮迁入 `ai-plan/public/archive/documentation-governance-and-refresh/`
|
||||
- 后续若需历史回溯,应从 archive 中恢复,而不是继续把该 topic 作为 active 默认入口
|
||||
|
||||
## 当前状态摘要
|
||||
|
||||
- `docs/zh-CN/godot/` 当前高优先级页面集与 `docs/zh-CN/tutorials/godot-integration.md` 已完成源码优先收口
|
||||
- PR #268 已合并,上一轮保留 active 的唯一原因已经解除
|
||||
- 本 topic 已达到归档条件:实现完成、校验完成、PR 生命周期结束
|
||||
|
||||
## 当前活跃事实
|
||||
|
||||
- 当前 worktree 下未发现 `ai-plan/private/` 恢复目录,本主题一直以 public artifacts 作为唯一恢复入口
|
||||
- 已存在的阶段归档:
|
||||
- `ai-plan/public/documentation-governance-and-refresh/archive/todos/documentation-governance-and-refresh-history-through-2026-04-22.md`
|
||||
- `ai-plan/public/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-history-through-2026-04-22.md`
|
||||
- 2026-04-22 之前的长篇历史已存在于 2026-04-18 与 RP-001 through RP-008 的归档文件中
|
||||
- 当前待处理事项已清零;后续只保留历史查询价值
|
||||
|
||||
## 当前风险
|
||||
|
||||
- 后续历史定位风险:如果不把 topic 从 active 列表中移除,`boot` 会继续把已经完成的文档治理主题当作默认入口
|
||||
- 缓解措施:本轮同步更新 `ai-plan/public/README.md` 并把整个 topic 目录迁入 `ai-plan/public/archive/`
|
||||
- 文档回漂风险:未来若有新的 README / `docs/zh-CN` 变更,仍可能重新引入与源码不一致的表述
|
||||
- 缓解措施:新任务应创建或复用新的 active topic,而不是重启当前已完成主题
|
||||
|
||||
## 活跃文档
|
||||
|
||||
- 当前 trace:[documentation-governance-and-refresh-trace.md](../traces/documentation-governance-and-refresh-trace.md)
|
||||
- 2026-04-22 跟踪归档:[documentation-governance-and-refresh-history-through-2026-04-22.md](../archive/todos/documentation-governance-and-refresh-history-through-2026-04-22.md)
|
||||
- 2026-04-22 trace 归档:[documentation-governance-and-refresh-history-through-2026-04-22.md](../archive/traces/documentation-governance-and-refresh-history-through-2026-04-22.md)
|
||||
- 2026-04-18 历史归档:[documentation-governance-and-refresh-history-through-2026-04-18.md](../archive/todos/documentation-governance-and-refresh-history-through-2026-04-18.md)
|
||||
- RP-001 到 RP-008 trace 归档:[documentation-governance-and-refresh-rp-001-through-rp-008.md](../archive/traces/documentation-governance-and-refresh-rp-001-through-rp-008.md)
|
||||
|
||||
## 验证说明
|
||||
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/godot/index.md`
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/godot/architecture.md`
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/godot/scene.md`
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/godot/ui.md`
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/godot/signal.md`
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/godot/extensions.md`
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/godot/logging.md`
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/tutorials/godot-integration.md`
|
||||
- `cd docs && bun run build`
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 将整个 `documentation-governance-and-refresh` 目录迁入 `ai-plan/public/archive/`
|
||||
2. 从 `ai-plan/public/README.md` 删除该 topic 的 active 声明与 worktree 映射
|
||||
@ -0,0 +1,26 @@
|
||||
# Documentation Governance And Refresh Trace
|
||||
|
||||
## 2026-04-22
|
||||
|
||||
### 当前恢复点:RP-019
|
||||
|
||||
- 本轮按 `boot` 恢复 `documentation-governance-and-refresh` 主题
|
||||
- 用户明确说明 PR #268 已合并,因此该主题不再需要保持 active 以等待 review follow-up
|
||||
- 当前主题满足完成条件:文档页已完成校验、`docs` 站点先前已构建通过、PR 生命周期结束
|
||||
- 本轮将把整个主题目录迁入 `ai-plan/public/archive/documentation-governance-and-refresh/`
|
||||
- `ai-plan/public/README.md` 也将在本轮删除该 topic 的 active 声明与 worktree 映射
|
||||
|
||||
### 当前决策
|
||||
|
||||
- 当前主题正式归档,不再作为 `boot` 默认入口
|
||||
- 若未来出现新的文档治理任务,应创建新的 active topic 或挂到新的现役主题,而不是恢复本目录
|
||||
- 现有 tracking / trace 留在 archive 中作为历史恢复材料
|
||||
|
||||
### 验证
|
||||
|
||||
- `cd docs && bun run build`
|
||||
- 结果:通过;无构建失败,主题满足归档前的最终验证要求
|
||||
|
||||
### 下一步
|
||||
|
||||
1. 若需回看本阶段历史,从 `ai-plan/public/archive/documentation-governance-and-refresh/` 读取归档材料
|
||||
@ -0,0 +1,77 @@
|
||||
# Documentation Full Coverage Governance Validation History Through RP-007
|
||||
|
||||
以下内容从 active tracking 中迁出,用于保留 `DOCUMENTATION-FULL-COVERAGE-GOV-RP-001` 到
|
||||
`DOCUMENTATION-FULL-COVERAGE-GOV-RP-007` 的详细验证历史。默认 `boot` 只需要读取 active tracking 中的最新摘要;
|
||||
若需要追溯早期验证命令与结果,再回到本归档文件。
|
||||
|
||||
## 详细验证历史
|
||||
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/abstractions/index.md`
|
||||
- 结果:通过
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/abstractions/ecs-arch-abstractions.md`
|
||||
- 结果:通过
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/api-reference/index.md`
|
||||
- 结果:通过
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/core/index.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在补充 Core XML inventory 后重新验证
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/abstractions/core-abstractions.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在补充 Core.Abstractions XML inventory 后重新验证
|
||||
- `cd docs && bun run build`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 重新构建通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
- `dotnet build GFramework.Ecs.Arch.Abstractions/GFramework.Ecs.Arch.Abstractions.csproj -c Release -p:RestoreFallbackFolders=`
|
||||
- 结果:通过
|
||||
- 备注:`0 Warning(s) / 0 Error(s)`
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home dotnet build GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj -c Release -p:RestoreFallbackFolders=`
|
||||
- 结果:通过
|
||||
- 备注:`0 Warning(s) / 0 Error(s)`
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/ecs/index.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在重写 ECS landing 后重新验证
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/ecs/arch.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在重写 Arch ECS 专题页后重新验证
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/abstractions/ecs-arch-abstractions.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在补充抽象页 XML inventory 后重新验证
|
||||
- `cd docs && bun run build`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在 Ecs 波次重写后重新构建通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/core/cqrs.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在重写 `Cqrs` family landing 后重新验证
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在新增 `Cqrs.SourceGenerators` 专题页后验证通过
|
||||
- `python3` 轻量 XML inventory 扫描
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 确认 `GFramework.Cqrs` 的 `Internal/` 为 `14/14`、`GFramework.Cqrs.SourceGenerators/Cqrs/` 为 `3/3`、`GFramework.Cqrs.Abstractions/Cqrs/` 为 `20/20`
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release -p:RestoreFallbackFolders=`
|
||||
- 结果:通过
|
||||
- 备注:保留既有 `NU1900` 与 `MA0051` warnings;无新增编译错误
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`
|
||||
- 结果:失败
|
||||
- 备注:当前环境会命中失效的 Windows fallback package folder,并在多目标 inner build 阶段触发 `MSB4276` / `MSB4018`;失败原因已记录为环境阻塞,不属于本轮文档改动回归
|
||||
- `cd docs && bun run build`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-22` 在 `Cqrs` 波次文档刷新后重新构建通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/abstractions/game-abstractions.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-23` 在重写 `Game.Abstractions` 页面后验证通过
|
||||
- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/game/index.md`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-23` 在补充 frontmatter 与 XML inventory 后重新验证
|
||||
- `python3` 轻量 XML inventory 扫描
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-23` 确认 `GFramework.Game` 为 `56/56`、`GFramework.Game.Abstractions` 为 `80/80`、`GFramework.Game.SourceGenerators` 为 `2/2`
|
||||
- `cd docs && bun run build`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-23` 在 `Game` 波次文档刷新后重新构建通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
- `cd docs && bun run build`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-23` 在更新 `AGENTS.md` 的 WSL Git 优先级后重新构建通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
- `cd docs && bun run build`
|
||||
- 结果:通过
|
||||
- 备注:`2026-04-23` 在推进 `DOCUMENTATION-FULL-COVERAGE-GOV-RP-007`、回写 `Game` family 巡检结论后重新构建通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
@ -0,0 +1,124 @@
|
||||
# Documentation Full Coverage Governance 跟踪
|
||||
|
||||
## 目标
|
||||
|
||||
建立一个长期 active topic,持续治理 `GFramework` 的 README、`docs/zh-CN`、站点导航、XML 文档和 API
|
||||
参考链路,避免历史上的阶段性刷新完成后再次回漂。
|
||||
|
||||
- 用源码、测试、`*.csproj` 和必要的 `ai-libs/` 证据校正文档
|
||||
- 以模块族为单位闭环 README、landing page、专题页、教程入口和 API 参考链路
|
||||
- 明确哪些目录是可直接消费模块,哪些只是内部支撑模块
|
||||
- 把 XML 文档缺口纳入治理范围,而不是只刷新 Markdown
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`DOCUMENTATION-FULL-COVERAGE-GOV-RP-008`
|
||||
- 当前阶段:`Phase 5 - Governance Maintenance`
|
||||
- 当前焦点:
|
||||
- 消化 PR #271 的 latest-head review follow-up,修正仍在本地成立的 docs / skill / ai-plan 问题
|
||||
- 将 active tracking 的重复验证明细迁出默认 boot 路径,只保留最新可恢复摘要
|
||||
- 评估是否需要把 `Godot` family 的关键 XML inventory 摘要迁回 active topic
|
||||
|
||||
## 当前状态摘要
|
||||
|
||||
- 已归档的 `documentation-governance-and-refresh` 仅保留为历史证据,不再作为默认 `boot` 入口
|
||||
- 本轮已消化的 PR #271 review follow-up:
|
||||
- 为 `.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py` 补齐 WSL worktree 下的显式 Linux Git 绑定,避免 `git.exe` 在当前会话触发 `Exec format error`
|
||||
- 同步更新 `.agents/skills/gframework-pr-review/SKILL.md`,改为与 `AGENTS.md` 一致的 Git 策略,并把命令示例统一到 `.agents/...` 路径
|
||||
- 为 `docs/zh-CN/source-generators/cqrs-handler-registry-generator.md` 补充 marker 类型放置与命名约定说明
|
||||
- 从 `docs/zh-CN/abstractions/ecs-arch-abstractions.md` 删除误放的 source-generator 内部模块提醒,并微调 `docs/zh-CN/ecs/index.md` 的边界说明语序
|
||||
- 为 `ai-plan/public/archive/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md` 的归档验证补写结果态
|
||||
- 将 RP-001 至 RP-007 的详细验证历史迁入 `ai-plan/public/documentation-full-coverage-governance/archive/todos/documentation-full-coverage-governance-validation-history-through-rp-007.md`
|
||||
- 本轮已确认的消费属性结论:
|
||||
- `GFramework.Ecs.Arch.Abstractions`:可打包直接消费模块,需要 README 和文档入口
|
||||
- `GFramework.Core.SourceGenerators.Abstractions`:`IsPackable=false`,按内部支撑模块处理
|
||||
- `GFramework.Godot.SourceGenerators.Abstractions`:`IsPackable=false`,按内部支撑模块处理
|
||||
- `GFramework.SourceGenerators.Common`:`IsPackable=false`,按内部支撑模块处理
|
||||
- 本轮已完成的治理动作:
|
||||
- 新建 `GFramework.Ecs.Arch.Abstractions/README.md`
|
||||
- 在根 `README.md` 中补齐 `GFramework.Ecs.Arch.Abstractions` 入口,并声明内部支撑模块 owner
|
||||
- 为抽象接口栏目补齐 `Ecs.Arch.Abstractions` 页面与 sidebar 入口
|
||||
- 将 `docs/zh-CN/api-reference/index.md` 重写为模块到 XML / README / 教程的阅读链路入口
|
||||
- 为 `GFramework.Core/README.md` 补齐 `Services`、`Configuration`、`Environment`、`Pool`、`Rule`、`Time` 等当前目录映射
|
||||
- 为 `GFramework.Core.Abstractions/README.md` 补齐契约族地图与 XML 阅读重点
|
||||
- 将 `docs/zh-CN/abstractions/core-abstractions.md` 从过时的接口摘录页重写为契约边界 / 包关系 / 最小接入路径页面
|
||||
- 为 `docs/zh-CN/core/index.md` 补齐 frontmatter、能力域导航和 API / XML 阅读入口
|
||||
- 为 `GFramework.Core/README.md`、`GFramework.Core.Abstractions/README.md` 补齐类型族级 XML 覆盖基线入口
|
||||
- 为 `docs/zh-CN/core/index.md`、`docs/zh-CN/abstractions/core-abstractions.md` 增加“类型族 -> XML 覆盖状态 -> 代表类型”的 inventory
|
||||
- 基于顶层目录轻量盘点确认:`Core` / `Core.Abstractions` 当前公开 / 内部类型声明都已带 XML 注释,成员级审计留待后续波次
|
||||
- 重写 `docs/zh-CN/ecs/index.md`,收敛当前 ECS family 的包边界、采用顺序和 XML inventory
|
||||
- 重写 `docs/zh-CN/ecs/arch.md`,明确 `UseArch(...)` 需早于 `Initialize()` 的真实接入时机
|
||||
- 刷新 `GFramework.Ecs.Arch/README.md`,使运行时 README 与源码 / 测试一致
|
||||
- 为 `GFramework.Ecs.Arch.Abstractions/README.md` 与 `docs/zh-CN/abstractions/ecs-arch-abstractions.md` 补齐类型族级 XML inventory
|
||||
- 重写 `docs/zh-CN/core/cqrs.md`,将其收敛为 `Cqrs` family landing,并补齐运行时 / 契约层 / 生成器的 XML inventory
|
||||
- 新建 `docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`,为 `Cqrs.SourceGenerators` 补齐站内专题入口
|
||||
- 更新 `docs/zh-CN/source-generators/index.md`、`docs/zh-CN/api-reference/index.md` 与 VitePress sidebar,使 `Cqrs` family 的 generator 入口可导航
|
||||
- 为 `GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs` 与 `GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs` 中缺失的内部类型补齐 XML 注释,使本轮轻量 inventory 达到声明级闭环
|
||||
- 为 `GFramework.Game/README.md`、`GFramework.Game.Abstractions/README.md`、`GFramework.Game.SourceGenerators/README.md` 补齐 `Game` family 的类型族级 XML inventory
|
||||
- 为 `docs/zh-CN/game/index.md` 补齐 frontmatter,并增加 `Game` / `Game.Abstractions` / `Game.SourceGenerators` 的 XML 覆盖基线入口
|
||||
- 将 `docs/zh-CN/abstractions/game-abstractions.md` 从失真的旧接口摘录页重写为契约边界 / 包关系 / 最小接入路径页面
|
||||
- 基于顶层目录轻量盘点确认:`GFramework.Game` 为 `56/56`、`GFramework.Game.Abstractions` 为 `80/80`、`GFramework.Game.SourceGenerators` 为 `2/2`,当前公开 / 内部类型声明都已带 XML 注释
|
||||
- 更新 `AGENTS.md` 的 WSL Git 策略,将显式 `--git-dir` / `--work-tree` 绑定提升为高于 `git.exe` 的默认优先级
|
||||
- 记录当前环境偏差:本会话 `git.exe` 可解析但执行会触发 `Exec format error`,而 plain Linux `git` 会命中 worktree 路径翻译错误,需要显式仓库绑定
|
||||
- 完成 `Game` family 巡检,确认 `docs/zh-CN/game/config-system.md`、`scene.md`、`ui.md` 与 `docs/zh-CN/source-generators/index.md` 的核心采用说明、包关系与交叉引用仍与当前源码 / README 一致,没有发现需要立刻修正的回漂
|
||||
|
||||
## Inventory(第一版)
|
||||
|
||||
| 模块族 | 当前状态 | 当前证据 | 下一动作 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Core` / `Core.Abstractions` | `README / landing / 类型族级 XML inventory 已收口,成员级审计待补齐` | 根 README、模块 README、`docs/zh-CN/core/**`、`docs/zh-CN/abstractions/core-abstractions.md` 已对齐当前目录与类型族基线 | 进入巡检;如有新 API 变更,再追加成员级 XML 审计 |
|
||||
| `Cqrs` / `Cqrs.Abstractions` / `Cqrs.SourceGenerators` | `README / landing / generator topic / 类型族级 XML inventory 已收口,成员级审计待补齐` | `GFramework.Cqrs/README.md`、`GFramework.Cqrs.Abstractions/README.md`、`GFramework.Cqrs.SourceGenerators/README.md`、`docs/zh-CN/core/cqrs.md`、`docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`、`docs/zh-CN/api-reference/index.md` 已对齐当前源码与测试 | 转入巡检;下一波切到 `Game` family 的 XML / 教程链路审计 |
|
||||
| `Game` / `Game.Abstractions` / `Game.SourceGenerators` | `README / landing / abstractions / 类型族级 XML inventory 已收口,成员级审计待补齐` | `GFramework.Game/README.md`、`GFramework.Game.Abstractions/README.md`、`GFramework.Game.SourceGenerators/README.md`、`docs/zh-CN/game/index.md`、`docs/zh-CN/abstractions/game-abstractions.md` 已对齐当前源码与目录基线 | 转入巡检;优先抽查 `config-system`、`scene`、`ui` 与 `source-generators` 交叉链路是否回漂 |
|
||||
| `Godot` / `Godot.SourceGenerators` | `已验证` | 上一轮归档 topic 已完成核心 landing / topic / tutorial 校验 | 进入巡检周期,重点看回漂 |
|
||||
| `Ecs.Arch` / `Ecs.Arch.Abstractions` | `README / landing / abstractions / 类型族级 XML inventory 已收口,成员级审计待补齐` | `GFramework.Ecs.Arch/README.md`、`GFramework.Ecs.Arch.Abstractions/README.md`、`docs/zh-CN/ecs/**`、`docs/zh-CN/abstractions/ecs-arch-abstractions.md` 已对齐当前源码与测试 | 转入巡检;后续仅在运行时公共 API 变动时补成员级 XML 细审 |
|
||||
| `SourceGenerators.Common` 与 `*.SourceGenerators.Abstractions` | `已判定为内部支撑` | `*.csproj` 明确 `IsPackable=false` | 由所属模块 README 与生成器栏目说明 owner,不建独立采用页 |
|
||||
|
||||
## 缺口分级
|
||||
|
||||
- `P0`
|
||||
- 错误采用路径、错误包关系、错误 API / 生命周期语义
|
||||
- 站点导航死链、空 landing page、明显错误的模块 owner
|
||||
- `P1`
|
||||
- 直接消费模块缺 README 或缺对应 docs 入口
|
||||
- README / docs 示例与源码实现不一致
|
||||
- 教程仍引用已经过时的默认接线方式
|
||||
- `P2`
|
||||
- 结构重复、交叉链接不足、API 参考链路过薄
|
||||
- 站内页面存在事实正确但组织方式不利于定位的内容
|
||||
|
||||
## 当前风险
|
||||
|
||||
- 当前 `Core` / `Core.Abstractions` 只完成了类型族级 XML 基线,不等于成员级契约全审计
|
||||
- 缓解措施:后续只在共享抽象或高风险生命周期接口发生改动时补成员级细审,不在本轮扩张范围
|
||||
- `Godot` family 的治理结论主要留在已归档 topic 中,active topic 当前只保留摘要
|
||||
- 缓解措施:下一恢复点优先判断是否要把关键 XML inventory 摘要迁回 active topic,避免后续 boot 仍过度依赖 archive
|
||||
- 新功能分支若修改 README / docs / 公共 API 却不挂文档 topic,仍可能回漂
|
||||
- 缓解措施:将本 topic 作为长期 active topic 保留,并在后续巡检中记录回漂来源
|
||||
- VitePress 页面不能直接链接到 `docs/` 目录之外的模块 `README.md`
|
||||
- 缓解措施:站内页面用模块路径文本或站内 API 入口表达,仓库级 README 仍保留仓库文件链接
|
||||
- `GFramework.Cqrs` 在当前 WSL / dotnet 环境下,本地 build 仍会读取失效的 fallback package folder 配置,导致无法完成该项目的标准编译验证
|
||||
- 缓解措施:本轮先以 `GFramework.Cqrs.SourceGenerators` 编译通过和 docs site build 通过作为有效验证,并在后续环境治理或构建脚本清理时单独处理 `RestoreFallbackFolders` / 资产文件问题
|
||||
- 当前 WSL 会话中 `git.exe` 虽然可解析,但不能执行
|
||||
- 缓解措施:把显式 `--git-dir` / `--work-tree` 绑定上升为仓库默认回退策略,并仅把 `git.exe` 保留为可执行时的次级 fallback
|
||||
|
||||
## 验证说明
|
||||
|
||||
- 详细验证历史已归档到 `ai-plan/public/documentation-full-coverage-governance/archive/todos/documentation-full-coverage-governance-validation-history-through-rp-007.md`
|
||||
- `2026-04-23` `python3 -B -c "from pathlib import Path; compile(Path('.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py').read_text(encoding='utf-8'), '.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py', 'exec')"`
|
||||
- 结果:通过
|
||||
- `2026-04-23` `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --json-output /tmp/gframework-current-pr-review.json`
|
||||
- 结果:通过;成功抓取 PR `#271`,并确认当前 latest-head review threads 为 `4` 条 open
|
||||
- `2026-04-23` `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`
|
||||
- 结果:通过
|
||||
- `2026-04-23` `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/ecs/index.md`
|
||||
- 结果:通过
|
||||
- `2026-04-23` `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/abstractions/ecs-arch-abstractions.md`
|
||||
- 结果:通过
|
||||
- `2026-04-23` `cd docs && bun run build`
|
||||
- 结果:通过;仅保留既有 VitePress 大 chunk warning,无构建失败
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 完成本轮 PR #271 follow-up 的针对性验证与 docs build,确认 open threads 是否都已被本地收敛
|
||||
2. 推送当前分支后重新执行 `$gframework-pr-review`,确认 PR #271 的 latest-head open threads 是否按预期收敛
|
||||
3. 评估是否需要把 `Godot` family 的关键 XML inventory 摘要迁回 active topic,避免长期治理只依赖 archive 恢复
|
||||
@ -0,0 +1,275 @@
|
||||
# Documentation Full Coverage Governance Trace
|
||||
|
||||
## 2026-04-22
|
||||
|
||||
### 当前恢复点:RP-001
|
||||
|
||||
- 按长期治理计划新建 active topic `documentation-full-coverage-governance`
|
||||
- 在 `ai-plan/public/README.md` 中将当前分支 `docs/sdk-update-documentation` 映射到该 topic
|
||||
- 复核已知缺口模块的 `*.csproj` 后确认:
|
||||
- `GFramework.Ecs.Arch.Abstractions` 是可打包消费模块,需要独立 README
|
||||
- `GFramework.Core.SourceGenerators.Abstractions`、`GFramework.Godot.SourceGenerators.Abstractions`、
|
||||
`GFramework.SourceGenerators.Common` 都是 `IsPackable=false` 的内部支撑模块
|
||||
- 基于该结论,本轮没有为内部支撑模块新增独立 README,而是在根 README 与 abstractions / API 入口中明确其 owner
|
||||
|
||||
### 当前决策
|
||||
|
||||
- 新主题的完成条件采用长期治理口径:`P0` 清零、无 README 缺失、无导航死链,并完成连续两轮稳定巡检
|
||||
- 本轮先做治理基础设施与 inventory,不把整个长期计划伪装成单轮完成
|
||||
- `api-reference` 页面改为“模块 -> README / docs / XML / tutorial”的阅读链路入口,避免继续维护失真的伪签名列表
|
||||
- `Ecs.Arch` family 被列为高优先 backlog:抽象层入口已补齐,但 runtime docs 仍需按源码重写
|
||||
- `Core` / `Core.Abstractions` 波次先收口 README、landing page 和 abstractions 页的目录映射,再补显式 XML 覆盖 inventory
|
||||
- VitePress 站内页面不直接链接仓库根模块 `README.md`;站内仅保留可构建的 docs 链接,模块 README 以文本路径或仓库 README 承接
|
||||
|
||||
### 当前恢复点:RP-002
|
||||
|
||||
- 完成 `Core` / `Core.Abstractions` 的类型族级 XML inventory:
|
||||
- `GFramework.Core/README.md`
|
||||
- `GFramework.Core.Abstractions/README.md`
|
||||
- `docs/zh-CN/core/index.md`
|
||||
- `docs/zh-CN/abstractions/core-abstractions.md`
|
||||
- 通过顶层目录轻量盘点确认:
|
||||
- `GFramework.Core` 当前各目录族的公开 / 内部类型声明都已带 XML 注释
|
||||
- `GFramework.Core.Abstractions` 当前各契约目录族的公开 / 内部类型声明都已带 XML 注释
|
||||
- 这轮 inventory 明确限定为“类型声明级基线”,不把结果表述成成员级 XML 合规审计
|
||||
|
||||
### 当前决策(RP-002)
|
||||
|
||||
- XML inventory 同时落在模块 README 和站内 landing page:
|
||||
- README 提供仓库侧入口,方便从包目录直接恢复上下文
|
||||
- docs landing 提供更细的类型族 / 代表类型 / 阅读重点表格,方便站内导航
|
||||
- `Core` 波次在补齐基线后转入巡检,不继续在本轮展开成员级 ``<param>`` / ``<returns>`` 审计
|
||||
- 下一恢复点切换到 `Ecs` 波次,优先处理仍明显失真的 runtime docs
|
||||
|
||||
### 当前验证
|
||||
|
||||
- 文档校验:
|
||||
- `validate-all.sh docs/zh-CN/abstractions/index.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/abstractions/ecs-arch-abstractions.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/api-reference/index.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/core/index.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/abstractions/core-abstractions.md`:通过
|
||||
- 构建校验:
|
||||
- `cd docs && bun run build`:通过
|
||||
- `DOTNET_CLI_HOME=/tmp/dotnet-home dotnet build GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj -c Release -p:RestoreFallbackFolders=`:通过,`0 Warning(s) / 0 Error(s)`
|
||||
- `dotnet build GFramework.Ecs.Arch.Abstractions/GFramework.Ecs.Arch.Abstractions.csproj -c Release -p:RestoreFallbackFolders=`:通过,`0 Warning(s) / 0 Error(s)`
|
||||
|
||||
### 当前验证(RP-002)
|
||||
|
||||
- 文档校验:
|
||||
- `validate-all.sh docs/zh-CN/core/index.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/abstractions/core-abstractions.md`:通过
|
||||
- 构建校验:
|
||||
- `cd docs && bun run build`:通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
|
||||
### 当前恢复点:RP-003
|
||||
|
||||
- 完成 `Ecs.Arch` 波次的运行时文档刷新:
|
||||
- `docs/zh-CN/ecs/index.md`
|
||||
- `docs/zh-CN/ecs/arch.md`
|
||||
- `GFramework.Ecs.Arch/README.md`
|
||||
- 为 `Ecs.Arch.Abstractions` 补齐与运行时页同粒度的 XML inventory:
|
||||
- `GFramework.Ecs.Arch.Abstractions/README.md`
|
||||
- `docs/zh-CN/abstractions/ecs-arch-abstractions.md`
|
||||
- 明确记录一个关键采用事实:
|
||||
- `UseArch(...)` 必须早于 `Initialize()` 调用
|
||||
- 该结论以 `ArchExtensions` 的模块注册方式和 `ExplicitRegistrationTests` 为证据
|
||||
- 将 `Ecs.Arch` family 从“入口存在但失真”推进到“README / landing / abstractions / XML inventory 已对齐源码与测试”
|
||||
|
||||
### 当前决策(RP-003)
|
||||
|
||||
- `Ecs` 波次继续采用与 `Core` 相同的治理粒度:
|
||||
- 模块 README 承担仓库入口
|
||||
- `docs/zh-CN/ecs/index.md` 承担模块族 landing
|
||||
- `docs/zh-CN/ecs/arch.md` 承担运行时默认实现专题页
|
||||
- `docs/zh-CN/abstractions/ecs-arch-abstractions.md` 承担契约边界专题页
|
||||
- `EnableStatistics` 当前仅保留在公开配置面上;文档不再把它写成已验证的运行时行为
|
||||
- 下一恢复点切换到 `Cqrs` 波次,优先解决入口分散和 API / XML 阅读链路不统一的问题
|
||||
|
||||
### 当前验证(RP-003)
|
||||
|
||||
- 文档校验:
|
||||
- `validate-all.sh docs/zh-CN/ecs/index.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/ecs/arch.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/abstractions/ecs-arch-abstractions.md`:通过
|
||||
- 构建校验:
|
||||
- `cd docs && bun run build`:通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
|
||||
### 下一步
|
||||
|
||||
1. 在 `Cqrs` 波次核对模块 README、`docs/zh-CN/core/cqrs.md` 与 `docs/zh-CN/source-generators/**` 的真实 owner
|
||||
2. 决定 `Cqrs` family 是补 dedicated landing 还是拆分现有入口页
|
||||
|
||||
### 当前恢复点:RP-004
|
||||
|
||||
- 完成 `Cqrs` 波次的模块族入口刷新:
|
||||
- 重写 `docs/zh-CN/core/cqrs.md`
|
||||
- 新建 `docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`
|
||||
- 更新 `docs/zh-CN/source-generators/index.md`
|
||||
- 更新 `docs/zh-CN/api-reference/index.md`
|
||||
- 更新 `docs/.vitepress/config.mts`
|
||||
- 将 `Cqrs` family 从“README 已存在但 generator 入口分散”推进到“runtime / abstractions / source generator 都有明确站内入口”
|
||||
- 为 `GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs` 与
|
||||
`GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs` 中缺失的内部类型补齐 XML 注释
|
||||
- 基于轻量扫描确认:
|
||||
- `GFramework.Cqrs.Abstractions/Cqrs/` 当前类型声明级 XML 覆盖为 `20/20`
|
||||
- `GFramework.Cqrs` 根入口与 `Internal/` 已补到 `19/19`
|
||||
- `GFramework.Cqrs.SourceGenerators/Cqrs/` 当前类型声明级 XML 覆盖为 `3/3`
|
||||
|
||||
### 当前决策(RP-004)
|
||||
|
||||
- `docs/zh-CN/core/cqrs.md` 继续保留在 `Core` 栏目,但其角色调整为 `Cqrs` family landing,而不再只是 runtime 简介页
|
||||
- `Cqrs.SourceGenerators` 不单独新建一级导航栏目,而是在 `source-generators` 栏目内补一个专用专题页,保持站点 taxonomy 稳定
|
||||
- generator 入口以“专题页 + API reference 链接 + sidebar”三点联动,而不是只在 `source-generators/index.md` 留一个段落链接
|
||||
- XML inventory 仍维持“类型声明级基线”口径,不在本轮扩展成成员级 `param/returns/exception` 细审
|
||||
|
||||
### 当前验证(RP-004)
|
||||
|
||||
- 文档校验:
|
||||
- `validate-all.sh docs/zh-CN/core/cqrs.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`:通过
|
||||
- 轻量 XML inventory:
|
||||
- `GFramework.Cqrs/Internal/`:`14/14`
|
||||
- `GFramework.Cqrs.Abstractions/Cqrs/`:`20/20`
|
||||
- `GFramework.Cqrs.SourceGenerators/Cqrs/`:`3/3`
|
||||
- 构建校验:
|
||||
- `dotnet build GFramework.Cqrs.SourceGenerators/GFramework.Cqrs.SourceGenerators.csproj -c Release -p:RestoreFallbackFolders=`:通过
|
||||
- `cd docs && bun run build`:通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
- `dotnet build GFramework.Cqrs/GFramework.Cqrs.csproj -c Release`:失败;当前 WSL / dotnet 环境仍引用失效的 Windows fallback package folder,并在多目标 inner build 阶段触发 `MSB4276` / `MSB4018`
|
||||
|
||||
### 下一步
|
||||
|
||||
1. 切换到 `Game` family 波次,按 `Core` / `Ecs` / `Cqrs` 已验证模板继续补 XML inventory 与教程链路
|
||||
2. 把 `GFramework.Cqrs` 的本地构建阻塞留给后续环境治理或构建脚本清理,不在本 topic 内扩张为环境修复任务
|
||||
|
||||
### 当前恢复点:RP-005
|
||||
|
||||
- 完成 `Game` 波次的模块族入口刷新:
|
||||
- 更新 `GFramework.Game/README.md`
|
||||
- 更新 `GFramework.Game.Abstractions/README.md`
|
||||
- 更新 `GFramework.Game.SourceGenerators/README.md`
|
||||
- 更新 `docs/zh-CN/game/index.md`
|
||||
- 重写 `docs/zh-CN/abstractions/game-abstractions.md`
|
||||
- 将 `Game` family 从“README / 页面存在但缺少可审计 XML 入口,且 abstractions 页失真”推进到“runtime / abstractions / source generator 都有声明级 XML inventory 与真实采用边界”
|
||||
- 基于轻量扫描确认:
|
||||
- `GFramework.Game` 当前类型声明级 XML 覆盖为 `56/56`
|
||||
- `GFramework.Game.Abstractions` 当前类型声明级 XML 覆盖为 `80/80`
|
||||
- `GFramework.Game.SourceGenerators` 当前类型声明级 XML 覆盖为 `2/2`
|
||||
|
||||
### 当前决策(RP-005)
|
||||
|
||||
- `docs/zh-CN/abstractions/game-abstractions.md` 不再维护虚构接口摘录,而是与源码中的 `Config` / `Data` / `Setting` / `Scene` / `UI` / `Routing` 契约分组保持一致
|
||||
- `Game.SourceGenerators` 继续以 `README + docs/zh-CN/game/config-system.md + docs/zh-CN/source-generators/index.md` 组成入口,不额外新增只为凑数量的专题页
|
||||
- `docs/zh-CN/game/index.md` 补 frontmatter,并承担 `Game` family 的 XML 基线入口;更细的类型族说明继续留在模块 README 与 abstractions 页
|
||||
|
||||
### 当前验证(RP-005)
|
||||
|
||||
- 文档校验:
|
||||
- `validate-all.sh docs/zh-CN/abstractions/game-abstractions.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/game/index.md`:通过
|
||||
- 轻量 XML inventory:
|
||||
- `GFramework.Game`:`56/56`
|
||||
- `GFramework.Game.Abstractions`:`80/80`
|
||||
- `GFramework.Game.SourceGenerators`:`2/2`
|
||||
- 构建校验:
|
||||
- `cd docs && bun run build`:通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
|
||||
### 下一步
|
||||
|
||||
1. 进入 `Game` family 巡检,优先检查 `config-system.md`、`scene.md`、`ui.md` 与 `source-generators/index.md` 的交叉引用是否回漂
|
||||
2. 评估是否需要把 `Godot` family 的关键 XML inventory 摘要迁回 active topic,减少对 archive 的依赖
|
||||
|
||||
### 当前恢复点:RP-006
|
||||
|
||||
- 更新 `AGENTS.md` 的 WSL Git 规则:
|
||||
- 将显式 `git --git-dir=<...> --work-tree=<...>` 绑定提升为高于 `git.exe` 的默认优先级
|
||||
- 明确 plain Linux `git` 命中 worktree 路径翻译错误时,应先切到显式绑定而不是直接改用 `git.exe`
|
||||
- 明确 `git.exe` 只有在当前会话可执行时才作为次级 fallback
|
||||
- 记录本次恢复任务的环境偏差:
|
||||
- `git.exe` 在当前 WSL 会话中可解析,但执行会触发 `Exec format error`
|
||||
- plain `git` 会把 worktree 元数据路径翻译错并报“not a git repository”
|
||||
- 显式 `--git-dir` / `--work-tree` 绑定是本次已验证可用的 Git 操作方式
|
||||
|
||||
### 当前决策(RP-006)
|
||||
|
||||
- 把 Git 回退顺序写进 `AGENTS.md`,而不是只留在一次性的聊天上下文里
|
||||
- 不额外扩张 `gframework-boot` skill,因为它本身不内嵌 Git 选择逻辑,继续由 `AGENTS.md` 作为唯一准则
|
||||
- 继续把 `git.exe` 保留为 fallback,而不是完全删除,避免在可执行的 WSL 会话里丢掉可用路径
|
||||
|
||||
### 当前验证(RP-006)
|
||||
|
||||
- 构建校验:
|
||||
- `cd docs && bun run build`:通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
|
||||
### 下一步
|
||||
|
||||
1. 继续 `Game` family 巡检,优先检查 `config-system.md`、`scene.md`、`ui.md` 与 `source-generators/index.md` 的交叉引用是否回漂
|
||||
2. 评估是否需要把 `Godot` family 的关键 XML inventory 摘要迁回 active topic,减少对 archive 的依赖
|
||||
|
||||
### 当前恢复点:RP-007
|
||||
|
||||
- 完成 `Game` family 巡检:
|
||||
- 复核 `docs/zh-CN/game/config-system.md`
|
||||
- 复核 `docs/zh-CN/game/scene.md`
|
||||
- 复核 `docs/zh-CN/game/ui.md`
|
||||
- 复核 `docs/zh-CN/source-generators/index.md`
|
||||
- 对照 `GFramework.Game`、`GFramework.Game.Abstractions`、`GFramework.Game.SourceGenerators` README 与相关源码 / 测试后,未发现需要立刻修正的采用语义回漂
|
||||
- 重点确认的真实语义包括:
|
||||
- `GameConfigBootstrap` / `RegisterAllGeneratedConfigTables(...)` / `GFrameworkConfigSchemaDirectory` 的配置入口仍与文档示例一致
|
||||
- `SceneRouterBase` 仍通过 `SemaphoreSlim` 串行化切换,并拒绝重复 `sceneKey` 入栈
|
||||
- `UiRouterBase` 仍将 `Page` 层与 `Overlay` / `Modal` / `Toast` / `Topmost` 分为两套入口,且 `Show(..., UiLayer.Page)` 会直接拒绝
|
||||
|
||||
### 当前决策(RP-007)
|
||||
|
||||
- 本轮不为“巡检通过”硬造文档改动,先把结论写回 active topic,保持恢复点准确
|
||||
- `Game` family 暂时转入稳定巡检,不在没有源码变化的情况下重复改写 landing page
|
||||
- 默认下一步切到 `Godot` family 摘要是否回迁,减少长期治理对 archive topic 的依赖
|
||||
|
||||
### 当前验证(RP-007)
|
||||
|
||||
- 构建校验:
|
||||
- `cd docs && bun run build`:通过;仅保留 VitePress 大 chunk warning,无构建失败
|
||||
|
||||
### 下一步
|
||||
|
||||
1. 评估是否需要把 `Godot` family 的关键 XML inventory 摘要迁回 active topic
|
||||
2. 若不需要迁回,则继续抽查 README / landing page / API reference 之间的 cross-link 是否出现新的漂移
|
||||
|
||||
### 当前恢复点:RP-008
|
||||
|
||||
- 使用 `$gframework-pr-review` 抓取当前分支 PR `#271` 后,确认 latest head review threads 仍有 `4` 条 open:
|
||||
- `docs/zh-CN/source-generators/cqrs-handler-registry-generator.md` 的 marker 类型约定说明缺口
|
||||
- `docs/zh-CN/ecs/index.md` 的边界说明语序问题
|
||||
- `docs/zh-CN/abstractions/ecs-arch-abstractions.md` 误放的 source-generator 内部模块提醒
|
||||
- `ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md` 的验证历史过长,以及
|
||||
`ai-plan/public/archive/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md` 缺少显式结果态
|
||||
- 在当前 WSL 会话里,`gframework-pr-review` 脚本先命中了 `git.exe` 的 `Exec format error`
|
||||
- 已将 `.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py` 改为优先使用 Linux `git` 的显式
|
||||
`--git-dir` / `--work-tree` 绑定,并仅在无法建立该绑定时回退到旧的可执行解析逻辑
|
||||
- 已同步更新 `.agents/skills/gframework-pr-review/SKILL.md`,使其 Git 策略与命令示例都与当前仓库状态一致
|
||||
- 已把 `DOCUMENTATION-FULL-COVERAGE-GOV-RP-001` 到 `RP-007` 的详细验证历史迁入
|
||||
`ai-plan/public/documentation-full-coverage-governance/archive/todos/documentation-full-coverage-governance-validation-history-through-rp-007.md`
|
||||
|
||||
### 当前决策(RP-008)
|
||||
|
||||
- 继续把 latest-head unresolved threads 作为主信号,只修仍在本地成立的评论,不为已失效的历史 summary 做无意义回写
|
||||
- active tracking 只保留最新验证摘要与恢复点;详细验证历史留在 topic 自己的 archive,而不是继续堆在默认 boot 路径
|
||||
- `gframework-pr-review` 的脚本行为、技能文案与 `AGENTS.md` 必须保持同一套 WSL Git 策略,避免再次出现“文档说法正确但工具实现仍跑偏”的情况
|
||||
|
||||
### 当前验证(RP-008)
|
||||
|
||||
- PR review 抓取:
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --json-output /tmp/gframework-current-pr-review.json`:通过
|
||||
- 脚本语法校验:
|
||||
- `python3 -B -c "from pathlib import Path; compile(Path('.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py').read_text(encoding='utf-8'), '.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py', 'exec')"`:通过
|
||||
- 文档校验:
|
||||
- `validate-all.sh docs/zh-CN/source-generators/cqrs-handler-registry-generator.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/ecs/index.md`:通过
|
||||
- `validate-all.sh docs/zh-CN/abstractions/ecs-arch-abstractions.md`:通过
|
||||
- 构建校验:
|
||||
- `cd docs && bun run build`:通过;仅保留既有 VitePress 大 chunk warning,无构建失败
|
||||
|
||||
### 下一步
|
||||
|
||||
1. 提交本轮 PR review follow-up
|
||||
2. 推送当前分支后重新执行 `$gframework-pr-review`,观察 PR #271 的 open threads 是否收敛
|
||||
@ -252,6 +252,7 @@ export default defineConfig({
|
||||
{ text: 'ContextAware 生成器', link: '/zh-CN/source-generators/context-aware-generator' },
|
||||
{ text: 'Priority 生成器', link: '/zh-CN/source-generators/priority-generator' },
|
||||
{ text: 'Context Get 注入', link: '/zh-CN/source-generators/context-get-generator' },
|
||||
{ text: 'CQRS Handler Registry', link: '/zh-CN/source-generators/cqrs-handler-registry-generator' },
|
||||
{ text: 'Godot 项目元数据', link: '/zh-CN/source-generators/godot-project-generator' },
|
||||
{ text: 'GetNode 生成器 (Godot)', link: '/zh-CN/source-generators/get-node-generator' },
|
||||
{ text: 'BindNodeSignal 生成器 (Godot)', link: '/zh-CN/source-generators/bind-node-signal-generator' }
|
||||
@ -264,7 +265,8 @@ export default defineConfig({
|
||||
text: '抽象接口',
|
||||
items: [
|
||||
{ text: 'Core Abstractions', link: '/zh-CN/abstractions/core-abstractions' },
|
||||
{ text: 'Game Abstractions', link: '/zh-CN/abstractions/game-abstractions' }
|
||||
{ text: 'Game Abstractions', link: '/zh-CN/abstractions/game-abstractions' },
|
||||
{ text: 'Ecs.Arch Abstractions', link: '/zh-CN/abstractions/ecs-arch-abstractions' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@ -1,192 +1,104 @@
|
||||
---
|
||||
title: Core Abstractions
|
||||
description: GFramework.Core.Abstractions 的契约边界、包关系与 XML 阅读重点。
|
||||
---
|
||||
|
||||
# Core Abstractions
|
||||
|
||||
> GFramework.Core.Abstractions 核心抽象接口定义
|
||||
`GFramework.Core.Abstractions` 是 `Core` 运行时的契约包。
|
||||
|
||||
## 概述
|
||||
它负责定义架构、生命周期、事件、状态、资源、日志、配置、并发和持久化相关的接口、枚举和值对象,用来建立跨模块协作边界;
|
||||
默认实现、基类、容器适配和运行时装配则在 `GFramework.Core` 中。
|
||||
|
||||
GFramework.Core.Abstractions 包含了框架的所有核心接口定义,这些接口定义了组件之间的契约,实现了依赖倒置和面向接口编程。
|
||||
如果你要开箱即用地使用框架能力,应依赖 `GFramework.Core`;如果你在做扩展包、测试替身、工具层或多模块拆分,才单独消费本包。
|
||||
|
||||
## 核心接口
|
||||
## 什么时候单独依赖它
|
||||
|
||||
### IArchitecture
|
||||
- 你在写插件、模块扩展或测试替身,只想依赖接口而不拉入默认运行时
|
||||
- 你需要让多个程序集共享架构、状态、资源或日志契约
|
||||
- 你希望把公共边界放进 `*.Abstractions`,而把具体实现留在应用层或宿主层
|
||||
|
||||
应用程序架构接口:
|
||||
## 包关系
|
||||
|
||||
- 契约层:`GFramework.Core.Abstractions`
|
||||
- 运行时实现:`GFramework.Core`
|
||||
- 常见相邻契约:`GFramework.Cqrs.Abstractions`、`GFramework.Game.Abstractions`
|
||||
|
||||
## 契约地图
|
||||
|
||||
| 契约族 | 作用 |
|
||||
| --- | --- |
|
||||
| `Architectures/` `Lifecycle/` `Registries/` | `IArchitecture`、上下文、模块、服务模块、阶段监听、注册表与初始化 / 销毁生命周期契约 |
|
||||
| `Bases/` `Controller/` `Model/` `Systems/` `Utility/` `Rule/` | 组件角色接口、优先级 / key 值对象、上下文感知边界 |
|
||||
| `Command/` `Query/` `Cqrs/` | 旧版命令 / 查询执行器接口,以及与新版请求模型衔接的运行时契约 |
|
||||
| `Events/` `Property/` `State/` `StateManagement/` | 事件总线、解绑对象、可绑定属性、状态机、Store / reducer / middleware 契约 |
|
||||
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | 协程状态、时间源、暂停栈、键控异步锁与统计对象 |
|
||||
| `Resource/` `Pool/` `Logging/` `Localization/` | 资源句柄、对象池、日志、logger factory、本地化表与格式化契约 |
|
||||
| `Configuration/` `Environment/` | 配置管理器、环境对象与运行时环境访问契约 |
|
||||
| `Data/` `Serializer/` `Storage/` `Versioning/` | 数据装载、序列化、存储与版本化契约 |
|
||||
| `Enums/` `Properties/` | 架构阶段枚举,以及架构 / logger 相关属性键 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
### 1. 只面向契约编程
|
||||
|
||||
```csharp
|
||||
public interface IArchitecture
|
||||
{
|
||||
void Initialize();
|
||||
void Destroy();
|
||||
|
||||
T GetModel<T>() where T : IModel;
|
||||
T GetSystem<T>() where T : ISystem;
|
||||
T GetUtility<T>() where T : IUtility;
|
||||
|
||||
void RegisterModel(IModel model);
|
||||
void RegisterSystem(ISystem system);
|
||||
void RegisterUtility(IUtility utility);
|
||||
}
|
||||
```
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Logging;
|
||||
|
||||
### IModel
|
||||
|
||||
数据模型接口:
|
||||
|
||||
```csharp
|
||||
public interface IModel
|
||||
{
|
||||
void Init();
|
||||
void Dispose();
|
||||
|
||||
IArchitecture Architecture { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### ISystem
|
||||
|
||||
业务逻辑系统接口:
|
||||
|
||||
```csharp
|
||||
public interface ISystem
|
||||
{
|
||||
void Init();
|
||||
void Dispose();
|
||||
|
||||
IArchitecture Architecture { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### IController
|
||||
|
||||
控制器接口:
|
||||
|
||||
```csharp
|
||||
public interface IController : IBelongToArchitecture
|
||||
{
|
||||
void Init();
|
||||
void Dispose();
|
||||
}
|
||||
```
|
||||
|
||||
### IUtility
|
||||
|
||||
工具类接口:
|
||||
|
||||
```csharp
|
||||
public interface IUtility
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
## 事件接口
|
||||
|
||||
### IEvent
|
||||
|
||||
事件基接口:
|
||||
|
||||
```csharp
|
||||
public interface IEvent
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
### IEventHandler
|
||||
|
||||
事件处理器接口:
|
||||
|
||||
```csharp
|
||||
public interface IEventHandler<TEvent> where TEvent : IEvent
|
||||
{
|
||||
void Handle(TEvent @event);
|
||||
}
|
||||
```
|
||||
|
||||
## 命令查询接口
|
||||
|
||||
### ICommand
|
||||
|
||||
命令接口:
|
||||
|
||||
```csharp
|
||||
public interface ICommand
|
||||
{
|
||||
void Execute();
|
||||
}
|
||||
```
|
||||
|
||||
### IQuery
|
||||
|
||||
查询接口:
|
||||
|
||||
```csharp
|
||||
public interface IQuery<TResult>
|
||||
{
|
||||
TResult Execute();
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖注入接口
|
||||
|
||||
### IIocContainer
|
||||
|
||||
IoC 容器接口:
|
||||
|
||||
```csharp
|
||||
public interface IIocContainer
|
||||
{
|
||||
void Register<TInterface, TImplementation>() where TImplementation : TInterface;
|
||||
void Register<TInterface>(TInterface instance);
|
||||
TInterface Resolve<TInterface>();
|
||||
bool IsRegistered<TInterface>();
|
||||
}
|
||||
```
|
||||
|
||||
## 生命周期接口
|
||||
|
||||
### ILifecycle
|
||||
|
||||
组件生命周期接口:
|
||||
|
||||
```csharp
|
||||
public interface ILifecycle
|
||||
{
|
||||
void OnInit();
|
||||
void OnDestroy();
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 通过接口实现依赖注入
|
||||
|
||||
```csharp
|
||||
public class MyService : IMyService
|
||||
public sealed class DiagnosticsFeature
|
||||
{
|
||||
private readonly IArchitecture _architecture;
|
||||
|
||||
public MyService(IArchitecture architecture)
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public DiagnosticsFeature(IArchitecture architecture, ILogger logger)
|
||||
{
|
||||
_architecture = architecture;
|
||||
_logger = logger;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 自定义事件
|
||||
### 2. 什么时候切到运行时包
|
||||
|
||||
```csharp
|
||||
public class PlayerDiedEvent : IEvent
|
||||
{
|
||||
public int PlayerId { get; set; }
|
||||
public Vector2 Position { get; set; }
|
||||
}
|
||||
```
|
||||
下面这些需求都属于 `GFramework.Core` 的职责,而不是本包:
|
||||
|
||||
---
|
||||
- 继承 `Architecture` 并完成默认初始化流程
|
||||
- 使用 `ContextAwareBase`、`AbstractModel`、`AbstractSystem` 等默认基类
|
||||
- 使用默认的 `CommandExecutor`、`QueryExecutor`、`BindableProperty<T>`、`StateMachine`
|
||||
- 直接启用默认的 `Microsoft.Extensions.DependencyInjection` 容器适配或资源 / 协程 / 日志实现
|
||||
|
||||
**相关文档**:
|
||||
## XML 阅读重点
|
||||
|
||||
- [Core 概述](../core/index.md)
|
||||
- [Architecture](../core/architecture)
|
||||
- [Events](../core/events)
|
||||
- [Command](../core/command)
|
||||
- [Query](../core/query)
|
||||
如果你在做契约审计、采用设计或扩展适配,优先核对这些类型族的 XML 文档:
|
||||
|
||||
- 架构与模块入口:`IArchitecture`、`IArchitectureContext`、`IServiceModule`
|
||||
- 运行时基础设施:`IIocContainer`、`ILogger`、`IResourceManager`、`IConfigurationManager`
|
||||
- 状态与并发能力:`IStateMachine`、`IStore`、`IAsyncKeyLockManager`、`ITimeProvider`
|
||||
- 迁移与组合边界:`ICommandExecutor`、`IQueryExecutor`、`ICqrsRuntime`
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
下面这份 inventory 记录的是 `2026-04-22` 对 `GFramework.Core.Abstractions` 做的一轮轻量 XML 盘点结果:只统计公开 /
|
||||
内部类型声明是否带 XML 注释,用来建立契约层阅读入口;成员级参数、返回值、异常与生命周期说明仍需要后续波次继续细化。
|
||||
|
||||
| 契约族 | 基线状态 | 代表类型 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Architectures/` | `12/12` 个类型声明已带 XML 注释 | `IArchitecture`、`IArchitectureContext`、`IArchitectureServices`、`IServiceModule` | 看架构上下文、服务访问面与模块安装 / 生命周期约束 |
|
||||
| `Lifecycle/` `Registries/` | `8/8` 个类型声明已带 XML 注释 | `ILifecycle`、`IAsyncInitializable`、`IRegistry<T, TR>`、`KeyValueRegistryBase<TKey, TValue>` | 看初始化 / 销毁阶段和注册表抽象边界 |
|
||||
| `Command/` `Query/` `Cqrs/` | `10/10` 个类型声明已带 XML 注释 | `ICommandExecutor`、`IAsyncCommand<TResult>`、`IQueryExecutor`、`ICqrsRuntime` | 看旧命令 / 查询接口与新请求模型之间的兼容和迁移边界 |
|
||||
| `Events/` `Property/` | `10/10` 个类型声明已带 XML 注释 | `IEventBus`、`IEventFilter<T>`、`IBindableProperty<T>`、`IReadonlyBindableProperty<T>` | 看事件传播、过滤、解绑对象和属性订阅语义 |
|
||||
| `State/` `StateManagement/` | `15/15` 个类型声明已带 XML 注释 | `IStateMachine`、`IAsyncState`、`IStore<TState>`、`IStoreMiddleware<TState>` | 看状态机契约与 Store 的 reducer / middleware / diagnostics 边界 |
|
||||
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | `17/17` 个类型声明已带 XML 注释 | `IYieldInstruction`、`ICoroutineStatistics`、`ITimeProvider`、`IPauseStackManager`、`IAsyncKeyLockManager` | 看调度模型、时间源、暂停栈和异步锁契约 |
|
||||
| `Resource/` `Pool/` `Logging/` `Localization/` | `27/27` 个类型声明已带 XML 注释 | `IResourceManager`、`IObjectPoolSystem`、`ILogger`、`IStructuredLogger`、`ILocalizationManager` | 看资源 / 池化 / 日志 / 本地化这些基础设施的宿主责任 |
|
||||
| `Configuration/` `Environment/` `Data/` `Serializer/` `Storage/` `Versioning/` | `7/7` 个类型声明已带 XML 注释 | `IConfigurationManager`、`IEnvironment`、`ILoadableFrom<T>`、`ISerializer`、`IStorage`、`IVersioned` | 看配置、环境、序列化和持久化边界,以及谁负责具体实现 |
|
||||
| `Bases/` `Controller/` `Model/` `Systems/` `Utility/` `Rule/` `Enums/` `Properties/` | `19/19` 个类型声明已带 XML 注释 | `IPrioritized`、`IController`、`IModel`、`ISystem`、`IContextUtility`、`ArchitecturePhase` | 看基础角色接口、辅助值对象和架构属性键的复用方式 |
|
||||
|
||||
## 阅读顺序
|
||||
|
||||
1. 先读本页,确认你是否真的只需要契约层
|
||||
2. 再看 [`../core/index.md`](../core/index.md) 了解默认运行时怎么组织这些契约
|
||||
3. 回到模块 README:
|
||||
- `GFramework.Core.Abstractions/README.md`
|
||||
- `GFramework.Core/README.md`
|
||||
4. 需要统一导航时,再看 [`../api-reference/index.md`](../api-reference/index.md)
|
||||
|
||||
94
docs/zh-CN/abstractions/ecs-arch-abstractions.md
Normal file
94
docs/zh-CN/abstractions/ecs-arch-abstractions.md
Normal file
@ -0,0 +1,94 @@
|
||||
---
|
||||
title: Ecs.Arch Abstractions
|
||||
description: GFramework.Ecs.Arch.Abstractions 的契约边界、包关系和最小接入路径。
|
||||
---
|
||||
|
||||
# Ecs.Arch Abstractions
|
||||
|
||||
`GFramework.Ecs.Arch.Abstractions` 是 Arch ECS 集成层的契约包。
|
||||
|
||||
它建立在 `GFramework.Core.Abstractions` 之上,只定义 ECS 模块更新、系统适配和配置对象,不负责默认的 Arch
|
||||
`World` 装配、扩展方法或系统基类。
|
||||
|
||||
如果你需要开箱即用的集成实现,请改为依赖 `GFramework.Ecs.Arch`。
|
||||
|
||||
## 什么时候单独依赖它
|
||||
|
||||
- 你在做共享宿主循环、工具层或 feature 包,只需要 `IArchEcsModule`
|
||||
- 你想让不同程序集共享 `ArchOptions` 或系统适配契约,但不直接绑定默认 runtime
|
||||
- 你需要为测试或外部适配层提供替身实现
|
||||
|
||||
## 包关系
|
||||
|
||||
- 契约层:`GFramework.Ecs.Arch.Abstractions`
|
||||
- 运行时实现:`GFramework.Ecs.Arch`
|
||||
- 底层基础契约:`GFramework.Core.Abstractions`
|
||||
|
||||
## 契约地图
|
||||
|
||||
| 类型 | 作用 |
|
||||
| --- | --- |
|
||||
| `IArchEcsModule` | 统一更新 ECS 系统的服务模块契约 |
|
||||
| `IArchSystemAdapter<T>` | 让 ECS 系统适配到 `ISystem` 生命周期 |
|
||||
| `ArchOptions` | 承载 `WorldCapacity`、`EnableStatistics`、`Priority` 等配置 |
|
||||
|
||||
## 类型族级 XML Inventory
|
||||
|
||||
| 类型族 | 代表类型 | XML 状态 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| 模块契约 | `IArchEcsModule` | 已覆盖 | 统一更新入口、宿主循环边界 |
|
||||
| 系统契约 | `IArchSystemAdapter<T>` | 已覆盖 | 只依赖更新接口而不绑定默认 runtime |
|
||||
| 配置对象 | `ArchOptions` | 已覆盖 | 共享配置字段与跨程序集采用边界 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
### 1. 共享模块只依赖更新契约
|
||||
|
||||
```csharp
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
public sealed class GameplayHost
|
||||
{
|
||||
private readonly IArchEcsModule _ecsModule;
|
||||
|
||||
public GameplayHost(IArchEcsModule ecsModule)
|
||||
{
|
||||
_ecsModule = ecsModule;
|
||||
}
|
||||
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
_ecsModule.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 共享配置对象
|
||||
|
||||
```csharp
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
var options = new ArchOptions
|
||||
{
|
||||
WorldCapacity = 2048,
|
||||
EnableStatistics = true,
|
||||
Priority = 40
|
||||
};
|
||||
```
|
||||
|
||||
### 3. 什么时候切到运行时包
|
||||
|
||||
下面这些需求都属于 `GFramework.Ecs.Arch` 的职责,而不是本包:
|
||||
|
||||
- 通过 `UseArch(...)` 把模块挂进架构
|
||||
- 使用默认的 `ArchSystemAdapter<T>` 基类
|
||||
- 访问 Arch `World` 与查询 API
|
||||
- 使用默认的模块装配和生命周期实现
|
||||
|
||||
## 阅读顺序
|
||||
|
||||
1. 先读本页,确认你是否真的只需要契约层
|
||||
2. 如果需要默认实现,再看 [`../ecs/arch.md`](../ecs/arch.md)
|
||||
3. 回到对应模块 README:
|
||||
- `GFramework.Ecs.Arch.Abstractions/README.md`
|
||||
- `GFramework.Ecs.Arch/README.md`
|
||||
@ -1,94 +1,122 @@
|
||||
# Game Abstractions
|
||||
|
||||
> GFramework.Game.Abstractions 游戏模块抽象接口定义
|
||||
|
||||
## 概述
|
||||
|
||||
GFramework.Game.Abstractions 包含了游戏特定功能的抽象接口,这些接口定义了游戏开发中的通用契约。
|
||||
|
||||
## 存档接口
|
||||
|
||||
### ISaveSystem
|
||||
|
||||
存档系统接口:
|
||||
|
||||
```csharp
|
||||
public interface ISaveSystem
|
||||
{
|
||||
void Save(string slotId, SaveData data);
|
||||
SaveData Load(string slotId);
|
||||
bool HasSave(string slotId);
|
||||
void Delete(string slotId);
|
||||
List<SaveSlotInfo> GetAllSaveSlots();
|
||||
}
|
||||
```
|
||||
|
||||
### ISaveData
|
||||
|
||||
存档数据接口:
|
||||
|
||||
```csharp
|
||||
public interface ISaveData
|
||||
{
|
||||
int Version { get; }
|
||||
DateTime Timestamp { get; }
|
||||
void Validate();
|
||||
}
|
||||
```
|
||||
|
||||
## 设置接口
|
||||
|
||||
### IGameSettings
|
||||
|
||||
游戏设置接口:
|
||||
|
||||
```csharp
|
||||
public interface IGameSettings
|
||||
{
|
||||
AudioSettings Audio { get; }
|
||||
GraphicsSettings Graphics { get; }
|
||||
InputSettings Input { get; }
|
||||
|
||||
void Save();
|
||||
void Load();
|
||||
void ResetToDefaults();
|
||||
}
|
||||
```
|
||||
|
||||
## 场景管理接口
|
||||
|
||||
### ISceneManager
|
||||
|
||||
场景管理器接口:
|
||||
|
||||
```csharp
|
||||
public interface ISceneManager
|
||||
{
|
||||
void SwitchScene<TScene>() where TScene : IScene;
|
||||
Task SwitchSceneAsync<TScene>() where TScene : IScene;
|
||||
|
||||
void PushScene<TScene>() where TScene : IScene;
|
||||
void PopScene();
|
||||
|
||||
IScene CurrentScene { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### IScene
|
||||
|
||||
场景接口:
|
||||
|
||||
```csharp
|
||||
public interface IScene
|
||||
{
|
||||
void OnEnter();
|
||||
void OnExit();
|
||||
void OnUpdate(float delta);
|
||||
}
|
||||
```
|
||||
---
|
||||
title: Game Abstractions
|
||||
description: GFramework.Game.Abstractions 的契约边界、包关系与 XML 阅读重点。
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
# Game Abstractions
|
||||
|
||||
- [Game 概述](../game/index.md)
|
||||
- [核心抽象](./core-abstractions.md)
|
||||
`GFramework.Game.Abstractions` 是 `Game` 运行时的契约包。
|
||||
|
||||
它建立在 `GFramework.Core.Abstractions` 之上,负责定义配置、数据、设置、场景、UI、路由、存储和资源注册表相关的接口、
|
||||
枚举与事件契约;默认实现、路由基类、YAML 加载器、文件存储和设置 / 存档仓库则在 `GFramework.Game` 中。
|
||||
|
||||
如果你要开箱即用地接入游戏运行时能力,应依赖 `GFramework.Game`;如果你在做共享业务层、feature 包、测试替身或引擎适配层,
|
||||
才单独消费本包。
|
||||
|
||||
## 什么时候单独依赖它
|
||||
|
||||
- 你希望公共业务层只依赖 `ISceneRouter`、`IUiRouter`、`ISettingsSystem`、`ISaveRepository<TSaveData>` 这类契约
|
||||
- 你要让多个程序集共享 `ISettingsData`、`IData`、`ISceneEnterParam`、`IUiPageEnterParam` 等数据和路由上下文
|
||||
- 你需要自己实现 factory、root、存储或配置加载器,但不想把默认运行时一起带进来
|
||||
|
||||
## 包关系
|
||||
|
||||
- 契约层:`GFramework.Game.Abstractions`
|
||||
- 运行时实现:`GFramework.Game`
|
||||
- 底层基础契约:`GFramework.Core.Abstractions`
|
||||
|
||||
## 契约地图
|
||||
|
||||
| 契约族 | 作用 |
|
||||
| --- | --- |
|
||||
| `Config/` | `IConfigLoader`、`IConfigRegistry`、`IConfigTable<TKey, TValue>` 和配置失败诊断模型 |
|
||||
| `Data/` | `IData`、`IVersionedData`、`IDataRepository`、`ISettingsDataRepository`、`ISaveRepository<TSaveData>` 及数据事件 |
|
||||
| `Setting/` | `ISettingsData`、`ISettingsModel`、`ISettingsSystem`、设置迁移契约与内置设置数据类型 |
|
||||
| `Scene/` | `IScene`、`ISceneRouter`、`ISceneFactory`、`ISceneRoot`、转场处理器与事件 |
|
||||
| `UI/` | `IUiPage`、`IUiRouter`、`IUiFactory`、`IUiRoot`、交互配置与 UI 转场选项 |
|
||||
| `Routing/` | `IRoute`、`IRouteContext`、`IRouteGuard<TRoute>`,作为 Scene / UI 共享的路由基础约定 |
|
||||
| `Storage/` `Asset/` `Enums/` | 文件存储角色、资源注册表,以及转场 / UI 层级 / 输入动作等跨层枚举 |
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
下面这份 inventory 记录的是 `2026-04-23` 对 `GFramework.Game.Abstractions` 做的一轮轻量 XML 盘点结果:只统计公开 /
|
||||
内部类型声明是否带 XML 注释,用来建立契约层阅读入口;成员级参数、返回值、异常和生命周期说明仍需要后续 API 波次继续细化。
|
||||
|
||||
| 契约族 | 基线状态 | 代表类型 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Config/` | `7/7` 个类型声明已带 XML 注释 | `IConfigLoader`、`IConfigRegistry`、`IConfigTable<TKey, TValue>`、`ConfigLoadException` | 看配置表注册、只读访问和失败诊断边界 |
|
||||
| `Data/` | `14/14` 个类型声明已带 XML 注释 | `IDataRepository`、`ISettingsDataRepository`、`ISaveRepository<TSaveData>`、`DataRepositoryOptions` | 看业务数据、统一设置文件、槽位存档与迁移契约 |
|
||||
| `Setting/` | `12/12` 个类型声明已带 XML 注释 | `ISettingsData`、`ISettingsModel`、`ISettingsSystem`、`LocalizationSettings` | 看设置生命周期、应用语义、迁移接口和内置设置对象 |
|
||||
| `Scene/` | `14/14` 个类型声明已带 XML 注释 | `IScene`、`ISceneRouter`、`ISceneFactory`、`SceneTransitionEvent` | 看场景行为、工厂 / root 边界和转场模型 |
|
||||
| `UI/` | `19/19` 个类型声明已带 XML 注释 | `IUiPage`、`IUiRouter`、`IUiFactory`、`UiInteractionProfile`、`UiTransitionHandlerOptions` | 看页面栈、层级 UI、输入动作和 UI 转场契约 |
|
||||
| `Routing/` `Storage/` `Asset/` `Enums/` | `13/13` 个类型声明已带 XML 注释 | `IRoute`、`IRouteContext`、`IFileStorage`、`IAssetRegistry<T>`、`UiLayer`、`SceneTransitionType` | 看公共路由上下文、存储角色、资源注册表与共享枚举 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
### 1. 只在公共业务层声明游戏对象
|
||||
|
||||
```csharp
|
||||
using GFramework.Game.Abstractions.Data;
|
||||
using GFramework.Game.Abstractions.Scene;
|
||||
using GFramework.Game.Abstractions.UI;
|
||||
|
||||
public sealed class GameSaveData : IVersionedData
|
||||
{
|
||||
public int Version { get; set; } = 1;
|
||||
public DateTime LastModified { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class GameplayEnterParam : ISceneEnterParam
|
||||
{
|
||||
public required string Seed { get; init; }
|
||||
}
|
||||
|
||||
public sealed class PauseMenuParam : IUiPageEnterParam
|
||||
{
|
||||
public bool AllowRestart { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 让 feature 包只依赖抽象
|
||||
|
||||
```csharp
|
||||
using GFramework.Game.Abstractions.Data;
|
||||
using GFramework.Game.Abstractions.Scene;
|
||||
|
||||
public sealed class ContinueGameCommandHandler
|
||||
{
|
||||
private readonly ISaveRepository<GameSaveData> _saveRepository;
|
||||
private readonly ISceneRouter _sceneRouter;
|
||||
|
||||
public ContinueGameCommandHandler(
|
||||
ISaveRepository<GameSaveData> saveRepository,
|
||||
ISceneRouter sceneRouter)
|
||||
{
|
||||
_saveRepository = saveRepository;
|
||||
_sceneRouter = sceneRouter;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 什么时候切到运行时包
|
||||
|
||||
下面这些需求都属于 `GFramework.Game` 的职责,而不是本包:
|
||||
|
||||
- 使用默认的 `JsonSerializer`、`FileStorage` 或 `ScopedStorage`
|
||||
- 使用 `SettingsModel<TRepository>`、`SettingsSystem`、`SaveRepository<TSaveData>` 等默认实现
|
||||
- 使用 `YamlConfigLoader`、`GameConfigBootstrap`、`GameConfigModule`
|
||||
- 继承 `SceneRouterBase`、`UiRouterBase` 或默认转场处理器基类
|
||||
|
||||
## 阅读顺序
|
||||
|
||||
1. 先读本页,确认你是否真的只需要契约层
|
||||
2. 再看 [`../game/index.md`](../game/index.md) 了解默认运行时怎么组织这些契约
|
||||
3. 继续读具体专题页:
|
||||
- [`../game/config-system.md`](../game/config-system.md)
|
||||
- [`../game/data.md`](../game/data.md)
|
||||
- [`../game/setting.md`](../game/setting.md)
|
||||
- [`../game/scene.md`](../game/scene.md)
|
||||
- [`../game/ui.md`](../game/ui.md)
|
||||
4. 需要仓库侧入口时,回到:
|
||||
- `GFramework.Game.Abstractions/README.md`
|
||||
- `GFramework.Game/README.md`
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
---
|
||||
title: 抽象接口
|
||||
description: GFramework 各抽象层模块的阅读入口与使用边界。
|
||||
---
|
||||
|
||||
# 抽象接口
|
||||
|
||||
`GFramework.*.Abstractions` 用来承载跨模块协作所需的契约,而不是运行时实现。
|
||||
@ -12,9 +17,19 @@
|
||||
|
||||
- Core 抽象层:[`core-abstractions.md`](./core-abstractions.md)
|
||||
- Game 抽象层:[`game-abstractions.md`](./game-abstractions.md)
|
||||
- Ecs.Arch 抽象层:[`ecs-arch-abstractions.md`](./ecs-arch-abstractions.md)
|
||||
|
||||
## 使用建议
|
||||
|
||||
- 如果你只是想直接使用框架功能,优先从对应运行时模块的 `README.md` 和栏目页开始。
|
||||
- 只有在明确需要“契约层而非实现层”时,才单独依赖 `*.Abstractions` 包。
|
||||
- 抽象层页面会解释接口分组与职责;实际安装与接入路径,仍应以运行时模块 README 与 `getting-started` 为主。
|
||||
- 抽象层页面会解释接口分组与职责;实际安装与接入路径,仍应以运行时模块 README 与 `getting-started` 为主。
|
||||
|
||||
## 当前边界
|
||||
|
||||
- `GFramework.Core.SourceGenerators.Abstractions`
|
||||
- `GFramework.Godot.SourceGenerators.Abstractions`
|
||||
- `GFramework.SourceGenerators.Common`
|
||||
|
||||
这些目录当前不作为独立抽象接口栏目维护,而是作为源码生成器家族的内部支撑模块,分别跟随所属模块 README 和
|
||||
`source-generators` 栏目维护。
|
||||
|
||||
@ -1,571 +1,81 @@
|
||||
# API 参考文档
|
||||
|
||||
本文档提供 GFramework 各模块的完整 API 参考。
|
||||
|
||||
## 核心命名空间
|
||||
|
||||
### GFramework.Core.architecture
|
||||
|
||||
核心架构命名空间,包含所有基础组件。
|
||||
|
||||
#### 主要类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
|--------------------|--------|
|
||||
| `Architecture` | 应用架构基类 |
|
||||
| `AbstractModel` | 数据模型基类 |
|
||||
| `AbstractSystem` | 业务系统基类 |
|
||||
| `AbstractCommand` | 命令基类 |
|
||||
| `AbstractQuery<T>` | 查询基类 |
|
||||
| `IController` | 控制器接口 |
|
||||
| `IUtility` | 工具类接口 |
|
||||
|
||||
### GFramework.Core.events
|
||||
|
||||
事件系统命名空间。
|
||||
|
||||
#### 主要类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
|-------------------|----------|
|
||||
| `IEvent` | 事件接口 |
|
||||
| `IEventSystem` | 事件系统接口 |
|
||||
| `TypeEventSystem` | 类型安全事件系统 |
|
||||
|
||||
### GFramework.Core.property
|
||||
|
||||
属性系统命名空间。
|
||||
|
||||
#### 主要类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
|-----------------------|--------|
|
||||
| `BindableProperty<T>` | 可绑定属性 |
|
||||
| `IUnRegister` | 注销接口 |
|
||||
| `IUnRegisterList` | 注销列表接口 |
|
||||
|
||||
### GFramework.Core.ioc
|
||||
|
||||
IoC 容器命名空间。
|
||||
|
||||
#### 主要类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
|--------------|------|
|
||||
| `IContainer` | 容器接口 |
|
||||
| `Container` | 容器实现 |
|
||||
|
||||
### GFramework.Core.pool
|
||||
|
||||
对象池命名空间。
|
||||
|
||||
#### 主要类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------------------|-------|
|
||||
| `IObjectPool<T>` | 对象池接口 |
|
||||
| `ObjectPool<T>` | 对象池实现 |
|
||||
|
||||
### GFramework.Core.Localization
|
||||
|
||||
本地化系统命名空间。
|
||||
|
||||
#### 主要类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
|--------------------------|----------|
|
||||
| `ILocalizationManager` | 本地化管理器接口 |
|
||||
| `ILocalizationTable` | 本地化表接口 |
|
||||
| `ILocalizationString` | 本地化字符串接口 |
|
||||
| `ILocalizationFormatter` | 格式化器接口 |
|
||||
| `LocalizationConfig` | 本地化配置类 |
|
||||
| `LocalizationManager` | 本地化管理器实现 |
|
||||
| `LocalizationTable` | 本地化表实现 |
|
||||
| `LocalizationString` | 本地化字符串实现 |
|
||||
|
||||
## 常用 API
|
||||
|
||||
### Architecture
|
||||
|
||||
```csharp
|
||||
public abstract class Architecture : IBelongToArchitecture
|
||||
{
|
||||
// 初始化架构
|
||||
public void Initialize();
|
||||
|
||||
// 销毁架构
|
||||
public void Destroy();
|
||||
|
||||
// 注册模型
|
||||
public void RegisterModel<T>(T model) where T : IModel;
|
||||
|
||||
// 获取模型
|
||||
public T GetModel<T>() where T : IModel;
|
||||
|
||||
// 注册系统
|
||||
public void RegisterSystem<T>(T system) where T : ISystem;
|
||||
|
||||
// 获取系统
|
||||
public T GetSystem<T>() where T : ISystem;
|
||||
|
||||
// 注册工具
|
||||
public void RegisterUtility<T>(T utility) where T : IUtility;
|
||||
|
||||
// 获取工具
|
||||
public T GetUt>() where T : IUtility;
|
||||
|
||||
// 发送命令
|
||||
public void SendCommand<T>(T command) where T : ICommand;
|
||||
|
||||
// 发送查询
|
||||
public TResult SendQuery<TQuery, TResult>(TQuery query)
|
||||
where TQuery : IQuery<TResult>;
|
||||
|
||||
// 发送事件
|
||||
public void SendEvent<T>(T e) where T : IEvent;
|
||||
}
|
||||
```
|
||||
|
||||
### AbstractModel
|
||||
|
||||
```csharp
|
||||
public abstract class AbstractModel : IBelongToArchitecture
|
||||
{
|
||||
// 初始化模型
|
||||
protected abstract void OnInit();
|
||||
|
||||
// 销毁模型
|
||||
protected virtual void OnDestroy();
|
||||
|
||||
// 获取架构
|
||||
public IArchitecture GetArchitecture();
|
||||
|
||||
// 发送事件
|
||||
protected void SendEvent<T>(T e) where T : IEvent;
|
||||
|
||||
// 获取模型
|
||||
protected T GetModel<T>() where T : IModel;
|
||||
|
||||
// 获取系统
|
||||
protected T GetSystem<T>() where T : ISystem;
|
||||
|
||||
// 获取工具
|
||||
protected T GetUtility<T>() where T : IUtility;
|
||||
}
|
||||
```
|
||||
|
||||
### AbstractSystem
|
||||
|
||||
```csharp
|
||||
public abstract class AbstractSystem : IBelongToArchitecture
|
||||
{
|
||||
// 初始化系统
|
||||
protected abstract void OnInit();
|
||||
|
||||
// 销毁系统
|
||||
protected virtual void OnDestroy();
|
||||
|
||||
// 获取架构
|
||||
public IArchitecture GetArchitecture();
|
||||
|
||||
// 发送事件
|
||||
protected void SendEvent<T>(T e) where T : IEvent;
|
||||
|
||||
// 注册事件
|
||||
protected IUnRegister RegisterEvent<T>(Action<T> onEvent)
|
||||
where T : IEvent;
|
||||
|
||||
// 获取模型
|
||||
protected T GetModel<T>() where T : IModel;
|
||||
|
||||
// 获取系统
|
||||
protected T GetSystem<T>() where T : ISystem;
|
||||
|
||||
// 获取工具
|
||||
protected T GetUtility<T>() where T : IUtility;
|
||||
}
|
||||
```
|
||||
|
||||
### AbstractCommand
|
||||
|
||||
```csharp
|
||||
public abstract class AbstractCommand : IBelongToArchitecture
|
||||
{
|
||||
// 执行命令
|
||||
public void Execute();
|
||||
|
||||
// 命令实现
|
||||
protected abstract void OnDo();
|
||||
|
||||
// 获取架构
|
||||
public IArchitecture GetArchitecture();
|
||||
|
||||
// 发送事件
|
||||
protected void SendEvent<T>(T e) where T : IEvent;
|
||||
|
||||
// 获取模型
|
||||
protected T GetModel<T>() where T : IModel;
|
||||
|
||||
// 获取系统
|
||||
protected T GetSystem<T>() where T : ISystem;
|
||||
|
||||
// 获取工具
|
||||
protected T GetUtility<T>() where T : IUtility;
|
||||
}
|
||||
```
|
||||
|
||||
### AbstractQuery`<T>`
|
||||
|
||||
```csharp
|
||||
public abstract class AbstractQuery<T> : IBelongToArchitecture
|
||||
{
|
||||
// 执行查询
|
||||
public T Do();
|
||||
|
||||
// 查询实现
|
||||
protected abstract T OnDo();
|
||||
|
||||
// 获取架构
|
||||
public IArchitecture GetArchitecture();
|
||||
|
||||
// 获取模型
|
||||
protected T GetModel<T>() where T : IModel;
|
||||
|
||||
// 获取系统
|
||||
protected T GetSystem<T>() where T : ISystem;
|
||||
|
||||
// 获取工具
|
||||
protected T GetUtility<T>() where T : IUtility;
|
||||
}
|
||||
```
|
||||
|
||||
### BindableProperty`<T>`
|
||||
|
||||
```csharp
|
||||
public class BindableProperty<T>
|
||||
{
|
||||
// 构造函数
|
||||
public BindableProperty(T initialValue = default);
|
||||
|
||||
// 获取或设置值
|
||||
public T Value { get; set; }
|
||||
|
||||
// 注册监听器
|
||||
public IUnRegister Register(Action<T> onValueChanged);
|
||||
|
||||
// 注册监听器(包含初始值)
|
||||
public IUnRegister RegisterWithInitValue(Action<T> onValueChanged);
|
||||
|
||||
// 获取当前值
|
||||
public T GetValue();
|
||||
|
||||
// 设置值
|
||||
public void SetValue(T newValue);
|
||||
}
|
||||
```
|
||||
|
||||
### ILocalizationManager
|
||||
|
||||
```csharp
|
||||
public interface ILocalizationManager : ISystem
|
||||
{
|
||||
// 获取当前语言代码
|
||||
string CurrentLanguage { get; }
|
||||
|
||||
// 获取当前文化信息
|
||||
CultureInfo CurrentCulture { get; }
|
||||
|
||||
// 获取可用语言列表
|
||||
IReadOnlyList<string> AvailableLanguages { get; }
|
||||
|
||||
// 设置当前语言
|
||||
void SetLanguage(string languageCode);
|
||||
|
||||
// 获取本地化表
|
||||
ILocalizationTable GetTable(string tableName);
|
||||
|
||||
// 获取本地化文本
|
||||
string GetText(string table, string key);
|
||||
|
||||
// 获取本地化字符串(支持变量)
|
||||
ILocalizationString GetString(string table, string key);
|
||||
|
||||
// 尝试获取本地化文本
|
||||
bool TryGetText(string table, string key, out string text);
|
||||
|
||||
// 注册格式化器
|
||||
void RegisterFormatter(string name, ILocalizationFormatter formatter);
|
||||
|
||||
// 订阅语言变化事件
|
||||
void SubscribeToLanguageChange(Action<string> callback);
|
||||
|
||||
// 取消订阅语言变化事件
|
||||
void UnsubscribeFromLanguageChange(Action<string> callback);
|
||||
}
|
||||
```
|
||||
|
||||
### ILocalizationString
|
||||
|
||||
```csharp
|
||||
public interface ILocalizationString
|
||||
{
|
||||
// 获取表名
|
||||
string Table { get; }
|
||||
|
||||
// 获取键名
|
||||
string Key { get; }
|
||||
|
||||
// 添加变量
|
||||
ILocalizationString WithVariable(string name, object value);
|
||||
|
||||
// 批量添加变量
|
||||
ILocalizationString WithVariables(params (string name, object value)[] variables);
|
||||
|
||||
// 格式化并返回文本
|
||||
string Format();
|
||||
|
||||
// 获取原始文本
|
||||
string GetRaw();
|
||||
|
||||
// 检查键是否存在
|
||||
bool Exists();
|
||||
}
|
||||
```
|
||||
|
||||
### LocalizationConfig
|
||||
|
||||
```csharp
|
||||
public class LocalizationConfig
|
||||
{
|
||||
// 默认语言代码
|
||||
public string DefaultLanguage { get; set; } = "eng";
|
||||
|
||||
// 回退语言代码
|
||||
public string FallbackLanguage { get; set; } = "eng";
|
||||
|
||||
// 本地化文件路径
|
||||
public string LocalizationPath { get; set; } = "res://localization";
|
||||
|
||||
// 用户覆盖路径
|
||||
public string OverridePath { get; set; } = "user://localization_override";
|
||||
|
||||
// 是否启用热重载
|
||||
public bool EnableHotReload { get; set; } = true;
|
||||
|
||||
// 是否在加载时验证
|
||||
public bool ValidateOnLoad { get; set; } = true;
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展方法
|
||||
|
||||
### 架构扩展
|
||||
|
||||
```csharp
|
||||
// 发送命令
|
||||
public static void SendCommand<T>(this IBelongToArchitecture self, T command)
|
||||
where T : ICommand;
|
||||
|
||||
// 发送查询
|
||||
public static TResult SendQuery<TQuery, TResult>(
|
||||
this IBelongToArchitecture self, TQuery query)
|
||||
where TQuery : IQuery<TResult>;
|
||||
|
||||
// 发送事件
|
||||
public static void SendEvent<T>(this IBelongToArchitecture self, T e)
|
||||
where T : IEvent;
|
||||
|
||||
// 获取模型
|
||||
public static T GetModel<T>(this IBelongToArchitecture self)
|
||||
where T : IModel;
|
||||
|
||||
// 获取系统
|
||||
public static T GetSystem<T>(this IBelongToArchitecture self)
|
||||
where T : ISystem;
|
||||
|
||||
// 获取工具
|
||||
public static T GetUtility<T>(this IBelongToArchitecture self)
|
||||
where T : IUtility;
|
||||
|
||||
// 注册事件
|
||||
public static IUnRegister RegisterEvent<T>(
|
||||
this IBelongToArchitecture self, Action<T> onEvent)
|
||||
where T : IEvent;
|
||||
```
|
||||
|
||||
### 属性扩展
|
||||
|
||||
```csharp
|
||||
// 添加到注销列表
|
||||
public static IUnRegister AddToUnregisterList(
|
||||
this IUnRegister self, IUnRegisterList list);
|
||||
|
||||
// 注销所有
|
||||
public static void UnRegisterAll(this IUnRegisterList self);
|
||||
```
|
||||
|
||||
## 游戏模块 API
|
||||
|
||||
### GFramework.Game
|
||||
|
||||
游戏业务扩展模块。
|
||||
|
||||
#### 主要类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
|---------------|--------|
|
||||
| `GameSetting` | 游戏设置 |
|
||||
| `GameState` | 游戏状态 |
|
||||
| `IGameModule` | 游戏模块接口 |
|
||||
|
||||
## Godot 集成 API
|
||||
|
||||
### GFramework.Godot
|
||||
|
||||
Godot 引擎集成模块。
|
||||
|
||||
#### 主要类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------------------|------------|
|
||||
| `GodotNode` | Godot 节点扩展 |
|
||||
| `GodotCoroutine` | Godot 协程 |
|
||||
| `GodotSignal` | Godot 信号 |
|
||||
|
||||
## 源码生成器
|
||||
|
||||
### Source Generators 家族
|
||||
|
||||
自动代码生成工具按模块拆分为 `GFramework.Core.SourceGenerators`、`GFramework.Game.SourceGenerators`、
|
||||
`GFramework.Godot.SourceGenerators` 与 `GFramework.Cqrs.SourceGenerators`。面向业务代码声明的 Attribute
|
||||
主要来自 `GFramework.Core.SourceGenerators.Abstractions.*` 与对应模块的 runtime/generator 包。
|
||||
|
||||
#### 支持的生成器
|
||||
|
||||
| 生成器 | 说明 |
|
||||
|--------------------------------------------|-------------|
|
||||
| `LoggingGenerator` | 日志生成器 |
|
||||
| `EnumGenerator` | 枚举扩展生成器 |
|
||||
| `RuleGenerator` | 规则生成器 |
|
||||
| `AutoRegisterModuleGenerator` | 架构模块注册生成器 |
|
||||
| `AutoUiPageGenerator` | UI 页面行为生成器 |
|
||||
| `AutoSceneGenerator` | 场景行为生成器 |
|
||||
| `AutoRegisterExportedCollectionsGenerator` | 导出集合批量注册生成器 |
|
||||
|
||||
#### 常用 Attribute
|
||||
|
||||
| Attribute | 说明 | 文档 |
|
||||
|--------------------------------------------|-------------------------------------------|-------------------------------------------------------------------------------------------------------------|
|
||||
| `AutoRegisterModuleAttribute` | 为模块类生成 `Install(IArchitecture)` | [AutoRegisterModule 生成器](../source-generators/auto-register-module-generator.md) |
|
||||
| `RegisterModelAttribute` | 声明模块内自动注册的 `IModel` 类型 | [AutoRegisterModule 生成器](../source-generators/auto-register-module-generator.md) |
|
||||
| `RegisterSystemAttribute` | 声明模块内自动注册的 `ISystem` 类型 | [AutoRegisterModule 生成器](../source-generators/auto-register-module-generator.md) |
|
||||
| `RegisterUtilityAttribute` | 声明模块内自动注册的 `IUtility` 类型 | [AutoRegisterModule 生成器](../source-generators/auto-register-module-generator.md) |
|
||||
| `AutoUiPageAttribute` | 为 `CanvasItem` 页面节点生成 `GetPage()` | [AutoUiPage 生成器](../source-generators/auto-ui-page-generator.md) |
|
||||
| `AutoSceneAttribute` | 为场景根节点生成 `GetScene()` | [AutoScene 生成器](../source-generators/auto-scene-generator.md) |
|
||||
| `AutoLoadAttribute` | 显式声明 `project.godot` AutoLoad 与 C# 节点类型映射 | [Godot 项目元数据生成器](../source-generators/godot-project-generator.md) |
|
||||
| `AutoRegisterExportedCollectionsAttribute` | 为宿主类开启导出集合批量注册生成 | [AutoRegisterExportedCollections 生成器](../source-generators/auto-register-exported-collections-generator.md) |
|
||||
| `RegisterExportedCollectionAttribute` | 指定集合与注册器成员的映射关系 | [AutoRegisterExportedCollections 生成器](../source-generators/auto-register-exported-collections-generator.md) |
|
||||
|
||||
## 常见用法示例
|
||||
|
||||
### 创建架构
|
||||
|
||||
```csharp
|
||||
public class MyArchitecture : Architecture
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
RegisterModel(new PlayerModel());
|
||||
RegisterSystem(new PlayerSystem());
|
||||
RegisterUtility(new StorageUtility());
|
||||
}
|
||||
}
|
||||
|
||||
// 使用
|
||||
var arch = new MyArchitecture();
|
||||
arch.Initialize();
|
||||
```
|
||||
|
||||
### 发送命令
|
||||
|
||||
```csharp
|
||||
public class AttackCommand : AbstractCommand
|
||||
{
|
||||
public int Damage { get; set; }
|
||||
|
||||
protected override void OnDo()
|
||||
{
|
||||
var player = this.GetModel<PlayerModel>();
|
||||
this.SendEvent(new AttackEvent { Damage = Damage });
|
||||
}
|
||||
}
|
||||
|
||||
// 使用
|
||||
arch.SendCommand(new AttackCommand { Damage = 10 });
|
||||
```
|
||||
|
||||
### 发送查询
|
||||
|
||||
```csharp
|
||||
public class GetPlayerHealthQuery : AbstractQuery<int>
|
||||
{
|
||||
protected override int OnDo()
|
||||
{
|
||||
return this.GetModel<PlayerModel>().Health.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用
|
||||
var health = arch.SendQuery(new GetPlayerHealthQuery());
|
||||
```
|
||||
|
||||
### 监听事件
|
||||
|
||||
```csharp
|
||||
public class PlayerSystem : AbstractSystem
|
||||
{
|
||||
protected override void OnInit()
|
||||
{
|
||||
this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
|
||||
}
|
||||
|
||||
private void OnPlayerDied(PlayerDiedEvent e)
|
||||
{
|
||||
Console.WriteLine("Player died!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 使用本地化
|
||||
|
||||
```csharp
|
||||
// 初始化本地化管理器
|
||||
var config = new LocalizationConfig
|
||||
{
|
||||
DefaultLanguage = "eng",
|
||||
LocalizationPath = "res://localization"
|
||||
};
|
||||
var locManager = new LocalizationManager(config);
|
||||
locManager.Initialize();
|
||||
|
||||
// 获取简单文本
|
||||
string title = locManager.GetText("common", "game.title");
|
||||
|
||||
// 使用变量
|
||||
var message = locManager.GetString("common", "ui.message.welcome")
|
||||
.WithVariable("playerName", "Alice")
|
||||
.Format();
|
||||
|
||||
// 切换语言
|
||||
locManager.SetLanguage("zhs");
|
||||
|
||||
// 监听语言变化
|
||||
locManager.SubscribeToLanguageChange(language =>
|
||||
{
|
||||
Console.WriteLine($"Language changed to: {language}");
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
title: API 参考
|
||||
description: GFramework 的 API 阅读入口,按模块映射 README、专题页、XML 文档和教程链路。
|
||||
---
|
||||
|
||||
更多详情请查看各模块的详细文档。
|
||||
# API 参考
|
||||
|
||||
这里不再维护一份脱离源码演化的“伪 API 列表”。
|
||||
|
||||
当前 `GFramework` 的 API 参考链路以四类证据协同为准:
|
||||
|
||||
1. 模块 README:说明包关系、最小接入路径和目录边界
|
||||
2. `docs/zh-CN` 专题页:说明采用顺序、生命周期和使用建议
|
||||
3. 代码中的 XML 文档:说明公开 / 内部类型和关键成员的契约
|
||||
4. 教程页:说明这些 API 在真实接入路径中的组合方式
|
||||
|
||||
## 阅读顺序
|
||||
|
||||
### 想确认“该装哪个包、先看哪类 API”
|
||||
|
||||
先读模块 README,再读对应 landing page:
|
||||
|
||||
- 入门入口:[`../getting-started/index.md`](../getting-started/index.md)
|
||||
- 根模块地图:仓库根 `README.md`
|
||||
|
||||
### 想确认“这个功能属于哪个模块”
|
||||
|
||||
按下面的模块映射进入对应入口:
|
||||
|
||||
| 模块族 | 模块 README | 站内入口 | XML 文档关注点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Core` / `Core.Abstractions` | `GFramework.Core/README.md`、`GFramework.Core.Abstractions/README.md` | [`../core/index.md`](../core/index.md)、[`../abstractions/core-abstractions.md`](../abstractions/core-abstractions.md) | 架构入口、生命周期、命令 / 查询 / 事件 / 状态 / 资源 / 日志 / 配置 / 并发契约 |
|
||||
| `Cqrs` / `Cqrs.Abstractions` / `Cqrs.SourceGenerators` | `GFramework.Cqrs/README.md`、`GFramework.Cqrs.Abstractions/README.md`、`GFramework.Cqrs.SourceGenerators/README.md` | [`../core/cqrs.md`](../core/cqrs.md)、[`../source-generators/cqrs-handler-registry-generator.md`](../source-generators/cqrs-handler-registry-generator.md) | request / notification / handler / pipeline / registry / fallback contract |
|
||||
| `Game` / `Game.Abstractions` / `Game.SourceGenerators` | `GFramework.Game/README.md`、`GFramework.Game.Abstractions/README.md`、`GFramework.Game.SourceGenerators/README.md` | [`../game/index.md`](../game/index.md)、[`../abstractions/game-abstractions.md`](../abstractions/game-abstractions.md) | 配置、数据、设置、场景、UI、存储、序列化契约 |
|
||||
| `Godot` / `Godot.SourceGenerators` | `GFramework.Godot/README.md`、`GFramework.Godot.SourceGenerators/README.md` | [`../godot/index.md`](../godot/index.md)、[`../source-generators/index.md`](../source-generators/index.md) | 节点扩展、场景 / UI 适配、资源 / 存储 / 日志接入 |
|
||||
| `Ecs.Arch` / `Ecs.Arch.Abstractions` | `GFramework.Ecs.Arch/README.md`、`GFramework.Ecs.Arch.Abstractions/README.md` | [`../ecs/index.md`](../ecs/index.md)、[`../ecs/arch.md`](../ecs/arch.md)、[`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md) | ECS 模块契约、系统适配、配置对象和运行时装配边界 |
|
||||
|
||||
## 先看 XML,还是先看教程
|
||||
|
||||
### 先看 XML 文档的情况
|
||||
|
||||
- 你在确认公开类型的约束、线程 / 生命周期语义、参数和返回值契约
|
||||
- 你需要区分“抽象层保证了什么”和“默认实现额外提供了什么”
|
||||
- 你在做多模块拆分、测试替身或扩展适配层
|
||||
|
||||
优先关注这些类型族:
|
||||
|
||||
- 架构 / 模块 / 服务入口
|
||||
- 生命周期、注册、路由、工厂、provider 契约
|
||||
- Source Generator 的 attribute、diagnostic 和 generated contract
|
||||
|
||||
### 先看教程和专题页的情况
|
||||
|
||||
- 你要的是最小接入路径,而不是逐个类型审计
|
||||
- 你想确认模块组合方式、目录约定和推荐接线顺序
|
||||
- 你在做从旧入口迁移到新入口的采用决策
|
||||
|
||||
优先入口:
|
||||
|
||||
- 教程概览:[`../tutorials/index.md`](../tutorials/index.md)
|
||||
- 最佳实践:[`../best-practices/index.md`](../best-practices/index.md)
|
||||
- 故障排查:[`../troubleshooting.md`](../troubleshooting.md)
|
||||
|
||||
## 当前边界
|
||||
|
||||
- `GFramework.Core.SourceGenerators.Abstractions`
|
||||
- `GFramework.Godot.SourceGenerators.Abstractions`
|
||||
- `GFramework.SourceGenerators.Common`
|
||||
|
||||
这些目录当前不是独立消费模块,因此不单独维护站内 API 参考入口。它们的公开说明跟随所属模块 README 和
|
||||
`source-generators` 栏目维护。
|
||||
|
||||
## 使用方式
|
||||
|
||||
把本页当成“API 阅读导航”而不是“签名快照”:
|
||||
|
||||
- 先选模块
|
||||
- 再进 README 和专题页确认采用路径
|
||||
- 最后回到代码里的 XML 文档核对具体契约
|
||||
|
||||
当 README、专题页和 XML 文档出现冲突时,以源码和测试所反映的当前实现为准。
|
||||
|
||||
@ -1,15 +1,29 @@
|
||||
---
|
||||
title: CQRS
|
||||
description: 当前推荐的新请求模型,统一覆盖 command、query、notification、stream request 和 pipeline behaviors。
|
||||
description: Cqrs 模块族的运行时、契约层、生成器入口,以及 XML / API 阅读链路。
|
||||
---
|
||||
|
||||
# CQRS
|
||||
|
||||
`GFramework.Cqrs` 是当前推荐的新请求模型 runtime。
|
||||
`Cqrs` 栏目对应三个直接相关的消费模块:
|
||||
|
||||
如果你在写新功能,优先使用这套模型,而不是继续扩展 `GFramework.Core.Command` / `Query` 的兼容层。
|
||||
- `GFramework.Cqrs`
|
||||
- `GFramework.Cqrs.Abstractions`
|
||||
- `GFramework.Cqrs.SourceGenerators`
|
||||
|
||||
## 安装方式
|
||||
如果你在写新功能,优先使用这套请求模型,而不是继续扩展 `GFramework.Core.Command` / `Query` 的兼容层。
|
||||
|
||||
## 模块族边界
|
||||
|
||||
| 模块 | 角色 | 何时安装 |
|
||||
| --- | --- | --- |
|
||||
| `GeWuYou.GFramework.Cqrs.Abstractions` | 纯契约层,定义 request、notification、stream、handler、pipeline、runtime seam | 需要把消息契约放到更稳定的共享层,或只依赖接口做解耦 |
|
||||
| `GeWuYou.GFramework.Cqrs` | 默认 runtime,提供 dispatcher、handler 基类、上下文扩展和程序集注册流程 | 大多数直接消费 CQRS 的业务模块 |
|
||||
| `GeWuYou.GFramework.Cqrs.SourceGenerators` | 编译期生成 `ICqrsHandlerRegistry`,缩小运行时反射扫描范围 | handler 较多,想把注册映射前移到编译期 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
最小安装组合是:
|
||||
|
||||
```bash
|
||||
dotnet add package GeWuYou.GFramework.Cqrs
|
||||
@ -22,15 +36,6 @@ dotnet add package GeWuYou.GFramework.Cqrs.Abstractions
|
||||
dotnet add package GeWuYou.GFramework.Cqrs.SourceGenerators
|
||||
```
|
||||
|
||||
## 先理解分层
|
||||
|
||||
- `GFramework.Cqrs.Abstractions`
|
||||
- 纯契约层,定义请求、处理器、行为等接口
|
||||
- `GFramework.Cqrs`
|
||||
- 默认 runtime、dispatcher、处理器基类和上下文扩展
|
||||
- `GFramework.Cqrs.SourceGenerators`
|
||||
- 可选生成器,为消费端程序集生成 `ICqrsHandlerRegistry`
|
||||
|
||||
## 最小示例
|
||||
|
||||
消息基类和处理器基类在不同命名空间:
|
||||
@ -38,12 +43,10 @@ dotnet add package GeWuYou.GFramework.Cqrs.SourceGenerators
|
||||
- 消息基类:`GFramework.Cqrs.Command` / `Query` / `Notification`
|
||||
- 处理器基类:`GFramework.Cqrs.Cqrs.Command` / `Query` / `Notification`
|
||||
|
||||
示例:
|
||||
|
||||
```csharp
|
||||
using GFramework.Cqrs.Abstractions.Cqrs.Command;
|
||||
using GFramework.Cqrs.Command;
|
||||
using GFramework.Cqrs.Cqrs.Command;
|
||||
using GFramework.Cqrs.Abstractions.Cqrs.Command;
|
||||
|
||||
public sealed record CreatePlayerInput(string Name) : ICommandInput;
|
||||
|
||||
@ -66,9 +69,7 @@ public sealed class CreatePlayerCommandHandler
|
||||
}
|
||||
```
|
||||
|
||||
## 发送请求
|
||||
|
||||
如果你在 `IContextAware` 对象内部:
|
||||
如果你在 `IContextAware` 对象内部发送请求:
|
||||
|
||||
```csharp
|
||||
using GFramework.Cqrs.Extensions;
|
||||
@ -77,7 +78,7 @@ var playerId = await this.SendAsync(
|
||||
new CreatePlayerCommand(new CreatePlayerInput("Alice")));
|
||||
```
|
||||
|
||||
如果你在组合根或测试里:
|
||||
如果你在组合根或测试里发送请求:
|
||||
|
||||
```csharp
|
||||
var playerId = await architecture.Context.SendRequestAsync(
|
||||
@ -92,7 +93,7 @@ var playerId = await architecture.Context.SendRequestAsync(
|
||||
- `PublishAsync(...)`
|
||||
- `CreateStream(...)`
|
||||
|
||||
## 查询、通知和流
|
||||
## 统一请求模型
|
||||
|
||||
这套 runtime 不只处理 command,也统一处理:
|
||||
|
||||
@ -103,9 +104,9 @@ var playerId = await architecture.Context.SendRequestAsync(
|
||||
- Stream Request
|
||||
- 返回 `IAsyncEnumerable<T>`
|
||||
|
||||
也就是说,新代码通常不需要再分别设计“命令总线”“查询总线”和另一套通知分发语义。
|
||||
新代码通常不需要再分别设计“命令总线”“查询总线”和另一套通知分发语义。
|
||||
|
||||
## 注册处理器
|
||||
## 处理器注册与生成器协作
|
||||
|
||||
在标准 `Architecture` 启动路径中,CQRS runtime 会自动接入基础设施。你通常只需要在 `OnInitialize()` 里追加行为或额外程序集:
|
||||
|
||||
@ -123,11 +124,15 @@ protected override void OnInitialize()
|
||||
}
|
||||
```
|
||||
|
||||
默认逻辑会:
|
||||
默认注册流程当前遵循这些语义:
|
||||
|
||||
1. 优先使用消费端程序集上的生成注册器
|
||||
2. 生成注册器不可用时回退到反射扫描
|
||||
3. 对同一程序集去重,避免重复注册
|
||||
1. 优先读取消费端程序集上的 `CqrsHandlerRegistryAttribute`
|
||||
2. 存在生成注册器时优先使用 `ICqrsHandlerRegistry`
|
||||
3. 生成注册器不可用或元数据异常时记录告警并回退到反射路径
|
||||
4. 如果程序集带有 `CqrsReflectionFallbackAttribute`,只补扫剩余 handler
|
||||
5. 同一程序集按稳定键去重,避免重复注册
|
||||
|
||||
`Cqrs.SourceGenerators` 的专题入口见 [../source-generators/cqrs-handler-registry-generator.md](../source-generators/cqrs-handler-registry-generator.md)。
|
||||
|
||||
## Pipeline Behavior
|
||||
|
||||
@ -145,7 +150,7 @@ RegisterCqrsPipelineBehavior<LoggingBehavior<,>>();
|
||||
- 审计
|
||||
- 重试或统一异常封装
|
||||
|
||||
旧的 `Mediator` 兼容别名入口已经移除;当前公开入口只有 `RegisterCqrsPipelineBehavior<TBehavior>()`。
|
||||
当前公开入口只有 `RegisterCqrsPipelineBehavior<TBehavior>()`。
|
||||
|
||||
## 和旧 Command / Query 的关系
|
||||
|
||||
@ -157,15 +162,28 @@ RegisterCqrsPipelineBehavior<LoggingBehavior<,>>();
|
||||
- 新路径
|
||||
- `GFramework.Cqrs`
|
||||
|
||||
`IArchitectureContext` 仍然会兼容旧入口,但新代码应优先使用 CQRS runtime。
|
||||
`IArchitectureContext` 仍然兼容旧入口,但新代码应优先使用 CQRS runtime。
|
||||
|
||||
一个简单判断规则:
|
||||
|
||||
- 在维护历史代码:允许继续使用旧 Command / Query
|
||||
- 在写新功能或新模块:优先使用 CQRS
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
下面这份 inventory 记录的是 `2026-04-22` 对 `Cqrs` 家族做的一轮轻量 XML 盘点结果:只统计当前运行时、契约层和生成器入口中的类型声明级 XML 覆盖,用来校对 README、landing page 与 API 入口,不把它表述成成员级契约全审计。
|
||||
|
||||
| 类型族 | 基线状态 | 代表类型 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `GFramework.Cqrs.Abstractions/Cqrs/` | `20/20` 个类型声明已带 XML 注释 | `ICqrsRuntime`、`ICqrsHandlerRegistrar`、`IPipelineBehavior<,>`、`IRequestHandler<,>`、`Unit` | 先看请求、处理器和 runtime seam 的最小契约 |
|
||||
| `GFramework.Cqrs/Command` `Query` `Notification` `Request` `Extensions` | `7/7` 个类型声明已带 XML 注释 | `CommandBase<TInput, TResponse>`、`QueryBase<TInput, TResponse>`、`NotificationBase<TInput>`、`ContextAwareCqrsExtensions` | 看业务侧常用基类和上下文发送入口 |
|
||||
| `GFramework.Cqrs/Cqrs/` | `12/12` 个类型声明已带 XML 注释 | `AbstractCommandHandler<,>`、`AbstractQueryHandler<,>`、`AbstractNotificationHandler<>`、`LoggingBehavior<,>` | 看默认处理器基类、上下文注入与行为管道 |
|
||||
| `GFramework.Cqrs` 根入口与 `Internal/` | `19/19` 个类型声明已带 XML 注释 | `CqrsRuntimeFactory`、`ICqrsHandlerRegistry`、`CqrsHandlerRegistryAttribute`、`CqrsReflectionFallbackAttribute`、`DefaultCqrsRegistrationService` | 看 runtime 创建入口、registry 协议、fallback 语义和程序集去重规则 |
|
||||
| `GFramework.Cqrs.SourceGenerators/Cqrs/` | `3/3` 个类型声明已带 XML 注释 | `CqrsHandlerRegistryGenerator`、`RuntimeTypeReferenceSpec`、`OrderedRegistrationKind` | 看生成注册器、精确 type lookup 和 fallback 诊断边界 |
|
||||
|
||||
## 继续阅读
|
||||
|
||||
- 架构入口:[architecture](./architecture.md)
|
||||
- 上下文入口:[context](./context.md)
|
||||
- 生成器专题:[../source-generators/cqrs-handler-registry-generator.md](../source-generators/cqrs-handler-registry-generator.md)
|
||||
- 模块 README:`GFramework.Cqrs/README.md`
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Core
|
||||
description: GFramework.Core 与 GFramework.Core.Abstractions 的运行时入口、采用顺序和 XML 阅读导航。
|
||||
---
|
||||
|
||||
# Core
|
||||
|
||||
`Core` 栏目对应 `GFramework` 的基础运行时层,主要覆盖 `GFramework.Core` 与 `GFramework.Core.Abstractions`,以及与之直接相邻的旧版
|
||||
@ -29,28 +34,70 @@ dotnet add package GeWuYou.GFramework.Core.Abstractions
|
||||
|
||||
`Core` 栏目不是旧版“完整框架教程”的镜像,而是当前实现的入口导航。这里的页面按能力域组织:
|
||||
|
||||
- 架构与上下文
|
||||
- 架构与生命周期
|
||||
- [architecture](./architecture.md)
|
||||
- [context](./context.md)
|
||||
- [lifecycle](./lifecycle.md)
|
||||
- [async-initialization](./async-initialization.md)
|
||||
- 组件角色与运行时接入
|
||||
- [model](./model.md)
|
||||
- [system](./system.md)
|
||||
- [utility](./utility.md)
|
||||
- [environment](./environment.md)
|
||||
- [extensions](./extensions.md)
|
||||
- 旧版命令 / 查询执行器与迁移入口
|
||||
- [command](./command.md)
|
||||
- [query](./query.md)
|
||||
- [cqrs](./cqrs.md)
|
||||
- 核心横切能力
|
||||
- 状态、事件与规则
|
||||
- [events](./events.md)
|
||||
- [property](./property.md)
|
||||
- [rule](./rule.md)
|
||||
- [logging](./logging.md)
|
||||
- [resource](./resource.md)
|
||||
- [coroutine](./coroutine.md)
|
||||
- [ioc](./ioc.md)
|
||||
- 状态与扩展能力
|
||||
- [state-machine](./state-machine.md)
|
||||
- [state-management](./state-management.md)
|
||||
- 运行时支撑能力
|
||||
- [resource](./resource.md)
|
||||
- [pool](./pool.md)
|
||||
- [coroutine](./coroutine.md)
|
||||
- [pause](./pause.md)
|
||||
- [localization](./localization.md)
|
||||
- [configuration](./configuration.md)
|
||||
- [ioc](./ioc.md)
|
||||
- 通用辅助能力
|
||||
- [functional](./functional.md)
|
||||
- [extensions](./extensions.md)
|
||||
|
||||
## XML 与 API 阅读入口
|
||||
|
||||
如果你已经知道模块归属,但想确认公开类型的契约边界,建议按下面顺序阅读:
|
||||
|
||||
1. 先看模块 README `GFramework.Core/README.md`,确认包关系和目录边界
|
||||
2. 再看本栏目对应专题页,确认采用顺序、生命周期与推荐接线方式
|
||||
3. 最后回到源码中的 XML 文档,重点核对这些类型族:
|
||||
- `Architecture` / `IArchitectureContext`
|
||||
- `CommandExecutor` / `QueryExecutor`
|
||||
- `ILogger` / `ILoggerFactory`
|
||||
- `IResourceManager` / `IConfigurationManager`
|
||||
- `IAsyncKeyLockManager` / `ITimeProvider`
|
||||
|
||||
统一入口见 [`../api-reference/index.md`](../api-reference/index.md)。
|
||||
|
||||
## XML 覆盖基线
|
||||
|
||||
下面这份 inventory 记录的是 `2026-04-22` 对 `GFramework.Core` 做的一轮轻量 XML 盘点结果:只统计顶层目录中的公开 /
|
||||
内部类型声明是否带 XML 注释,用来确认阅读入口和治理优先级;成员级 ``<param>``、``<returns>``、异常语义与线程说明仍需要继续细审。
|
||||
|
||||
| 类型族 | 基线状态 | 代表类型 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Architectures/` | `16/16` 个类型声明已带 XML 注释 | `Architecture`、`ArchitectureContext`、`ArchitectureLifecycle`、`ArchitecturePhaseCoordinator` | 看架构启动、模块安装、阶段切换和上下文暴露边界 |
|
||||
| `Services/` | `6/6` 个类型声明已带 XML 注释 | `ServiceModuleManager`、`CommandExecutorModule`、`CqrsRuntimeModule` | 看服务模块的注册顺序、销毁语义和默认接线 |
|
||||
| `Command/` `Query/` | `15/15` 个类型声明已带 XML 注释 | `CommandExecutor`、`AsyncQueryExecutor`、`AbstractCommand<TInput>`、`AbstractQuery<TResult>` | 看旧入口兼容面与向 `CQRS` 迁移时还保留了哪些执行契约 |
|
||||
| `Events/` `Property/` | `19/19` 个类型声明已带 XML 注释 | `EventBus`、`EnhancedEventBus`、`BindableProperty<T>`、`OrEvent<T>` | 看事件传播、解绑约束和可绑定属性的订阅语义 |
|
||||
| `State/` `StateManagement/` | `10/10` 个类型声明已带 XML 注释 | `StateMachine`、`StateMachineSystem`、`Store<TState>`、`StoreBuilder<TState>` | 看状态切换、selector / middleware / dispatch 的单向流边界 |
|
||||
| `Coroutine/` `Time/` `Pause/` `Concurrency/` | `43/43` 个类型声明已带 XML 注释 | `CoroutineScheduler`、`CoroutineHandle`、`WaitForSecondsRealtime`、`PauseStackManager`、`AsyncKeyLockManager` | 看调度阶段、等待指令、时间源和暂停 / 锁的线程语义 |
|
||||
| `Resource/` `Pool/` | `8/8` 个类型声明已带 XML 注释 | `ResourceManager`、`AutoReleaseStrategy`、`ManualReleaseStrategy`、`AbstractObjectPoolSystem<TKey, TObject>` | 看资源句柄释放策略与对象池复用约束 |
|
||||
| `Logging/` `Localization/` `Configuration/` `Environment/` `Ioc/` | `31/31` 个类型声明已带 XML 注释 | `ConsoleLogger`、`CompositeLogger`、`LocalizationManager`、`ConfigurationManager`、`MicrosoftDiContainer` | 看日志组装、格式化 / filter、配置监听、环境对象与容器适配 |
|
||||
| `Model/` `Systems/` `Utility/` `Rule/` `Extensions/` `Functional/` | `34/34` 个类型声明已带 XML 注释 | `AbstractModel`、`AbstractSystem`、`NumericDisplayFormatter`、`ContextAwareBase`、`Result<T>` | 看默认基类、上下文感知 helper、数值格式化和通用扩展的使用边界 |
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
@ -104,4 +151,5 @@ public sealed class CounterArchitecture : Architecture
|
||||
|
||||
- `GFramework.Core/README.md`
|
||||
- `GFramework.Core.Abstractions/README.md`
|
||||
- `docs/zh-CN/api-reference/index.md`
|
||||
- 仓库根 `README.md`
|
||||
|
||||
@ -1,46 +1,43 @@
|
||||
---
|
||||
title: Arch ECS 集成
|
||||
description: GFramework 的 Arch ECS 集成包使用指南,提供高性能的实体组件系统支持。
|
||||
description: GFramework.Ecs.Arch 的默认运行时装配路径、系统桥接方式与 XML 阅读入口。
|
||||
---
|
||||
|
||||
# Arch ECS 集成
|
||||
|
||||
## 概述
|
||||
`GFramework.Ecs.Arch` 是当前仓库里负责 Arch ECS 默认接入路径的运行时包。它把 Arch `World`、GFramework 的
|
||||
`IServiceModule` 生命周期,以及 `AbstractSystem` / `ISystem` 体系桥接到同一条初始化与更新链路中。
|
||||
|
||||
`GFramework.Ecs.Arch` 是 GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component
|
||||
System)支持。基于 [Arch.Core](https://github.com/genaray/Arch) 实现,具有极致的性能和简洁的 API。
|
||||
## 什么时候依赖它
|
||||
|
||||
**主要特性**:
|
||||
当你需要下面任一能力时,应直接依赖 `GeWuYou.GFramework.Ecs.Arch`:
|
||||
|
||||
- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式
|
||||
- 🔌 **零依赖** - 不使用时,Core 包无 Arch 依赖
|
||||
- 🎯 **类型安全** - 完整的类型系统和编译时检查
|
||||
- ⚡ **高性能** - 基于 Arch ECS 的高性能实现
|
||||
- 🔧 **易扩展** - 简单的系统适配器模式
|
||||
- 📊 **优先级支持** - 系统按优先级顺序执行
|
||||
- 在架构实例上调用 `UseArch(...)`
|
||||
- 让 `World` 在服务模块注册阶段自动创建并注入容器
|
||||
- 让 ECS 系统继承 `ArchSystemAdapter<T>`
|
||||
- 使用仓库自带的 `Position`、`Velocity`、`MovementSystem` 最小示例
|
||||
|
||||
**性能特点**:
|
||||
如果你只想保留共享边界,而不依赖默认实现,请改看
|
||||
[`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md)。
|
||||
|
||||
- 10,000 个实体更新 < 100ms
|
||||
- 1,000 个实体创建 < 50ms
|
||||
- 基于 Archetype 的高效内存布局
|
||||
- 零 GC 分配的组件访问
|
||||
## 最小接入路径
|
||||
|
||||
## 安装
|
||||
### 1. 安装包
|
||||
|
||||
```bash
|
||||
dotnet add package GeWuYou.GFramework.Ecs.Arch
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
### 2. 在 `Initialize()` 之前调用 `UseArch(...)`
|
||||
|
||||
### 1. 注册 ECS 模块
|
||||
当前实现通过 `ArchitectureModuleRegistry.Register(...)` 提前登记 `ArchEcsModule`。这意味着调用时机应位于
|
||||
`Initialize()` 之前,而不是放进 `OnInitialize()` 里。
|
||||
|
||||
```csharp
|
||||
using GFramework.Core.Architecture;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Ecs.Arch.Extensions;
|
||||
|
||||
public class GameArchitecture : Architecture
|
||||
public sealed class GameArchitecture : Architecture
|
||||
{
|
||||
public GameArchitecture() : base(new ArchitectureConfiguration())
|
||||
{
|
||||
@ -48,698 +45,100 @@ public class GameArchitecture : Architecture
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
// 显式注册 Arch ECS 模块
|
||||
this.UseArch();
|
||||
RegisterSystem<MovementSystem>();
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化架构
|
||||
var architecture = new GameArchitecture();
|
||||
var architecture = new GameArchitecture()
|
||||
.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2048;
|
||||
options.Priority = 50;
|
||||
});
|
||||
|
||||
architecture.Initialize();
|
||||
```
|
||||
|
||||
### 2. 带配置的注册
|
||||
### 3. 用 `ArchSystemAdapter<float>` 编写系统
|
||||
|
||||
```csharp
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
// 带配置的注册
|
||||
this.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000; // World 初始容量
|
||||
options.EnableStatistics = true; // 启用统计信息
|
||||
options.Priority = 50; // 模块优先级
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 定义组件
|
||||
|
||||
组件是纯数据结构,使用 `struct` 定义:
|
||||
|
||||
```csharp
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MyGame.Components;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Velocity(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Health(float current, float max)
|
||||
{
|
||||
public float Current { get; set; } = current;
|
||||
public float Max { get; set; } = max;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 创建系统
|
||||
|
||||
系统继承自 `ArchSystemAdapter<T>`:
|
||||
`ArchSystemAdapter<T>` 在 `OnInit()` 中从当前上下文解析 `World`,再把 Arch 的 `Initialize / BeforeUpdate /
|
||||
AfterUpdate / Dispose` 钩子桥接到可重写方法。
|
||||
|
||||
```csharp
|
||||
using Arch.Core;
|
||||
using GFramework.Ecs.Arch;
|
||||
using MyGame.Components;
|
||||
using GFramework.Ecs.Arch.Components;
|
||||
|
||||
namespace MyGame.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// 移动系统 - 更新实体位置
|
||||
/// </summary>
|
||||
public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
private QueryDescription _query;
|
||||
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
// 创建查询:查找所有同时拥有 Position 和 Velocity 组件的实体
|
||||
_query = new QueryDescription()
|
||||
.WithAll<Position, Velocity>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 查询并更新所有符合条件的实体
|
||||
World.Query(in _query, (ref Position pos, ref Velocity vel) =>
|
||||
var frameDelta = deltaTime;
|
||||
|
||||
World.Query(in _query, (ref Position position, ref Velocity velocity) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
position.X += velocity.X * frameDelta;
|
||||
position.Y += velocity.Y * frameDelta;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 注册系统
|
||||
|
||||
```csharp
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
this.UseArch();
|
||||
|
||||
// 注册 ECS 系统
|
||||
RegisterSystem<MovementSystem>();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 创建实体
|
||||
### 4. 初始化后解析 `World` 与模块服务
|
||||
|
||||
```csharp
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.SourceGenerators.Abstractions.Rule;
|
||||
using MyGame.Components;
|
||||
|
||||
[ContextAware]
|
||||
public partial class GameController
|
||||
{
|
||||
public void Start()
|
||||
{
|
||||
// 获取 World
|
||||
var world = this.GetService<World>();
|
||||
|
||||
// 创建实体
|
||||
var player = world.Create(
|
||||
new Position(0, 0),
|
||||
new Velocity(0, 0),
|
||||
new Health(100, 100)
|
||||
);
|
||||
|
||||
var enemy = world.Create(
|
||||
new Position(10, 10),
|
||||
new Velocity(-1, 0),
|
||||
new Health(50, 50)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 更新系统
|
||||
|
||||
```csharp
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
public class GameLoop
|
||||
{
|
||||
private IArchEcsModule _ecsModule;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// 获取 ECS 模块
|
||||
_ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
// 更新所有 ECS 系统
|
||||
_ecsModule.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
var world = architecture.Context.GetService<World>();
|
||||
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
### ArchOptions
|
||||
### 5. 由宿主循环显式调用 `Update`
|
||||
|
||||
```csharp
|
||||
public sealed class ArchOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// World 初始容量(默认:1000)
|
||||
/// </summary>
|
||||
public int WorldCapacity { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用统计信息(默认:false)
|
||||
/// </summary>
|
||||
public bool EnableStatistics { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 模块优先级(默认:50)
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = 50;
|
||||
}
|
||||
ecsModule.Update(deltaTime);
|
||||
```
|
||||
|
||||
### 配置示例
|
||||
这一步在 `GFramework.Ecs.Arch.Tests/Ecs/*.cs` 中也采用同样的驱动方式。
|
||||
|
||||
```csharp
|
||||
this.UseArch(options =>
|
||||
{
|
||||
// 设置 World 初始容量
|
||||
// 根据预期实体数量设置,避免频繁扩容
|
||||
options.WorldCapacity = 2000;
|
||||
## 运行时职责
|
||||
|
||||
// 启用统计信息(开发/调试时使用)
|
||||
options.EnableStatistics = true;
|
||||
| 类型 | 责任 | 证据文件 |
|
||||
| --- | --- | --- |
|
||||
| `ArchExtensions` | 把 `ArchEcsModule` 注册到 `ArchitectureModuleRegistry` | `GFramework.Ecs.Arch/Extensions/ArchExtensions.cs` |
|
||||
| `ArchEcsModule` | 创建并注册 `World`,按优先级收集 `ArchSystemAdapter<float>`,负责初始化、销毁和逐帧更新 | `GFramework.Ecs.Arch/ArchEcsModule.cs` |
|
||||
| `ArchSystemAdapter<T>` | 从 GFramework 系统生命周期桥接到 Arch `ISystem<T>` 生命周期 | `GFramework.Ecs.Arch/ArchSystemAdapter.cs` |
|
||||
| `ArchOptions` | 暴露 `WorldCapacity`、`EnableStatistics`、`Priority` 这组运行时配置对象 | `GFramework.Ecs.Arch/ArchOptions.cs` |
|
||||
|
||||
// 设置模块优先级
|
||||
// 数值越小,优先级越高
|
||||
options.Priority = 50;
|
||||
});
|
||||
```
|
||||
## 配置对象阅读提示
|
||||
|
||||
## 核心概念
|
||||
当前公开配置对象是 `GFramework.Ecs.Arch.ArchOptions`。从源码可直接确认:
|
||||
|
||||
### Entity(实体)
|
||||
- `WorldCapacity` 用于 `World.Create(...)` 的容量参数
|
||||
- `Priority` 影响 `ArchEcsModule` 作为服务模块的排序
|
||||
- `EnableStatistics` 目前保留在公开配置面上;采用时应以源码 XML 注释和实现行为为准,而不是依赖旧文档推断
|
||||
|
||||
实体是游戏世界中的基本对象,本质上是一个唯一标识符:
|
||||
## 类型族级 XML Inventory
|
||||
|
||||
```csharp
|
||||
// 创建空实体
|
||||
var entity = world.Create();
|
||||
| 类型族 | 代表类型 | XML 状态 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| 装配入口 | `ArchExtensions` | 已覆盖 | `UseArch(...)` 的时机、链式调用返回值 |
|
||||
| 服务模块 | `ArchEcsModule` | 已覆盖 | `World` 注册、系统收集、模块销毁顺序 |
|
||||
| 系统桥接层 | `ArchSystemAdapter<T>` | 已覆盖 | `OnArchInitialize` / `OnUpdate` / `OnArchDispose` |
|
||||
| 示例类型 | `Position`、`Velocity`、`MovementSystem` | 已覆盖 | 组件布局、查询写法、最小集成样例 |
|
||||
|
||||
// 创建带组件的实体
|
||||
var entity = world.Create(
|
||||
new Position(0, 0),
|
||||
new Velocity(1, 1)
|
||||
);
|
||||
## 相关入口
|
||||
|
||||
// 销毁实体
|
||||
world.Destroy(entity);
|
||||
```
|
||||
|
||||
### Component(组件)
|
||||
|
||||
组件是纯数据结构,用于存储实体的状态:
|
||||
|
||||
```csharp
|
||||
// 添加组件
|
||||
world.Add(entity, new Position(0, 0));
|
||||
|
||||
// 检查组件
|
||||
if (world.Has<Position>(entity))
|
||||
{
|
||||
// 获取组件引用(零 GC 分配)
|
||||
ref var pos = ref world.Get<Position>(entity);
|
||||
pos.X += 10;
|
||||
}
|
||||
|
||||
// 设置组件(替换现有值)
|
||||
world.Set(entity, new Position(100, 100));
|
||||
|
||||
// 移除组件
|
||||
world.Remove<Velocity>(entity);
|
||||
```
|
||||
|
||||
### System(系统)
|
||||
|
||||
系统包含游戏逻辑,处理具有特定组件组合的实体:
|
||||
|
||||
```csharp
|
||||
public sealed class DamageSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
private QueryDescription _query;
|
||||
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
// 初始化查询
|
||||
_query = new QueryDescription()
|
||||
.WithAll<Health, Damage>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 处理伤害
|
||||
World.Query(in _query, (Entity entity, ref Health health, ref Damage damage) =>
|
||||
{
|
||||
health.Current -= damage.Value * deltaTime;
|
||||
|
||||
if (health.Current <= 0)
|
||||
{
|
||||
health.Current = 0;
|
||||
World.Remove<Damage>(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### World(世界)
|
||||
|
||||
World 是 ECS 的核心容器,管理所有实体和组件:
|
||||
|
||||
```csharp
|
||||
// World 由 ArchEcsModule 自动创建和注册
|
||||
var world = this.GetService<World>();
|
||||
|
||||
// 获取实体数量
|
||||
var entityCount = world.Size;
|
||||
|
||||
// 清空所有实体
|
||||
world.Clear();
|
||||
```
|
||||
|
||||
## 系统适配器
|
||||
|
||||
### ArchSystemAdapter<T>
|
||||
|
||||
`ArchSystemAdapter<T>` 桥接 Arch.System.ISystem<T> 到 GFramework 架构:
|
||||
|
||||
```csharp
|
||||
public sealed class MySystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// Arch 系统初始化
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
// 创建查询、初始化资源
|
||||
}
|
||||
|
||||
// 更新前调用
|
||||
protected override void OnBeforeUpdate(in float deltaTime)
|
||||
{
|
||||
// 预处理逻辑
|
||||
}
|
||||
|
||||
// 主更新逻辑
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 处理实体
|
||||
}
|
||||
|
||||
// 更新后调用
|
||||
protected override void OnAfterUpdate(in float deltaTime)
|
||||
{
|
||||
// 后处理逻辑
|
||||
}
|
||||
|
||||
// 资源清理
|
||||
protected override void OnArchDispose()
|
||||
{
|
||||
// 清理资源
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 访问 World
|
||||
|
||||
在系统中可以直接访问 `World` 属性:
|
||||
|
||||
```csharp
|
||||
public sealed class MySystem : ArchSystemAdapter<float>
|
||||
{
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 访问 World
|
||||
var entityCount = World.Size;
|
||||
|
||||
// 创建实体
|
||||
var entity = World.Create(new Position(0, 0));
|
||||
|
||||
// 查询实体
|
||||
var query = new QueryDescription().WithAll<Position>();
|
||||
World.Query(in query, (ref Position pos) =>
|
||||
{
|
||||
// 处理逻辑
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 访问框架服务
|
||||
|
||||
`ArchSystemAdapter<T>` 继承自 `AbstractSystem`,可以使用所有 GFramework 的扩展方法:
|
||||
|
||||
```csharp
|
||||
public sealed class ServiceAccessSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 获取 Model
|
||||
var playerModel = this.GetModel<PlayerModel>();
|
||||
|
||||
// 获取 Utility
|
||||
var timeUtility = this.GetUtility<TimeUtility>();
|
||||
|
||||
// 发送命令
|
||||
this.SendCommand(new SaveGameCommand());
|
||||
|
||||
// 发送查询
|
||||
var score = this.SendQuery(new GetScoreQuery());
|
||||
|
||||
// 发送事件
|
||||
this.SendEvent(new GameOverEvent());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 查询实体
|
||||
|
||||
### 基本查询
|
||||
|
||||
```csharp
|
||||
// 查询:必须有 Position 和 Velocity
|
||||
var query = new QueryDescription()
|
||||
.WithAll<Position, Velocity>();
|
||||
|
||||
World.Query(in query, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
});
|
||||
```
|
||||
|
||||
### 过滤查询
|
||||
|
||||
```csharp
|
||||
// 查询:必须有 Health,但不能有 Damage
|
||||
var query = new QueryDescription()
|
||||
.WithAll<Health>()
|
||||
.WithNone<Damage>();
|
||||
|
||||
World.Query(in query, (ref Health health) =>
|
||||
{
|
||||
// 只处理没有受伤的实体
|
||||
});
|
||||
```
|
||||
|
||||
### 可选组件查询
|
||||
|
||||
```csharp
|
||||
// 查询:必须有 Position,可选 Velocity
|
||||
var query = new QueryDescription()
|
||||
.WithAll<Position>()
|
||||
.WithAny<Velocity>();
|
||||
|
||||
World.Query(in query, (Entity entity, ref Position pos) =>
|
||||
{
|
||||
// 处理逻辑
|
||||
});
|
||||
```
|
||||
|
||||
### 访问实体 ID
|
||||
|
||||
```csharp
|
||||
var query = new QueryDescription().WithAll<Position>();
|
||||
|
||||
World.Query(in query, (Entity entity, ref Position pos) =>
|
||||
{
|
||||
// 可以访问实体 ID
|
||||
Console.WriteLine($"Entity {entity.Id}: ({pos.X}, {pos.Y})");
|
||||
|
||||
// 可以对实体进行操作
|
||||
if (pos.X > 100)
|
||||
{
|
||||
World.Destroy(entity);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 系统优先级
|
||||
|
||||
系统按照优先级顺序执行,数值越小优先级越高:
|
||||
|
||||
```csharp
|
||||
using GFramework.Core.Abstractions.bases;
|
||||
using GFramework.Core.SourceGenerators.Abstractions.Bases;
|
||||
|
||||
// 使用 Priority 特性设置优先级
|
||||
[Priority(10)] // 高优先级,先执行
|
||||
public sealed class InputSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
[Priority(20)] // 中优先级
|
||||
public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
[Priority(30)] // 低优先级,后执行
|
||||
public sealed class RenderSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
执行顺序:InputSystem → MovementSystem → RenderSystem
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 1. 使用 struct 组件
|
||||
|
||||
```csharp
|
||||
// ✅ 推荐:使用 struct
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
// ❌ 不推荐:使用 class
|
||||
public class Position
|
||||
{
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 缓存查询
|
||||
|
||||
```csharp
|
||||
public class OptimizedSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// ✅ 推荐:缓存查询
|
||||
private QueryDescription _cachedQuery;
|
||||
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
_cachedQuery = new QueryDescription()
|
||||
.WithAll<Position, Velocity>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
World.Query(in _cachedQuery, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 使用 ref 访问组件
|
||||
|
||||
```csharp
|
||||
// ✅ 推荐:使用 ref 避免复制
|
||||
World.Query(in query, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X; // 直接修改,零 GC
|
||||
});
|
||||
|
||||
// ❌ 不推荐:不使用 ref
|
||||
World.Query(in query, (Position pos, Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X; // 复制值,修改不会生效
|
||||
});
|
||||
```
|
||||
|
||||
### 4. 组件大小优化
|
||||
|
||||
```csharp
|
||||
// ✅ 推荐:小而专注的组件
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
public struct Velocity(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
// ❌ 不推荐:大而全的组件
|
||||
public struct Transform
|
||||
{
|
||||
public float X, Y, Z;
|
||||
public float RotationX, RotationY, RotationZ;
|
||||
public float ScaleX, ScaleY, ScaleZ;
|
||||
public float VelocityX, VelocityY, VelocityZ;
|
||||
// ... 太多数据
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 组件设计原则
|
||||
|
||||
- 使用 `struct` 而不是 `class`
|
||||
- 只包含数据,不包含逻辑
|
||||
- 使用 `[StructLayout(LayoutKind.Sequential)]` 优化内存布局
|
||||
- 保持组件小而专注
|
||||
|
||||
### 2. 系统设计原则
|
||||
|
||||
- 单一职责:每个系统只负责一件事
|
||||
- 缓存查询:在 `OnArchInitialize` 中创建查询
|
||||
- 使用 ref:访问组件时使用 ref 参数
|
||||
- 批量处理:一次查询处理所有实体
|
||||
|
||||
### 3. 标签组件
|
||||
|
||||
使用空结构体作为标签来分类实体:
|
||||
|
||||
```csharp
|
||||
// 定义标签组件
|
||||
public struct PlayerTag { }
|
||||
public struct EnemyTag { }
|
||||
public struct DeadTag { }
|
||||
|
||||
// 使用标签过滤实体
|
||||
var query = new QueryDescription()
|
||||
.WithAll<Position, Velocity, PlayerTag>()
|
||||
.WithNone<DeadTag>();
|
||||
```
|
||||
|
||||
### 4. 与传统架构结合
|
||||
|
||||
```csharp
|
||||
// ECS 系统可以访问 Model
|
||||
public class EnemySpawnSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
var gameState = this.GetModel<GameStateModel>();
|
||||
|
||||
// 根据关卡生成敌人
|
||||
for (int i = 0; i < gameState.Level; i++)
|
||||
{
|
||||
World.Create(
|
||||
new Position(Random.Shared.Next(0, 100), 0),
|
||||
new Velocity(0, -1),
|
||||
new Health(50, 50)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 如何在运行时动态添加/移除组件?
|
||||
|
||||
A: Arch 支持运行时修改实体的组件:
|
||||
|
||||
```csharp
|
||||
// 动态添加组件
|
||||
if (pos.X > 100 && !World.Has<FastTag>(entity))
|
||||
{
|
||||
World.Add(entity, new FastTag());
|
||||
}
|
||||
|
||||
// 动态移除组件
|
||||
if (pos.X < 0 && World.Has<FastTag>(entity))
|
||||
{
|
||||
World.Remove<FastTag>(entity);
|
||||
}
|
||||
```
|
||||
|
||||
### Q: 如何处理实体之间的交互?
|
||||
|
||||
A: 使用嵌套查询或事件:
|
||||
|
||||
```csharp
|
||||
// 方式 1:嵌套查询
|
||||
World.Query(in playerQuery, (Entity player, ref Position playerPos) =>
|
||||
{
|
||||
World.Query(in enemyQuery, (Entity enemy, ref Position enemyPos) =>
|
||||
{
|
||||
// 检测碰撞
|
||||
});
|
||||
});
|
||||
|
||||
// 方式 2:使用事件
|
||||
this.SendEvent(new CollisionEvent
|
||||
{
|
||||
Entity1 = player,
|
||||
Entity2 = enemy
|
||||
});
|
||||
```
|
||||
|
||||
### Q: 如何调试 ECS 系统?
|
||||
|
||||
A: 使用日志和统计信息:
|
||||
|
||||
```csharp
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 打印实体数量
|
||||
Console.WriteLine($"Total entities: {World.Size}");
|
||||
|
||||
// 查询特定实体
|
||||
var query = new QueryDescription().WithAll<Position>();
|
||||
var count = 0;
|
||||
World.Query(in query, (Entity entity, ref Position pos) =>
|
||||
{
|
||||
count++;
|
||||
Console.WriteLine($"Entity {entity.Id}: ({pos.X}, {pos.Y})");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Arch.Core 官方文档](https://github.com/genaray/Arch)
|
||||
- [ECS 概述](./index.md)
|
||||
- ECS 模块总览:[`index.md`](./index.md)
|
||||
- 抽象契约页:[`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md)
|
||||
- 仓库模块 README:`GFramework.Ecs.Arch/README.md`
|
||||
- 统一 API / XML 导航:[`../api-reference/index.md`](../api-reference/index.md)
|
||||
|
||||
@ -1,95 +1,39 @@
|
||||
---
|
||||
title: ECS 系统集成
|
||||
description: GFramework 的 ECS(Entity Component System)集成方案,支持多种 ECS 框架。
|
||||
description: GFramework 当前 ECS 模块族的包边界、采用顺序与 XML 阅读入口。
|
||||
---
|
||||
|
||||
# ECS 系统集成
|
||||
|
||||
## 概述
|
||||
GFramework 当前仓库内已经交付并持续维护的 ECS 模块族是 `Ecs.Arch`。它分成运行时实现包
|
||||
`GFramework.Ecs.Arch` 和契约包 `GFramework.Ecs.Arch.Abstractions`,分别覆盖默认装配能力与共享边界约定。
|
||||
|
||||
GFramework 提供了灵活的 ECS(Entity Component System)集成方案,允许你根据项目需求选择合适的 ECS 框架。ECS
|
||||
是一种数据驱动的架构模式,特别适合处理大量相似实体的场景。
|
||||
## 当前模块族
|
||||
|
||||
## 什么是 ECS?
|
||||
| 包 | 适用场景 | 你会得到什么 | 继续阅读 |
|
||||
| --- | --- | --- | --- |
|
||||
| `GFramework.Ecs.Arch` | 需要默认运行时、`UseArch(...)` 装配入口、`World` 注册和系统适配基类 | `ArchEcsModule`、`ArchSystemAdapter<T>`、`ArchExtensions.UseArch(...)`、示例组件与系统 | [`arch.md`](./arch.md) |
|
||||
| `GFramework.Ecs.Arch.Abstractions` | 只想让共享宿主循环、测试替身或扩展模块依赖最小契约,而不引入默认运行时 | `IArchEcsModule`、`IArchSystemAdapter<T>`、`ArchOptions` 契约对象 | [`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md) |
|
||||
|
||||
ECS(Entity Component System)是一种架构模式,将游戏对象分解为三个核心概念:
|
||||
## 最小采用路径
|
||||
|
||||
- **Entity(实体)**:游戏世界中的基本对象,本质上是一个唯一标识符
|
||||
- **Component(组件)**:纯数据结构,存储实体的状态
|
||||
- **System(系统)**:包含游戏逻辑,处理具有特定组件组合的实体
|
||||
### 1. 选择包边界
|
||||
|
||||
### ECS 的优势
|
||||
- 需要默认实现时安装 `GeWuYou.GFramework.Ecs.Arch`
|
||||
- 只需要契约时安装 `GeWuYou.GFramework.Ecs.Arch.Abstractions`
|
||||
|
||||
- **高性能**:数据局部性好,缓存友好
|
||||
- **可扩展**:通过组合组件轻松创建新实体类型
|
||||
- **并行处理**:系统之间相互独立,易于并行化
|
||||
- **数据驱动**:逻辑与数据分离,便于序列化和网络同步
|
||||
### 2. 在 `Initialize()` 前显式接入运行时
|
||||
|
||||
### 何时使用 ECS?
|
||||
|
||||
**适合使用 ECS 的场景**:
|
||||
|
||||
- 大量相似实体(敌人、子弹、粒子)
|
||||
- 需要高性能批量处理
|
||||
- 复杂的实体组合和变化
|
||||
- 需要并行处理的系统
|
||||
|
||||
**不适合使用 ECS 的场景**:
|
||||
|
||||
- 全局状态管理
|
||||
- 单例服务
|
||||
- UI 逻辑
|
||||
- 游戏流程控制
|
||||
|
||||
## 支持的 ECS 框架
|
||||
|
||||
GFramework 采用可选集成的设计,你可以根据需求选择合适的 ECS 框架:
|
||||
|
||||
### Arch ECS(推荐)
|
||||
|
||||
[Arch](https://github.com/genaray/Arch) 是一个高性能的 C# ECS 框架,具有以下特点:
|
||||
|
||||
- ✅ **极致性能**:基于 Archetype 的内存布局,零 GC 分配
|
||||
- ✅ **简单易用**:清晰的 API,易于上手
|
||||
- ✅ **功能完整**:支持查询、过滤、并行处理等高级特性
|
||||
- ✅ **活跃维护**:社区活跃,持续更新
|
||||
|
||||
**安装方式**:
|
||||
|
||||
```bash
|
||||
dotnet add package GeWuYou.GFramework.Ecs.Arch
|
||||
```
|
||||
|
||||
**文档链接**:[Arch ECS 集成指南](./arch.md)
|
||||
|
||||
### 其他 ECS 框架
|
||||
|
||||
GFramework 的设计允许集成其他 ECS 框架,未来可能支持:
|
||||
|
||||
- **DefaultEcs**:轻量级 ECS 框架
|
||||
- **Entitas**:成熟的 ECS 框架,Unity 生态常用
|
||||
- **自定义 ECS**:你可以基于 GFramework 的模块系统实现自己的 ECS 集成
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 选择 ECS 框架
|
||||
|
||||
根据项目需求选择合适的 ECS 框架。对于大多数项目,我们推荐使用 Arch ECS。
|
||||
|
||||
### 2. 安装集成包
|
||||
|
||||
```bash
|
||||
# 安装 Arch ECS 集成包
|
||||
dotnet add package GeWuYou.GFramework.Ecs.Arch
|
||||
```
|
||||
|
||||
### 3. 注册 ECS 模块
|
||||
`UseArch(...)` 通过 `ArchitectureModuleRegistry` 注册服务模块。按当前源码与集成测试,它应在架构实例调用
|
||||
`Initialize()` 之前完成。
|
||||
|
||||
```csharp
|
||||
using GFramework.Core.Architecture;
|
||||
using GFramework.Ecs.Arc;
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
using GFramework.Ecs.Arch.Extensions;
|
||||
|
||||
public class GameArchitecture : Architecture
|
||||
public sealed class GameArchitecture : Architecture
|
||||
{
|
||||
public GameArchitecture() : base(new ArchitectureConfiguration())
|
||||
{
|
||||
@ -97,41 +41,29 @@ public class GameArchitecture : Architecture
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
// 显式注册 Arch ECS 模块
|
||||
this.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000;
|
||||
options.EnableStatistics = true;
|
||||
});
|
||||
RegisterSystem<MovementSystem>();
|
||||
}
|
||||
}
|
||||
|
||||
var architecture = new GameArchitecture()
|
||||
.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2048;
|
||||
options.Priority = 50;
|
||||
});
|
||||
|
||||
architecture.Initialize();
|
||||
|
||||
var world = architecture.Context.GetService<World>();
|
||||
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
```
|
||||
|
||||
### 4. 定义组件
|
||||
|
||||
```csharp
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Velocity(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 创建系统
|
||||
### 3. 让 ECS 系统继承 `ArchSystemAdapter<float>`
|
||||
|
||||
```csharp
|
||||
using Arch.Core;
|
||||
using GFramework.Ecs.Arch;
|
||||
using GFramework.Ecs.Arch.Components;
|
||||
|
||||
public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
@ -145,147 +77,60 @@ public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
World.Query(in _query, (ref Position pos, ref Velocity vel) =>
|
||||
var frameDelta = deltaTime;
|
||||
|
||||
World.Query(in _query, (ref Position position, ref Velocity velocity) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
position.X += velocity.X * frameDelta;
|
||||
position.Y += velocity.Y * frameDelta;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 注册系统
|
||||
### 4. 由宿主循环驱动更新
|
||||
|
||||
`IArchEcsModule` 继承自 `IServiceModule`,负责初始化和销毁;真正的帧更新通过 `Update(float deltaTime)` 显式触发。
|
||||
|
||||
```csharp
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
this.UseArch();
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
// 注册 ECS 系统
|
||||
RegisterSystem<MovementSystem>();
|
||||
public sealed class GameLoop
|
||||
{
|
||||
private readonly IArchEcsModule _ecsModule;
|
||||
|
||||
public GameLoop(IArchEcsModule ecsModule)
|
||||
{
|
||||
_ecsModule = ecsModule;
|
||||
}
|
||||
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
_ecsModule.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 设计理念
|
||||
## 阅读顺序
|
||||
|
||||
### 显式集成
|
||||
1. 先看本页,确认自己要的是运行时包还是契约包
|
||||
2. 需要默认实现时继续读 [`arch.md`](./arch.md)
|
||||
3. 只想保留共享边界时继续读 [`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md)
|
||||
4. 统一查阅 README / docs / XML 入口时回到 [`../api-reference/index.md`](../api-reference/index.md)
|
||||
|
||||
GFramework 采用显式集成的设计,而不是自动注册:
|
||||
## 类型族级 XML Inventory
|
||||
|
||||
```csharp
|
||||
// ✅ 显式注册 - 清晰、可控
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
this.UseArch(); // 明确表示使用 Arch ECS
|
||||
}
|
||||
}
|
||||
下表记录当前 `Ecs.Arch` family 的类型声明级 XML 基线,便于从 README、站内 landing 和源码之间建立一致的审计入口。
|
||||
|
||||
// ❌ 自动注册 - 隐式、难以控制
|
||||
// 只需引入包,自动注册(不推荐)
|
||||
```
|
||||
| 包 | 类型族 | 代表类型 | XML 状态 | 阅读重点 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `GFramework.Ecs.Arch` | 运行时装配与模块生命周期 | `ArchExtensions`、`ArchEcsModule` | 已覆盖 | `UseArch(...)` 的接入时机、`World` 注册、模块优先级 |
|
||||
| `GFramework.Ecs.Arch` | 系统桥接层 | `ArchSystemAdapter<T>` | 已覆盖 | GFramework `ISystem` 生命周期如何桥接到 Arch `ISystem<T>` |
|
||||
| `GFramework.Ecs.Arch` | 示例组件与系统 | `Position`、`Velocity`、`MovementSystem` | 已覆盖 | 查询写法、组件布局、最小可运行示例 |
|
||||
| `GFramework.Ecs.Arch.Abstractions` | 契约与配置对象 | `IArchEcsModule`、`IArchSystemAdapter<T>`、`ArchOptions` | 已覆盖 | 共享宿主循环、测试替身、跨程序集配置边界 |
|
||||
|
||||
**优势**:
|
||||
## 边界说明
|
||||
|
||||
- 清晰的依赖关系
|
||||
- 更好的 IDE 支持
|
||||
- 易于测试和调试
|
||||
- 符合 .NET 生态习惯
|
||||
|
||||
### 零依赖原则
|
||||
|
||||
如果你不使用 ECS,GFramework.Core 包不会引入任何 ECS 相关的依赖:
|
||||
|
||||
```xml
|
||||
<!-- GFramework.Core.csproj -->
|
||||
<ItemGroup>
|
||||
<!-- 无 Arch 依赖 -->
|
||||
</ItemGroup>
|
||||
|
||||
<!-- GFramework.Ecs.Arch.csproj -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Arch" Version="2.1.0" />
|
||||
<PackageReference Include="Arch.System" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
### 模块化设计
|
||||
|
||||
ECS 集成基于 GFramework 的模块系统:
|
||||
|
||||
```csharp
|
||||
// ECS 模块实现 IServiceModule 接口
|
||||
public sealed class ArchEcsModule : IArchEcsModule
|
||||
{
|
||||
public string ModuleName => nameof(ArchEcsModule);
|
||||
public int Priority => 50;
|
||||
public bool IsEnabled { get; }
|
||||
|
||||
public void Register(IIocContainer container) { }
|
||||
public void Initialize() { }
|
||||
public ValueTask DestroyAsync() { }
|
||||
public void Update(float deltaTime) { }
|
||||
}
|
||||
```
|
||||
|
||||
## 与传统架构结合
|
||||
|
||||
ECS 可以与 GFramework 的传统架构(Model、System、Utility)无缝结合:
|
||||
|
||||
```csharp
|
||||
// Model 存储全局状态
|
||||
public class GameStateModel : AbstractModel
|
||||
{
|
||||
public int Score { get; set; }
|
||||
public int Level { get; set; }
|
||||
}
|
||||
|
||||
// ECS System 处理实体逻辑
|
||||
public class EnemySpawnSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 访问 Model
|
||||
var gameState = this.GetModel<GameStateModel>();
|
||||
|
||||
// 根据关卡生成敌人
|
||||
for (int i = 0; i < gameState.Level; i++)
|
||||
{
|
||||
World.Create(
|
||||
new Position(Random.Shared.Next(0, 100), 0),
|
||||
new Velocity(0, -1),
|
||||
new Health(50, 50)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 传统 System 处理游戏逻辑
|
||||
public class ScoreSystem : AbstractSystem
|
||||
{
|
||||
protected override void OnInit()
|
||||
{
|
||||
this.RegisterEvent<EnemyDestroyedEvent>(OnEnemyDestroyed);
|
||||
}
|
||||
|
||||
private void OnEnemyDestroyed(EnemyDestroyedEvent e)
|
||||
{
|
||||
var gameState = this.GetModel<GameStateModel>();
|
||||
gameState.Score += 100;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 下一步
|
||||
|
||||
- [Arch ECS 集成指南](./arch.md) - 详细的 Arch ECS 使用文档
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Architecture 架构系统](../core/architecture.md)
|
||||
- [System 系统](../core/system.md)
|
||||
- [事件系统](../core/events.md)
|
||||
- 当前仓库没有交付其他可直接消费的 ECS 运行时包;旧文档把“未来可能支持的其他 ECS 框架”写成现有能力,会误导采用路径。
|
||||
- `GFramework.Ecs.Arch.Abstractions` 负责“边界”,`GFramework.Ecs.Arch` 负责“默认实现”。
|
||||
- 站内页面只维护可构建的 docs 链路;仓库根 README 和模块 README 继续承担包目录入口职责。
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Game
|
||||
description: GFramework.Game family 的运行时入口、采用顺序与 XML 阅读基线。
|
||||
---
|
||||
|
||||
# Game
|
||||
|
||||
`Game` 栏目对应 `GFramework.Game` 与 `GFramework.Game.Abstractions` 这层游戏运行时能力。
|
||||
@ -98,6 +103,16 @@ IStorage storage = new FileStorage("GameData", serializer);
|
||||
4. [setting](./setting.md)
|
||||
5. [scene](./scene.md) 或 [ui](./ui.md)
|
||||
|
||||
## Game Family XML 覆盖基线
|
||||
|
||||
下面这份 inventory 记录的是 `2026-04-23` 对 `Game` family 做的一轮轻量 XML 盘点结果:只统计公开 / 内部类型声明是否带 XML 注释,用来建立 README / landing / API 阅读链路;成员级 `param`、`returns`、`exception` 与生命周期说明仍需要后续波次继续细化。
|
||||
|
||||
| 模块 | 基线状态 | 代表类型 | 阅读重点 |
|
||||
| --- | --- | --- | --- |
|
||||
| `GFramework.Game` | `56/56` 个类型声明已带 XML 注释 | `YamlConfigLoader`、`SettingsModel<TRepository>`、`SceneRouterBase`、`UiRouterBase` | 先看运行时默认实现、配置加载、设置编排和路由基类 |
|
||||
| `GFramework.Game.Abstractions` | `80/80` 个类型声明已带 XML 注释 | `IConfigRegistry`、`ISaveRepository<TSaveData>`、`ISettingsSystem`、`ISceneRouter`、`IUiRouter` | 再看契约层边界,决定项目哪些程序集只依赖接口 |
|
||||
| `GFramework.Game.SourceGenerators` | `2/2` 个类型声明已带 XML 注释 | `SchemaConfigGenerator`、`ConfigSchemaDiagnostics` | 最后看 schema 生成入口与诊断模型,确认配置系统的编译期链路 |
|
||||
|
||||
## 与真实接法的关系
|
||||
|
||||
这个栏目以源码、`*.csproj`、模块 `README.md` 与 `ai-libs/` 下已验证的参考接法为准。
|
||||
|
||||
131
docs/zh-CN/source-generators/cqrs-handler-registry-generator.md
Normal file
131
docs/zh-CN/source-generators/cqrs-handler-registry-generator.md
Normal file
@ -0,0 +1,131 @@
|
||||
---
|
||||
title: CQRS Handler Registry 生成器
|
||||
description: 为消费端程序集生成 CQRS handler registry,并在需要时附带精确 reflection fallback 元数据。
|
||||
---
|
||||
|
||||
# CQRS Handler Registry 生成器
|
||||
|
||||
`GFramework.Cqrs.SourceGenerators` 会在编译期为当前业务程序集生成 `ICqrsHandlerRegistry`,让 `GFramework.Cqrs`
|
||||
runtime 在注册 handlers 时优先走静态注册表,而不是先扫描整个程序集。
|
||||
|
||||
它服务的是 `Cqrs` 家族,不是独立运行时:
|
||||
|
||||
- 契约层:`GeWuYou.GFramework.Cqrs.Abstractions`
|
||||
- 默认 runtime:`GeWuYou.GFramework.Cqrs`
|
||||
- 编译期生成器:`GeWuYou.GFramework.Cqrs.SourceGenerators`
|
||||
|
||||
## 生成什么
|
||||
|
||||
当前生成器会分析消费端程序集中的:
|
||||
|
||||
- `IRequestHandler<,>`
|
||||
- `INotificationHandler<>`
|
||||
- `IStreamRequestHandler<,>`
|
||||
|
||||
然后输出两类结果:
|
||||
|
||||
1. 一个实现 `ICqrsHandlerRegistry` 的内部注册器类型
|
||||
2. 程序集级 `CqrsHandlerRegistryAttribute`
|
||||
|
||||
当某些 handler 不能被生成代码安全地直接引用时,还会补发:
|
||||
|
||||
- 程序集级 `CqrsReflectionFallbackAttribute`
|
||||
|
||||
这意味着运行时会先使用生成注册器完成可静态表达的映射,再只对剩余类型做补扫,而不是退回整程序集盲扫。
|
||||
|
||||
## 最小接入路径
|
||||
|
||||
安装方式保持 runtime 包与生成器包版本一致,并把生成器作为编译期依赖引入:
|
||||
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GeWuYou.GFramework.Cqrs" Version="x.y.z" />
|
||||
<PackageReference Include="GeWuYou.GFramework.Cqrs.Abstractions" Version="x.y.z" />
|
||||
<PackageReference Include="GeWuYou.GFramework.Cqrs.SourceGenerators"
|
||||
Version="x.y.z"
|
||||
PrivateAssets="all"
|
||||
ExcludeAssets="runtime" />
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
运行时侧仍然按 `Core` 的标准入口注册程序集:
|
||||
|
||||
```csharp
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
RegisterCqrsHandlersFromAssembly(typeof(GameArchitecture).Assembly);
|
||||
}
|
||||
```
|
||||
|
||||
如果你的 handlers 分布在多个业务程序集里,则改用:
|
||||
|
||||
```csharp
|
||||
RegisterCqrsHandlersFromAssemblies(
|
||||
[
|
||||
typeof(InventoryCqrsMarker).Assembly,
|
||||
typeof(BattleCqrsMarker).Assembly
|
||||
]);
|
||||
```
|
||||
|
||||
文档示例统一用 marker 类型承载程序集引用。框架本身不要求固定目录或固定命名,但团队实践里可以把这类空 marker
|
||||
集中放在每个业务程序集自己的 `Application/Markers` 或等价目录,并采用 `InventoryCqrsMarker` 这类能直接看出来源
|
||||
的名字,避免多人协作时拿无关业务类型充当程序集定位锚点。
|
||||
|
||||
## 运行时如何消费生成结果
|
||||
|
||||
`Cqrs` runtime 当前的注册顺序是:
|
||||
|
||||
1. 先读取程序集上的 `CqrsHandlerRegistryAttribute`
|
||||
2. 优先激活生成的 `ICqrsHandlerRegistry`
|
||||
3. 若生成元数据损坏、registry 不可激活,记录告警并回退到反射路径
|
||||
4. 若存在 `CqrsReflectionFallbackAttribute`,只补扫剩余 handler
|
||||
5. 同一程序集按稳定键去重,避免重复注册
|
||||
|
||||
这个行为由 `GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs` 和
|
||||
`GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 共同覆盖。
|
||||
|
||||
## 什么时候值得安装
|
||||
|
||||
推荐安装:
|
||||
|
||||
- 业务程序集内 handler 数量较多
|
||||
- 想把 handler 注册路径前移到编译期
|
||||
- 希望冷启动阶段减少整程序集反射扫描
|
||||
- 需要更明确地观察“哪些 handler 走静态注册,哪些只能走 fallback”
|
||||
|
||||
可以先不装:
|
||||
|
||||
- 项目体量很小,handler 很少
|
||||
- 当前只做原型,尚不关心注册成本
|
||||
- 你还没稳定到 `Cqrs` runtime 的最终接入边界
|
||||
|
||||
## fallback 边界
|
||||
|
||||
生成器并不会承诺“所有 handler 都能被静态表达”。
|
||||
|
||||
当前实现遵循一个保守原则:
|
||||
|
||||
- 能直接引用的 handler,生成直接注册语句
|
||||
- 实现类型不能直接引用、但服务接口还能精确表达时,生成反射实现类型查找
|
||||
- 服务接口本身也需要运行时解析时,生成精确 type lookup
|
||||
- 只有在 runtime 提供 `CqrsReflectionFallbackAttribute` 合同时,才允许发射依赖 fallback 的结果
|
||||
|
||||
如果当前编译环境缺少这个 fallback 合同,而某些 handler 又必须依赖它,生成器会报:
|
||||
|
||||
- `GF_Cqrs_001`
|
||||
|
||||
这条诊断的含义不是“某个 handler 写错了”,而是“当前 runtime 合同不足以安全承载这轮生成结果”。
|
||||
|
||||
## XML / API 阅读入口
|
||||
|
||||
如果你要核对生成器对外暴露的契约,优先看这些类型:
|
||||
|
||||
- `GFramework.Cqrs.ICqrsHandlerRegistry`
|
||||
- `GFramework.Cqrs.CqrsHandlerRegistryAttribute`
|
||||
- `GFramework.Cqrs.CqrsReflectionFallbackAttribute`
|
||||
- `GFramework.Cqrs.SourceGenerators.Cqrs.CqrsHandlerRegistryGenerator`
|
||||
|
||||
模块族入口见:
|
||||
|
||||
- [../core/cqrs.md](../core/cqrs.md)
|
||||
- [./index.md](./index.md)
|
||||
@ -65,7 +65,9 @@ GFramework 当前发布的生成器包是:
|
||||
|
||||
- 配置 schema 生成与运行时接法:
|
||||
- [../game/config-system.md](../game/config-system.md)
|
||||
- CQRS registry 生成入口:
|
||||
- CQRS handler registry 生成器:
|
||||
- [cqrs-handler-registry-generator](./cqrs-handler-registry-generator.md)
|
||||
- CQRS 模块族采用入口:
|
||||
- [../core/cqrs.md](../core/cqrs.md)
|
||||
|
||||
### Godot 专用生成器
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user