diff --git a/.agents/skills/gframework-pr-review/SKILL.md b/.agents/skills/gframework-pr-review/SKILL.md index 42ecfa95..473f9aa0 100644 --- a/.agents/skills/gframework-pr-review/SKILL.md +++ b/.agents/skills/gframework-pr-review/SKILL.md @@ -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. diff --git a/.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py b/.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py index a2e98cd7..ee9d870c 100644 --- a/.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py +++ b/.agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py @@ -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]: diff --git a/AGENTS.md b/AGENTS.md index cafd8cb7..27a2395f 100644 --- a/AGENTS.md +++ b/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=/.git/worktrees/` and `--work-tree=` 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 diff --git a/GFramework.Core.Abstractions/README.md b/GFramework.Core.Abstractions/README.md index 4be033ab..d6a9753b 100644 --- a/GFramework.Core.Abstractions/README.md +++ b/GFramework.Core.Abstractions/README.md @@ -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` | +| `Command/` `Query/` `Cqrs/` | `10/10` 个类型声明已带 XML 注释 | `ICommandExecutor`、`IAsyncQueryExecutor`、`ICqrsRuntime` | +| `Events/` `Property/` `State/` `StateManagement/` | `25/25` 个类型声明已带 XML 注释 | `IEventBus`、`IBindableProperty`、`IStateMachine`、`IStore` | +| `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`、`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) diff --git a/GFramework.Core/README.md b/GFramework.Core/README.md index 8287bd24..61e89a8a 100644 --- a/GFramework.Core/README.md +++ b/GFramework.Core/README.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 注释。这里先保留阅读基线,成员级 ```` / ```` / 生命周期语义审计仍属于后续治理项。 + +| 类型族 | 基线状态 | 代表类型 | +| --- | --- | --- | +| `Architectures/` `Services/` | `22/22` 个类型声明已带 XML 注释 | `Architecture`、`ArchitectureContext`、`ArchitectureLifecycle`、`ServiceModuleManager` | +| `Command/` `Query/` | `15/15` 个类型声明已带 XML 注释 | `CommandExecutor`、`AsyncQueryExecutor`、`AbstractCommand`、`AbstractQuery` | +| `Events/` `Property/` `State/` `StateManagement/` | `29/29` 个类型声明已带 XML 注释 | `EventBus`、`BindableProperty`、`StateMachine`、`Store` | +| `Coroutine/` `Time/` `Pause/` `Concurrency/` | `43/43` 个类型声明已带 XML 注释 | `CoroutineScheduler`、`CoroutineHandle`、`PauseStackManager`、`AsyncKeyLockManager` | +| `Resource/` `Pool/` | `8/8` 个类型声明已带 XML 注释 | `ResourceManager`、`AutoReleaseStrategy`、`AbstractObjectPoolSystem` | +| `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` | + +完整的模块化阅读顺序和 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) diff --git a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs index 9b3f889e..f74ec308 100644 --- a/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs +++ b/GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs @@ -1144,6 +1144,13 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator string HandlerInterfaceDisplayName, string HandlerInterfaceLogName); + /// + /// 标记某条 handler 注册语句在生成阶段采用的表达策略。 + /// + /// + /// 该枚举只服务于输出排序与代码分支选择,用来保证生成注册器在“直接注册” + /// “反射实现类型查找”和“精确运行时类型解析”之间保持稳定顺序。 + /// private enum OrderedRegistrationKind { Direct, @@ -1151,6 +1158,14 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator PreciseReflected } + /// + /// 描述生成注册器中某个运行时类型引用的构造方式。 + /// + /// + /// 某些 handler 服务类型可以直接以 typeof(...) 输出,某些则需要在运行时补充 + /// 反射查找、数组/指针封装或泛型实参重建。该记录把这些差异收敛为统一的递归结构, + /// 供源码输出阶段生成稳定的类型解析语句。 + /// private sealed record RuntimeTypeReferenceSpec( string? TypeDisplayName, string? ReflectionTypeMetadataName, @@ -1161,18 +1176,27 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator RuntimeTypeReferenceSpec? GenericTypeDefinitionReference, ImmutableArray GenericTypeArguments) { + /// + /// 创建一个可直接通过 typeof(...) 表达的类型引用。 + /// public static RuntimeTypeReferenceSpec FromDirectReference(string typeDisplayName) { return new RuntimeTypeReferenceSpec(typeDisplayName, null, null, null, 0, null, null, ImmutableArray.Empty); } + /// + /// 创建一个需要从当前消费端程序集反射解析的类型引用。 + /// public static RuntimeTypeReferenceSpec FromReflectionLookup(string reflectionTypeMetadataName) { return new RuntimeTypeReferenceSpec(null, reflectionTypeMetadataName, null, null, 0, null, null, ImmutableArray.Empty); } + /// + /// 创建一个需要从被引用程序集反射解析的类型引用。 + /// public static RuntimeTypeReferenceSpec FromExternalReflectionLookup( string reflectionAssemblyName, string reflectionTypeMetadataName) @@ -1182,18 +1206,27 @@ public sealed class CqrsHandlerRegistryGenerator : IIncrementalGenerator ImmutableArray.Empty); } + /// + /// 创建一个数组类型引用。 + /// public static RuntimeTypeReferenceSpec FromArray(RuntimeTypeReferenceSpec elementTypeReference, int arrayRank) { return new RuntimeTypeReferenceSpec(null, null, null, elementTypeReference, arrayRank, null, null, ImmutableArray.Empty); } + /// + /// 创建一个指针类型引用。 + /// public static RuntimeTypeReferenceSpec FromPointer(RuntimeTypeReferenceSpec pointedAtTypeReference) { return new RuntimeTypeReferenceSpec(null, null, null, null, 0, pointedAtTypeReference, null, ImmutableArray.Empty); } + /// + /// 创建一个封闭泛型类型引用。 + /// public static RuntimeTypeReferenceSpec FromConstructedGeneric( RuntimeTypeReferenceSpec genericTypeDefinitionReference, ImmutableArray genericTypeArguments) diff --git a/GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs b/GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs index 1bef8ef0..21db7821 100644 --- a/GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs +++ b/GFramework.Cqrs/Internal/CqrsHandlerRegistrar.cs @@ -651,32 +651,70 @@ internal static class CqrsHandlerRegistrar } } + /// + /// 描述某个程序集在生成注册器之后仍需运行时补扫的 handler 元数据。 + /// + /// + /// 该对象把“是否存在精确 fallback 类型列表”与“是否只能回退到整程序集扫描”收敛为同一份内部状态, + /// 供注册流水线后续阶段统一判断。 + /// private sealed class ReflectionFallbackMetadata(IReadOnlyList types) { + /// + /// 获取需要通过运行时反射补充注册的 handler 类型集合。 + /// public IReadOnlyList Types { get; } = types ?? throw new ArgumentNullException(nameof(types)); + /// + /// 获取当前是否持有精确的 fallback 类型清单。 + /// public bool HasExplicitTypes => Types.Count > 0; } + /// + /// 描述单个程序集在注册阶段提取到的 generated registry 与 reflection fallback 元数据。 + /// private sealed class AssemblyRegistrationMetadata( IReadOnlyList registryTypes, ReflectionFallbackMetadata? reflectionFallbackMetadata) { + /// + /// 获取程序集上声明的 generated registry 类型集合。 + /// public IReadOnlyList RegistryTypes { get; } = registryTypes ?? throw new ArgumentNullException(nameof(registryTypes)); + /// + /// 获取该程序集是否还要求运行时补充 reflection fallback。 + /// public ReflectionFallbackMetadata? ReflectionFallbackMetadata { get; } = reflectionFallbackMetadata; } + /// + /// 缓存 generated registry 激活所需的类型判定结果与工厂委托。 + /// + /// + /// 该缓存把“是否实现契约”“是否为抽象类型”“是否已构建激活委托”封装为不可变快照, + /// 避免对同一 registry 类型重复执行反射分析。 + /// private sealed class RegistryActivationMetadata( bool implementsRegistryContract, bool isAbstract, Func? factory) { + /// + /// 获取目标类型是否实现了 。 + /// public bool ImplementsRegistryContract { get; } = implementsRegistryContract; + /// + /// 获取目标类型是否为抽象类型。 + /// public bool IsAbstract { get; } = isAbstract; + /// + /// 获取可用于实例化 registry 的工厂委托。 + /// public Func? Factory { get; } = factory; } } diff --git a/GFramework.Ecs.Arch.Abstractions/README.md b/GFramework.Ecs.Arch.Abstractions/README.md new file mode 100644 index 00000000..758868b9 --- /dev/null +++ b/GFramework.Ecs.Arch.Abstractions/README.md @@ -0,0 +1,103 @@ +# GFramework.Ecs.Arch.Abstractions + +`GFramework.Ecs.Arch.Abstractions` 承载 Arch ECS 集成层的最小契约,用来让共享业务层、宿主循环或扩展模块在不依赖 +`GFramework.Ecs.Arch` 默认实现的前提下,仍然可以约定 ECS 模块边界。 + +如果你需要的是 `UseArch(...)` 扩展、`ArchSystemAdapter` 基类、`World` 注册和默认模块实现,请改为依赖 +`GFramework.Ecs.Arch`。 + +## 包定位 + +- 这是 `Ecs.Arch` 的契约层,不是默认实现层。 +- 适合让上层模块只面向 `IArchEcsModule`、`IArchSystemAdapter` 和 `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` | 已覆盖 | 外部模块怎样只依赖更新接口而不绑定默认实现 | +| 配置对象 | `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` 等默认基类 +- 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) diff --git a/GFramework.Ecs.Arch/README.md b/GFramework.Ecs.Arch/README.md index 96501af6..9d78666e 100644 --- a/GFramework.Ecs.Arch/README.md +++ b/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` 系统桥接到同一条采用路径中。 +如果你需要的只是共享契约,请改为依赖 `GFramework.Ecs.Arch.Abstractions`。 -- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式 -- 🔌 **零依赖** - 不使用时,Core 包无 Arch 依赖 -- 🎯 **类型安全** - 完整的类型系统和编译时检查 -- ⚡ **高性能** - 基于 Arch ECS 的高性能实现 -- 🔧 **易扩展** - 简单的系统适配器模式 +## 包定位 -## 快速开始 +- 这是运行时实现层,不是纯契约层。 +- 适合需要 `UseArch(...)`、`World` 自动注册、默认模块生命周期和系统桥接基类的项目。 +- 常见场景: + - 在架构实例上显式接入 Arch ECS + - 让 `World` 由默认模块创建并放入容器 + - 让 ECS 系统复用 `ArchSystemAdapter` 生命周期桥接 + - 通过 `IArchEcsModule.Update(deltaTime)` 统一驱动 ECS 帧更新 + +## 与相邻包的关系 + +- `GFramework.Core` + - 提供架构、容器、生命周期和系统注册基础设施。 +- `GFramework.Ecs.Arch.Abstractions` + - 提供 `IArchEcsModule`、`IArchSystemAdapter` 和契约层 `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(); + } +} -```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 { @@ -78,115 +82,57 @@ public sealed class MovementSystem : ArchSystemAdapter 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(); - } -} +using Arch.Core; +using GFramework.Ecs.Arch.Abstractions; + +var world = architecture.Context.GetService(); +var ecsModule = architecture.Context.GetService(); ``` -### 7. 创建实体 +### 5. 由宿主循环驱动更新 ```csharp -var world = this.GetService(); -var entity = world.Create( - new Position(0, 0), - new Velocity(1, 1) -); -``` - -### 8. 更新系统 - -```csharp -var ecsModule = this.GetService(); ecsModule.Update(deltaTime); ``` -## 配置选项 +## 运行时职责地图 -### 代码配置 +| 文件 | 作用 | +| --- | --- | +| `Extensions/ArchExtensions.cs` | 通过 `UseArch(...)` 把默认模块注册到 `ArchitectureModuleRegistry` | +| `ArchEcsModule.cs` | 创建并注册 `World`,按优先级收集 `ArchSystemAdapter`,负责初始化、销毁和逐帧更新 | +| `ArchSystemAdapter.cs` | 把 GFramework 系统生命周期桥接到 Arch `ISystem` 生命周期 | +| `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` | 已覆盖 | `OnArchInitialize`、`OnUpdate`、`OnArchDispose` | +| 示例类型 | `Position`、`Velocity`、`MovementSystem` | 已覆盖 | 组件布局、查询写法、最小示例 | -## 架构说明 +## 对应文档入口 -### 显式注册模式 - -本包采用 .NET 生态标准的显式注册模式,基于架构实例: - -**优点:** - -- ✅ 符合 .NET 生态习惯 -- ✅ 显式、可控 -- ✅ 易于测试和调试 -- ✅ 支持配置 -- ✅ 支持链式调用 -- ✅ 避免"魔法"行为 - -**使用方式:** -```csharp -// 在架构初始化时添加 -var architecture = new GameArchitecture(config) - .UseArch(); // 显式注册 - -architecture.Initialize(); -``` - -详见:[INTEGRATION_PATTERN.md](INTEGRATION_PATTERN.md) - -### 系统适配器 - -`ArchSystemAdapter` 桥接 Arch.System.ISystem 到 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) diff --git a/GFramework.Game.Abstractions/README.md b/GFramework.Game.Abstractions/README.md index 91fa5f32..d69c7c10 100644 --- a/GFramework.Game.Abstractions/README.md +++ b/GFramework.Game.Abstractions/README.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`、`ConfigLoadException` | 看配置表注册、读取约定和失败诊断模型 | +| `Data/` | `14/14` 个类型声明已带 XML 注释 | `IDataRepository`、`ISettingsDataRepository`、`ISaveRepository`、`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`、`UiLayer`、`SceneTransitionType` | 看公共路由上下文、存储角色、资源注册表与跨层共享枚举 | + ## 最小接入路径 ### 1. 只想在公共业务层声明游戏对象 diff --git a/GFramework.Game.SourceGenerators/README.md b/GFramework.Game.SourceGenerators/README.md index 050c4d16..c12a3607 100644 --- a/GFramework.Game.SourceGenerators/README.md +++ b/GFramework.Game.SourceGenerators/README.md @@ -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 diff --git a/GFramework.Game/README.md b/GFramework.Game/README.md index 60336e82..b4e8b8c2 100644 --- a/GFramework.Game/README.md +++ b/GFramework.Game/README.md @@ -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`、`UnifiedSettingsDataRepository`、`FileStorage`、`JsonSerializer` | 看持久化布局、槽位存档、统一设置文件和底层序列化 / 存储实现 | +| `Setting/` | `9/9` 个类型声明已带 XML 注释 | `SettingsModel`、`SettingsSystem`、`SettingsAppliedEvent` | 看初始化、应用、保存、重置等设置生命周期编排 | +| `Scene/` `UI/` `Routing/` | `10/10` 个类型声明已带 XML 注释 | `SceneRouterBase`、`UiRouterBase`、`SceneTransitionPipeline`、`UiTransitionPipeline`、`RouterBase` | 看路由基类、转换处理器和项目层需要自己提供的 factory / root 边界 | +| `Extensions/` `Internal/` `State/` | `3/3` 个类型声明已带 XML 注释 | `DataLocationExtensions`、`VersionedMigrationRunner`、`GameStateMachineSystem` | 看辅助扩展、内部迁移执行逻辑和游戏态状态机封装 | + ## 最小接入路径 下面按最常见的四种接入目标给出最短路径。 diff --git a/README.md b/README.md index 2c4f8634..af805a2f 100644 --- a/README.md +++ b/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/ ``` diff --git a/ai-plan/public/README.md b/ai-plan/public/README.md index fdae3d71..f5efae2b 100644 --- a/ai-plan/public/README.md +++ b/ai-plan/public/README.md @@ -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 栏目刷新阶段已完成,后续仅作为历史恢复材料保留。 diff --git a/ai-plan/public/documentation-governance-and-refresh/archive/todos/documentation-governance-and-refresh-history-through-2026-04-18.md b/ai-plan/public/archive/documentation-governance-and-refresh/archive/todos/documentation-governance-and-refresh-history-through-2026-04-18.md similarity index 100% rename from ai-plan/public/documentation-governance-and-refresh/archive/todos/documentation-governance-and-refresh-history-through-2026-04-18.md rename to ai-plan/public/archive/documentation-governance-and-refresh/archive/todos/documentation-governance-and-refresh-history-through-2026-04-18.md diff --git a/ai-plan/public/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md b/ai-plan/public/archive/documentation-governance-and-refresh/archive/todos/documentation-governance-and-refresh-history-through-2026-04-22.md similarity index 100% rename from ai-plan/public/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md rename to ai-plan/public/archive/documentation-governance-and-refresh/archive/todos/documentation-governance-and-refresh-history-through-2026-04-22.md diff --git a/ai-plan/public/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-history-through-2026-04-18.md b/ai-plan/public/archive/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-history-through-2026-04-18.md similarity index 100% rename from ai-plan/public/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-history-through-2026-04-18.md rename to ai-plan/public/archive/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-history-through-2026-04-18.md diff --git a/ai-plan/public/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md b/ai-plan/public/archive/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-history-through-2026-04-22.md similarity index 100% rename from ai-plan/public/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md rename to ai-plan/public/archive/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-history-through-2026-04-22.md diff --git a/ai-plan/public/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-rp-001-through-rp-008.md b/ai-plan/public/archive/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-rp-001-through-rp-008.md similarity index 100% rename from ai-plan/public/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-rp-001-through-rp-008.md rename to ai-plan/public/archive/documentation-governance-and-refresh/archive/traces/documentation-governance-and-refresh-rp-001-through-rp-008.md diff --git a/ai-plan/public/archive/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md b/ai-plan/public/archive/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md new file mode 100644 index 00000000..7ccc9ba0 --- /dev/null +++ b/ai-plan/public/archive/documentation-governance-and-refresh/todos/documentation-governance-and-refresh-tracking.md @@ -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 映射 diff --git a/ai-plan/public/archive/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md b/ai-plan/public/archive/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md new file mode 100644 index 00000000..3709cc23 --- /dev/null +++ b/ai-plan/public/archive/documentation-governance-and-refresh/traces/documentation-governance-and-refresh-trace.md @@ -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/` 读取归档材料 diff --git a/ai-plan/public/documentation-full-coverage-governance/archive/todos/documentation-full-coverage-governance-validation-history-through-rp-007.md b/ai-plan/public/documentation-full-coverage-governance/archive/todos/documentation-full-coverage-governance-validation-history-through-rp-007.md new file mode 100644 index 00000000..3a955053 --- /dev/null +++ b/ai-plan/public/documentation-full-coverage-governance/archive/todos/documentation-full-coverage-governance-validation-history-through-rp-007.md @@ -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,无构建失败 diff --git a/ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md b/ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md new file mode 100644 index 00000000..157f7b91 --- /dev/null +++ b/ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md @@ -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 恢复 diff --git a/ai-plan/public/documentation-full-coverage-governance/traces/documentation-full-coverage-governance-trace.md b/ai-plan/public/documentation-full-coverage-governance/traces/documentation-full-coverage-governance-trace.md new file mode 100644 index 00000000..220b0133 --- /dev/null +++ b/ai-plan/public/documentation-full-coverage-governance/traces/documentation-full-coverage-governance-trace.md @@ -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` 波次在补齐基线后转入巡检,不继续在本轮展开成员级 ```` / ```` 审计 +- 下一恢复点切换到 `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 是否收敛 diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 431f22f1..b8aeaf5a 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -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' } ] } ], diff --git a/docs/zh-CN/abstractions/core-abstractions.md b/docs/zh-CN/abstractions/core-abstractions.md index 4a139d74..24a922ab 100644 --- a/docs/zh-CN/abstractions/core-abstractions.md +++ b/docs/zh-CN/abstractions/core-abstractions.md @@ -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() where T : IModel; - T GetSystem() where T : ISystem; - T GetUtility() 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 where TEvent : IEvent -{ - void Handle(TEvent @event); -} -``` - -## 命令查询接口 - -### ICommand - -命令接口: - -```csharp -public interface ICommand -{ - void Execute(); -} -``` - -### IQuery - -查询接口: - -```csharp -public interface IQuery -{ - TResult Execute(); -} -``` - -## 依赖注入接口 - -### IIocContainer - -IoC 容器接口: - -```csharp -public interface IIocContainer -{ - void Register() where TImplementation : TInterface; - void Register(TInterface instance); - TInterface Resolve(); - bool IsRegistered(); -} -``` - -## 生命周期接口 - -### 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`、`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`、`KeyValueRegistryBase` | 看初始化 / 销毁阶段和注册表抽象边界 | +| `Command/` `Query/` `Cqrs/` | `10/10` 个类型声明已带 XML 注释 | `ICommandExecutor`、`IAsyncCommand`、`IQueryExecutor`、`ICqrsRuntime` | 看旧命令 / 查询接口与新请求模型之间的兼容和迁移边界 | +| `Events/` `Property/` | `10/10` 个类型声明已带 XML 注释 | `IEventBus`、`IEventFilter`、`IBindableProperty`、`IReadonlyBindableProperty` | 看事件传播、过滤、解绑对象和属性订阅语义 | +| `State/` `StateManagement/` | `15/15` 个类型声明已带 XML 注释 | `IStateMachine`、`IAsyncState`、`IStore`、`IStoreMiddleware` | 看状态机契约与 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`、`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) diff --git a/docs/zh-CN/abstractions/ecs-arch-abstractions.md b/docs/zh-CN/abstractions/ecs-arch-abstractions.md new file mode 100644 index 00000000..c477d310 --- /dev/null +++ b/docs/zh-CN/abstractions/ecs-arch-abstractions.md @@ -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` | 让 ECS 系统适配到 `ISystem` 生命周期 | +| `ArchOptions` | 承载 `WorldCapacity`、`EnableStatistics`、`Priority` 等配置 | + +## 类型族级 XML Inventory + +| 类型族 | 代表类型 | XML 状态 | 阅读重点 | +| --- | --- | --- | --- | +| 模块契约 | `IArchEcsModule` | 已覆盖 | 统一更新入口、宿主循环边界 | +| 系统契约 | `IArchSystemAdapter` | 已覆盖 | 只依赖更新接口而不绑定默认 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` 基类 +- 访问 Arch `World` 与查询 API +- 使用默认的模块装配和生命周期实现 + +## 阅读顺序 + +1. 先读本页,确认你是否真的只需要契约层 +2. 如果需要默认实现,再看 [`../ecs/arch.md`](../ecs/arch.md) +3. 回到对应模块 README: + - `GFramework.Ecs.Arch.Abstractions/README.md` + - `GFramework.Ecs.Arch/README.md` diff --git a/docs/zh-CN/abstractions/game-abstractions.md b/docs/zh-CN/abstractions/game-abstractions.md index bb854ca2..196557e0 100644 --- a/docs/zh-CN/abstractions/game-abstractions.md +++ b/docs/zh-CN/abstractions/game-abstractions.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 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() where TScene : IScene; - Task SwitchSceneAsync() where TScene : IScene; - - void PushScene() 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` 这类契约 +- 你要让多个程序集共享 `ISettingsData`、`IData`、`ISceneEnterParam`、`IUiPageEnterParam` 等数据和路由上下文 +- 你需要自己实现 factory、root、存储或配置加载器,但不想把默认运行时一起带进来 + +## 包关系 + +- 契约层:`GFramework.Game.Abstractions` +- 运行时实现:`GFramework.Game` +- 底层基础契约:`GFramework.Core.Abstractions` + +## 契约地图 + +| 契约族 | 作用 | +| --- | --- | +| `Config/` | `IConfigLoader`、`IConfigRegistry`、`IConfigTable` 和配置失败诊断模型 | +| `Data/` | `IData`、`IVersionedData`、`IDataRepository`、`ISettingsDataRepository`、`ISaveRepository` 及数据事件 | +| `Setting/` | `ISettingsData`、`ISettingsModel`、`ISettingsSystem`、设置迁移契约与内置设置数据类型 | +| `Scene/` | `IScene`、`ISceneRouter`、`ISceneFactory`、`ISceneRoot`、转场处理器与事件 | +| `UI/` | `IUiPage`、`IUiRouter`、`IUiFactory`、`IUiRoot`、交互配置与 UI 转场选项 | +| `Routing/` | `IRoute`、`IRouteContext`、`IRouteGuard`,作为 Scene / UI 共享的路由基础约定 | +| `Storage/` `Asset/` `Enums/` | 文件存储角色、资源注册表,以及转场 / UI 层级 / 输入动作等跨层枚举 | + +## XML 覆盖基线 + +下面这份 inventory 记录的是 `2026-04-23` 对 `GFramework.Game.Abstractions` 做的一轮轻量 XML 盘点结果:只统计公开 / +内部类型声明是否带 XML 注释,用来建立契约层阅读入口;成员级参数、返回值、异常和生命周期说明仍需要后续 API 波次继续细化。 + +| 契约族 | 基线状态 | 代表类型 | 阅读重点 | +| --- | --- | --- | --- | +| `Config/` | `7/7` 个类型声明已带 XML 注释 | `IConfigLoader`、`IConfigRegistry`、`IConfigTable`、`ConfigLoadException` | 看配置表注册、只读访问和失败诊断边界 | +| `Data/` | `14/14` 个类型声明已带 XML 注释 | `IDataRepository`、`ISettingsDataRepository`、`ISaveRepository`、`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`、`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 _saveRepository; + private readonly ISceneRouter _sceneRouter; + + public ContinueGameCommandHandler( + ISaveRepository saveRepository, + ISceneRouter sceneRouter) + { + _saveRepository = saveRepository; + _sceneRouter = sceneRouter; + } +} +``` + +### 3. 什么时候切到运行时包 + +下面这些需求都属于 `GFramework.Game` 的职责,而不是本包: + +- 使用默认的 `JsonSerializer`、`FileStorage` 或 `ScopedStorage` +- 使用 `SettingsModel`、`SettingsSystem`、`SaveRepository` 等默认实现 +- 使用 `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` diff --git a/docs/zh-CN/abstractions/index.md b/docs/zh-CN/abstractions/index.md index 38f9f7bc..4e1efc0c 100644 --- a/docs/zh-CN/abstractions/index.md +++ b/docs/zh-CN/abstractions/index.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` 为主。 \ No newline at end of file +- 抽象层页面会解释接口分组与职责;实际安装与接入路径,仍应以运行时模块 README 与 `getting-started` 为主。 + +## 当前边界 + +- `GFramework.Core.SourceGenerators.Abstractions` +- `GFramework.Godot.SourceGenerators.Abstractions` +- `GFramework.SourceGenerators.Common` + +这些目录当前不作为独立抽象接口栏目维护,而是作为源码生成器家族的内部支撑模块,分别跟随所属模块 README 和 +`source-generators` 栏目维护。 diff --git a/docs/zh-CN/api-reference/index.md b/docs/zh-CN/api-reference/index.md index 394ed10a..14ea32b8 100644 --- a/docs/zh-CN/api-reference/index.md +++ b/docs/zh-CN/api-reference/index.md @@ -1,571 +1,81 @@ -# API 参考文档 - -本文档提供 GFramework 各模块的完整 API 参考。 - -## 核心命名空间 - -### GFramework.Core.architecture - -核心架构命名空间,包含所有基础组件。 - -#### 主要类型 - -| 类型 | 说明 | -|--------------------|--------| -| `Architecture` | 应用架构基类 | -| `AbstractModel` | 数据模型基类 | -| `AbstractSystem` | 业务系统基类 | -| `AbstractCommand` | 命令基类 | -| `AbstractQuery` | 查询基类 | -| `IController` | 控制器接口 | -| `IUtility` | 工具类接口 | - -### GFramework.Core.events - -事件系统命名空间。 - -#### 主要类型 - -| 类型 | 说明 | -|-------------------|----------| -| `IEvent` | 事件接口 | -| `IEventSystem` | 事件系统接口 | -| `TypeEventSystem` | 类型安全事件系统 | - -### GFramework.Core.property - -属性系统命名空间。 - -#### 主要类型 - -| 类型 | 说明 | -|-----------------------|--------| -| `BindableProperty` | 可绑定属性 | -| `IUnRegister` | 注销接口 | -| `IUnRegisterList` | 注销列表接口 | - -### GFramework.Core.ioc - -IoC 容器命名空间。 - -#### 主要类型 - -| 类型 | 说明 | -|--------------|------| -| `IContainer` | 容器接口 | -| `Container` | 容器实现 | - -### GFramework.Core.pool - -对象池命名空间。 - -#### 主要类型 - -| 类型 | 说明 | -|------------------|-------| -| `IObjectPool` | 对象池接口 | -| `ObjectPool` | 对象池实现 | - -### 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 model) where T : IModel; - - // 获取模型 - public T GetModel() where T : IModel; - - // 注册系统 - public void RegisterSystem(T system) where T : ISystem; - - // 获取系统 - public T GetSystem() where T : ISystem; - - // 注册工具 - public void RegisterUtility(T utility) where T : IUtility; - - // 获取工具 - public T GetUt>() where T : IUtility; - - // 发送命令 - public void SendCommand(T command) where T : ICommand; - - // 发送查询 - public TResult SendQuery(TQuery query) - where TQuery : IQuery; - - // 发送事件 - public void SendEvent(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 e) where T : IEvent; - - // 获取模型 - protected T GetModel() where T : IModel; - - // 获取系统 - protected T GetSystem() where T : ISystem; - - // 获取工具 - protected T GetUtility() 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 e) where T : IEvent; - - // 注册事件 - protected IUnRegister RegisterEvent(Action onEvent) - where T : IEvent; - - // 获取模型 - protected T GetModel() where T : IModel; - - // 获取系统 - protected T GetSystem() where T : ISystem; - - // 获取工具 - protected T GetUtility() where T : IUtility; -} -``` - -### AbstractCommand - -```csharp -public abstract class AbstractCommand : IBelongToArchitecture -{ - // 执行命令 - public void Execute(); - - // 命令实现 - protected abstract void OnDo(); - - // 获取架构 - public IArchitecture GetArchitecture(); - - // 发送事件 - protected void SendEvent(T e) where T : IEvent; - - // 获取模型 - protected T GetModel() where T : IModel; - - // 获取系统 - protected T GetSystem() where T : ISystem; - - // 获取工具 - protected T GetUtility() where T : IUtility; -} -``` - -### AbstractQuery`` - -```csharp -public abstract class AbstractQuery : IBelongToArchitecture -{ - // 执行查询 - public T Do(); - - // 查询实现 - protected abstract T OnDo(); - - // 获取架构 - public IArchitecture GetArchitecture(); - - // 获取模型 - protected T GetModel() where T : IModel; - - // 获取系统 - protected T GetSystem() where T : ISystem; - - // 获取工具 - protected T GetUtility() where T : IUtility; -} -``` - -### BindableProperty`` - -```csharp -public class BindableProperty -{ - // 构造函数 - public BindableProperty(T initialValue = default); - - // 获取或设置值 - public T Value { get; set; } - - // 注册监听器 - public IUnRegister Register(Action onValueChanged); - - // 注册监听器(包含初始值) - public IUnRegister RegisterWithInitValue(Action onValueChanged); - - // 获取当前值 - public T GetValue(); - - // 设置值 - public void SetValue(T newValue); -} -``` - -### ILocalizationManager - -```csharp -public interface ILocalizationManager : ISystem -{ - // 获取当前语言代码 - string CurrentLanguage { get; } - - // 获取当前文化信息 - CultureInfo CurrentCulture { get; } - - // 获取可用语言列表 - IReadOnlyList 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 callback); - - // 取消订阅语言变化事件 - void UnsubscribeFromLanguageChange(Action 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(this IBelongToArchitecture self, T command) - where T : ICommand; - -// 发送查询 -public static TResult SendQuery( - this IBelongToArchitecture self, TQuery query) - where TQuery : IQuery; - -// 发送事件 -public static void SendEvent(this IBelongToArchitecture self, T e) - where T : IEvent; - -// 获取模型 -public static T GetModel(this IBelongToArchitecture self) - where T : IModel; - -// 获取系统 -public static T GetSystem(this IBelongToArchitecture self) - where T : ISystem; - -// 获取工具 -public static T GetUtility(this IBelongToArchitecture self) - where T : IUtility; - -// 注册事件 -public static IUnRegister RegisterEvent( - this IBelongToArchitecture self, Action 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(); - this.SendEvent(new AttackEvent { Damage = Damage }); - } -} - -// 使用 -arch.SendCommand(new AttackCommand { Damage = 10 }); -``` - -### 发送查询 - -```csharp -public class GetPlayerHealthQuery : AbstractQuery -{ - protected override int OnDo() - { - return this.GetModel().Health.Value; - } -} - -// 使用 -var health = arch.SendQuery(new GetPlayerHealthQuery()); -``` - -### 监听事件 - -```csharp -public class PlayerSystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(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 文档出现冲突时,以源码和测试所反映的当前实现为准。 diff --git a/docs/zh-CN/core/cqrs.md b/docs/zh-CN/core/cqrs.md index 8d9158ec..28653d22 100644 --- a/docs/zh-CN/core/cqrs.md +++ b/docs/zh-CN/core/cqrs.md @@ -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` -也就是说,新代码通常不需要再分别设计“命令总线”“查询总线”和另一套通知分发语义。 +新代码通常不需要再分别设计“命令总线”“查询总线”和另一套通知分发语义。 -## 注册处理器 +## 处理器注册与生成器协作 在标准 `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>(); - 审计 - 重试或统一异常封装 -旧的 `Mediator` 兼容别名入口已经移除;当前公开入口只有 `RegisterCqrsPipelineBehavior()`。 +当前公开入口只有 `RegisterCqrsPipelineBehavior()`。 ## 和旧 Command / Query 的关系 @@ -157,15 +162,28 @@ RegisterCqrsPipelineBehavior>(); - 新路径 - `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`、`QueryBase`、`NotificationBase`、`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` diff --git a/docs/zh-CN/core/index.md b/docs/zh-CN/core/index.md index d8a600a6..d712b50b 100644 --- a/docs/zh-CN/core/index.md +++ b/docs/zh-CN/core/index.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 注释,用来确认阅读入口和治理优先级;成员级 ````、````、异常语义与线程说明仍需要继续细审。 + +| 类型族 | 基线状态 | 代表类型 | 阅读重点 | +| --- | --- | --- | --- | +| `Architectures/` | `16/16` 个类型声明已带 XML 注释 | `Architecture`、`ArchitectureContext`、`ArchitectureLifecycle`、`ArchitecturePhaseCoordinator` | 看架构启动、模块安装、阶段切换和上下文暴露边界 | +| `Services/` | `6/6` 个类型声明已带 XML 注释 | `ServiceModuleManager`、`CommandExecutorModule`、`CqrsRuntimeModule` | 看服务模块的注册顺序、销毁语义和默认接线 | +| `Command/` `Query/` | `15/15` 个类型声明已带 XML 注释 | `CommandExecutor`、`AsyncQueryExecutor`、`AbstractCommand`、`AbstractQuery` | 看旧入口兼容面与向 `CQRS` 迁移时还保留了哪些执行契约 | +| `Events/` `Property/` | `19/19` 个类型声明已带 XML 注释 | `EventBus`、`EnhancedEventBus`、`BindableProperty`、`OrEvent` | 看事件传播、解绑约束和可绑定属性的订阅语义 | +| `State/` `StateManagement/` | `10/10` 个类型声明已带 XML 注释 | `StateMachine`、`StateMachineSystem`、`Store`、`StoreBuilder` | 看状态切换、selector / middleware / dispatch 的单向流边界 | +| `Coroutine/` `Time/` `Pause/` `Concurrency/` | `43/43` 个类型声明已带 XML 注释 | `CoroutineScheduler`、`CoroutineHandle`、`WaitForSecondsRealtime`、`PauseStackManager`、`AsyncKeyLockManager` | 看调度阶段、等待指令、时间源和暂停 / 锁的线程语义 | +| `Resource/` `Pool/` | `8/8` 个类型声明已带 XML 注释 | `ResourceManager`、`AutoReleaseStrategy`、`ManualReleaseStrategy`、`AbstractObjectPoolSystem` | 看资源句柄释放策略与对象池复用约束 | +| `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` | 看默认基类、上下文感知 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` diff --git a/docs/zh-CN/ecs/arch.md b/docs/zh-CN/ecs/arch.md index e84c8adb..47fd2e95 100644 --- a/docs/zh-CN/ecs/arch.md +++ b/docs/zh-CN/ecs/arch.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` +- 使用仓库自带的 `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(); } } -// 初始化架构 -var architecture = new GameArchitecture(); +var architecture = new GameArchitecture() + .UseArch(options => + { + options.WorldCapacity = 2048; + options.Priority = 50; + }); + architecture.Initialize(); ``` -### 2. 带配置的注册 +### 3. 用 `ArchSystemAdapter` 编写系统 -```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` 在 `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; - -/// -/// 移动系统 - 更新实体位置 -/// public sealed class MovementSystem : ArchSystemAdapter { private QueryDescription _query; protected override void OnArchInitialize() { - // 创建查询:查找所有同时拥有 Position 和 Velocity 组件的实体 _query = new QueryDescription() .WithAll(); } 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(); - } -} -``` - -### 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(); - - // 创建实体 - 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(); - } - - public void Update(float deltaTime) - { - // 更新所有 ECS 系统 - _ecsModule.Update(deltaTime); - } -} +var world = architecture.Context.GetService(); +var ecsModule = architecture.Context.GetService(); ``` -## 配置选项 - -### ArchOptions +### 5. 由宿主循环显式调用 `Update` ```csharp -public sealed class ArchOptions -{ - /// - /// World 初始容量(默认:1000) - /// - public int WorldCapacity { get; set; } = 1000; - - /// - /// 是否启用统计信息(默认:false) - /// - public bool EnableStatistics { get; set; } = false; - - /// - /// 模块优先级(默认:50) - /// - 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`,负责初始化、销毁和逐帧更新 | `GFramework.Ecs.Arch/ArchEcsModule.cs` | +| `ArchSystemAdapter` | 从 GFramework 系统生命周期桥接到 Arch `ISystem` 生命周期 | `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` | 已覆盖 | `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(entity)) -{ - // 获取组件引用(零 GC 分配) - ref var pos = ref world.Get(entity); - pos.X += 10; -} - -// 设置组件(替换现有值) -world.Set(entity, new Position(100, 100)); - -// 移除组件 -world.Remove(entity); -``` - -### System(系统) - -系统包含游戏逻辑,处理具有特定组件组合的实体: - -```csharp -public sealed class DamageSystem : ArchSystemAdapter -{ - private QueryDescription _query; - - protected override void OnArchInitialize() - { - // 初始化查询 - _query = new QueryDescription() - .WithAll(); - } - - 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(entity); - } - }); - } -} -``` - -### World(世界) - -World 是 ECS 的核心容器,管理所有实体和组件: - -```csharp -// World 由 ArchEcsModule 自动创建和注册 -var world = this.GetService(); - -// 获取实体数量 -var entityCount = world.Size; - -// 清空所有实体 -world.Clear(); -``` - -## 系统适配器 - -### ArchSystemAdapter<T> - -`ArchSystemAdapter<T>` 桥接 Arch.System.ISystem<T> 到 GFramework 架构: - -```csharp -public sealed class MySystem : ArchSystemAdapter -{ - // 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 -{ - 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(); - World.Query(in query, (ref Position pos) => - { - // 处理逻辑 - }); - } -} -``` - -### 访问框架服务 - -`ArchSystemAdapter<T>` 继承自 `AbstractSystem`,可以使用所有 GFramework 的扩展方法: - -```csharp -public sealed class ServiceAccessSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - // 获取 Model - var playerModel = this.GetModel(); - - // 获取 Utility - var timeUtility = this.GetUtility(); - - // 发送命令 - this.SendCommand(new SaveGameCommand()); - - // 发送查询 - var score = this.SendQuery(new GetScoreQuery()); - - // 发送事件 - this.SendEvent(new GameOverEvent()); - } -} -``` - -## 查询实体 - -### 基本查询 - -```csharp -// 查询:必须有 Position 和 Velocity -var query = new QueryDescription() - .WithAll(); - -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() - .WithNone(); - -World.Query(in query, (ref Health health) => -{ - // 只处理没有受伤的实体 -}); -``` - -### 可选组件查询 - -```csharp -// 查询:必须有 Position,可选 Velocity -var query = new QueryDescription() - .WithAll() - .WithAny(); - -World.Query(in query, (Entity entity, ref Position pos) => -{ - // 处理逻辑 -}); -``` - -### 访问实体 ID - -```csharp -var query = new QueryDescription().WithAll(); - -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 -{ - // ... -} - -[Priority(20)] // 中优先级 -public sealed class MovementSystem : ArchSystemAdapter -{ - // ... -} - -[Priority(30)] // 低优先级,后执行 -public sealed class RenderSystem : ArchSystemAdapter -{ - // ... -} -``` - -执行顺序: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 -{ - // ✅ 推荐:缓存查询 - private QueryDescription _cachedQuery; - - protected override void OnArchInitialize() - { - _cachedQuery = new QueryDescription() - .WithAll(); - } - - 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() - .WithNone(); -``` - -### 4. 与传统架构结合 - -```csharp -// ECS 系统可以访问 Model -public class EnemySpawnSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - var gameState = this.GetModel(); - - // 根据关卡生成敌人 - 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(entity)) -{ - World.Add(entity, new FastTag()); -} - -// 动态移除组件 -if (pos.X < 0 && World.Has(entity)) -{ - World.Remove(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(); - 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) \ No newline at end of file +- 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) diff --git a/docs/zh-CN/ecs/index.md b/docs/zh-CN/ecs/index.md index d0f6602c..b2b7e332 100644 --- a/docs/zh-CN/ecs/index.md +++ b/docs/zh-CN/ecs/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`、`ArchExtensions.UseArch(...)`、示例组件与系统 | [`arch.md`](./arch.md) | +| `GFramework.Ecs.Arch.Abstractions` | 只想让共享宿主循环、测试替身或扩展模块依赖最小契约,而不引入默认运行时 | `IArchEcsModule`、`IArchSystemAdapter`、`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(); } } + +var architecture = new GameArchitecture() + .UseArch(options => + { + options.WorldCapacity = 2048; + options.Priority = 50; + }); + +architecture.Initialize(); + +var world = architecture.Context.GetService(); +var ecsModule = architecture.Context.GetService(); ``` -### 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` ```csharp using Arch.Core; using GFramework.Ecs.Arch; +using GFramework.Ecs.Arch.Components; public sealed class MovementSystem : ArchSystemAdapter { @@ -145,147 +77,60 @@ public sealed class MovementSystem : ArchSystemAdapter 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(); +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` | 已覆盖 | GFramework `ISystem` 生命周期如何桥接到 Arch `ISystem` | +| `GFramework.Ecs.Arch` | 示例组件与系统 | `Position`、`Velocity`、`MovementSystem` | 已覆盖 | 查询写法、组件布局、最小可运行示例 | +| `GFramework.Ecs.Arch.Abstractions` | 契约与配置对象 | `IArchEcsModule`、`IArchSystemAdapter`、`ArchOptions` | 已覆盖 | 共享宿主循环、测试替身、跨程序集配置边界 | -**优势**: +## 边界说明 -- 清晰的依赖关系 -- 更好的 IDE 支持 -- 易于测试和调试 -- 符合 .NET 生态习惯 - -### 零依赖原则 - -如果你不使用 ECS,GFramework.Core 包不会引入任何 ECS 相关的依赖: - -```xml - - - - - - - - - - -``` - -### 模块化设计 - -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 -{ - protected override void OnUpdate(in float deltaTime) - { - // 访问 Model - var gameState = this.GetModel(); - - // 根据关卡生成敌人 - 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(OnEnemyDestroyed); - } - - private void OnEnemyDestroyed(EnemyDestroyedEvent e) - { - var gameState = this.GetModel(); - 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 继续承担包目录入口职责。 diff --git a/docs/zh-CN/game/index.md b/docs/zh-CN/game/index.md index 59a00443..4857a76c 100644 --- a/docs/zh-CN/game/index.md +++ b/docs/zh-CN/game/index.md @@ -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`、`SceneRouterBase`、`UiRouterBase` | 先看运行时默认实现、配置加载、设置编排和路由基类 | +| `GFramework.Game.Abstractions` | `80/80` 个类型声明已带 XML 注释 | `IConfigRegistry`、`ISaveRepository`、`ISettingsSystem`、`ISceneRouter`、`IUiRouter` | 再看契约层边界,决定项目哪些程序集只依赖接口 | +| `GFramework.Game.SourceGenerators` | `2/2` 个类型声明已带 XML 注释 | `SchemaConfigGenerator`、`ConfigSchemaDiagnostics` | 最后看 schema 生成入口与诊断模型,确认配置系统的编译期链路 | + ## 与真实接法的关系 这个栏目以源码、`*.csproj`、模块 `README.md` 与 `ai-libs/` 下已验证的参考接法为准。 diff --git a/docs/zh-CN/source-generators/cqrs-handler-registry-generator.md b/docs/zh-CN/source-generators/cqrs-handler-registry-generator.md new file mode 100644 index 00000000..c30d3869 --- /dev/null +++ b/docs/zh-CN/source-generators/cqrs-handler-registry-generator.md @@ -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 + + + + + +``` + +运行时侧仍然按 `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) diff --git a/docs/zh-CN/source-generators/index.md b/docs/zh-CN/source-generators/index.md index cb07dba2..279762e2 100644 --- a/docs/zh-CN/source-generators/index.md +++ b/docs/zh-CN/source-generators/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 专用生成器