diff --git a/CHANGELOG.md b/CHANGELOG.md index d1caec74c..dd7d378b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,6 +133,10 @@ * TcpConnectionProvider 单条 TCP 长连接改为按 endpoint 连接池(P0-A#3 / C239):每 endpoint 独立成池(默认上限 4 条,构造参数可调),并发需求驱动懒建(顺序调用保持单连接复用,并发调用按需扩展),轮询分发;连接级故障仅精准移除该连接(`IConnectionProvider.Invalidate(Stream)`/`ITransportProtocolAdapter.Invalidate(Stream)` 增量接口),不再全量断连。顺带修复旧实现隐藏缺陷:全进程单连接槽位在多 endpoint 交替调用时每次断连重连 * 连接死亡快速失败(P0-A#2#3 / C239):接收泵退出时经新增 `IRequestResponseMatcher.TryFail` 立即以 IOException 失败该连接上全部挂起请求(等待方收到可重试的 ConnectionFailed 而非干等超时),连接级异常(IO/Socket)仅失效当前连接、其余异常保守全量失效;新增本地化键 `RemoteMessaging.Client.ConnectionClosed` * 新增 `RemoteMessageClientConcurrencyTests`(3 用例):屏障式假服务端证明并发请求不再全局串行(旧实现必然全体超时)且扇出多连接;连接读后即断场景验证快速失败 + 池仅移除死亡连接后重建成功;双服务交替调用验证按 endpoint 连接复用(各 1 条连接,旧实现每次断连重连) + +### Documentation + +* 全仓禁用 ``(C301,GFX-1013):55 个 `.cs` 文件 151 处 `/// `(含 2 处 `cref` 形态)替换为描述实现自身行为的完整双语 XML 文档注释(`` 中文、`` 英文,`` / `` / `` / `` 用 `中文 / English`),覆盖 Capability 能力模块与 Options、Analyzers、Launcher 宿主适配、Templates 模板与测试替身;comment-hygiene 规范新增禁用条款。仅改 `///` 注释行,代码与行为零变更 ## [1.13.7] - 2026-08-05 ### Bug Fixes diff --git a/Capability/GameFrameX.Capability.Online.Abstractions/Contracts/OnlineAdminApiAdapters.cs b/Capability/GameFrameX.Capability.Online.Abstractions/Contracts/OnlineAdminApiAdapters.cs index c74d2edc0..d84e36526 100644 --- a/Capability/GameFrameX.Capability.Online.Abstractions/Contracts/OnlineAdminApiAdapters.cs +++ b/Capability/GameFrameX.Capability.Online.Abstractions/Contracts/OnlineAdminApiAdapters.cs @@ -130,7 +130,16 @@ internal static AdminApiErrorCode ToErrorCode(OnlineErrorCode code) /// private sealed class ScopeAdapter : IAdminApiScopeAdapter { - /// + /// + /// 从请求中读取声明的租户、应用、服务器三元素作用域;三者均可读取时组装为机制管道作用域并返回 true,否则输出 null 并返回 false。 + /// + /// + /// Reads the claimed tenant / app / server triple from the request; when all three are readable it builds an + /// and returns true, otherwise outputs null and returns false. + /// + /// 管理 API 请求 / Admin API request + /// 读取成功时为声明作用域,失败时为 null / Claimed scope on success, null on failure + /// 是否成功读取声明作用域 / Whether the claimed scope was read successfully public bool TryReadClaimedScope(AdminApiRequest request, out AdminApiClaimedScope claimedScope) { if (request.TryReadClaimedScope(out var tenantId, out var appId, out var serverId)) @@ -143,7 +152,16 @@ public bool TryReadClaimedScope(AdminApiRequest request, out AdminApiClaimedScop return false; } - /// + /// + /// 将声明作用域与授权作用域转换为 Online 作用域后交由 比对;越权时返回映射后的机制管道错误码,通过时返回 null。 + /// + /// + /// Converts both scopes to Online scopes and compares them via ; returns the mapped + /// pipeline error code when access is denied, or null when the claimed scope is within the authorized scope. + /// + /// 请求声明的作用域 / Scope claimed by the request + /// 调用方被授权的作用域 / Scope the caller is authorized for + /// 拒绝时的错误码;通过时为 null / Error code when denied; null when allowed public AdminApiErrorCode ValidateClaimed(AdminApiClaimedScope claimed, AdminApiClaimedScope authorized) { var denied = OnlineScopeGuard.Validate(ToOnlineScope(claimed), ToOnlineScope(authorized)); @@ -170,7 +188,18 @@ public IdempotencyAdapter(OnlineIdempotencyService idempotency) _idempotency = idempotency ?? throw new ArgumentNullException(nameof(idempotency)); } - /// + /// + /// 将作用域转换为 Online 作用域后委托 Online 幂等服务开始幂等登记,并把结果种类、可执行标志、错误码(无错误时为 null)与首次响应副本映射为机制管道幂等结果。 + /// + /// + /// Delegates to the Online idempotency service after converting the scope, then maps the outcome kind, can-execute + /// flag, error code (null when none) and a copy of the first response into the pipeline idempotency outcome. + /// + /// 幂等记录所属作用域 / Scope owning the idempotency record + /// 幂等键 / Idempotency key + /// 规范化请求文本,用于比对重放请求是否一致 / Canonical request text used to detect mismatched replays + /// 是否将幂等记录绑定到玩家维度 / Whether the record is bound to the player dimension + /// 机制管道幂等登记结果 / Pipeline idempotency outcome public async Task BeginAsync(AdminApiClaimedScope scope, string idempotencyKey, string canonicalRequestText, bool bindPlayer) { var outcome = await _idempotency.BeginAsync(ToOnlineScope(scope), idempotencyKey, canonicalRequestText, bindPlayer).ConfigureAwait(false); @@ -178,13 +207,32 @@ public async Task BeginAsync(AdminApiClaimedScope scope return new AdminIdempotencyOutcome(kind, outcome.CanExecute, outcome.ErrorCode == OnlineErrorCode.None ? null : ToErrorCode(outcome.ErrorCode), outcome.FirstResponse.ToArray()); } - /// + /// + /// 将作用域转换为 Online 作用域后委托 Online 幂等服务把幂等记录标记为完成并保存首次响应。 + /// + /// + /// Converts the scope and delegates to the Online idempotency service to mark the record completed and store the first response. + /// + /// 幂等记录所属作用域 / Scope owning the idempotency record + /// 幂等键 / Idempotency key + /// 首次执行的响应内容 / Response produced by the first execution + /// 是否将幂等记录绑定到玩家维度 / Whether the record is bound to the player dimension + /// 表示异步操作的任务 / Task representing the asynchronous operation public Task CompleteAsync(AdminApiClaimedScope scope, string idempotencyKey, byte[] firstResponse, bool bindPlayer) { return _idempotency.CompleteAsync(ToOnlineScope(scope), idempotencyKey, firstResponse, bindPlayer); } - /// + /// + /// 将作用域转换为 Online 作用域后委托 Online 幂等服务把幂等记录标记为失败,以便后续请求重新执行。 + /// + /// + /// Converts the scope and delegates to the Online idempotency service to mark the record failed so later requests can execute again. + /// + /// 幂等记录所属作用域 / Scope owning the idempotency record + /// 幂等键 / Idempotency key + /// 是否将幂等记录绑定到玩家维度 / Whether the record is bound to the player dimension + /// 表示异步操作的任务 / Task representing the asynchronous operation public Task FailAsync(AdminApiClaimedScope scope, string idempotencyKey, bool bindPlayer) { return _idempotency.FailAsync(ToOnlineScope(scope), idempotencyKey, bindPlayer); diff --git a/Capability/GameFrameX.Capability.Online.Assets/OnlineAssetsCapabilityModule.cs b/Capability/GameFrameX.Capability.Online.Assets/OnlineAssetsCapabilityModule.cs index b272ed529..30d0b93a8 100644 --- a/Capability/GameFrameX.Capability.Online.Assets/OnlineAssetsCapabilityModule.cs +++ b/Capability/GameFrameX.Capability.Online.Assets/OnlineAssetsCapabilityModule.cs @@ -95,13 +95,27 @@ public sealed class OnlineAssetsCapabilityModule : ICapabilityModule, IAdminActi /// private IOnlineAuditReader _audit; - /// + /// + /// 获取资产能力清单,固定返回静态实例 。 + /// + /// + /// Gets the assets capability manifest; always returns the static . + /// + /// 资产能力清单 / Assets capability manifest public CapabilityManifest Manifest { get { return ManifestInstance; } } - /// + /// + /// 懒默认注册内存版资产存储与资产交易存储并解析实际生效实例,解析审计读面、幂等服务与事件发布器,构造资产查询服务与统一发放服务并注册回共享服务面。 + /// + /// + /// Registers in-memory asset and asset-transaction stores as lazy defaults (overridable by the host), resolves the + /// effective stores plus the audit reader, idempotency service and event publisher, then builds the + /// and and registers them back into the shared services. + /// + /// 能力注册上下文 / Capability registration context public void Register(CapabilityRegistrationContext context) { // 两 store:懒默认注册后经共享面取用(族 / 宿主 GameDb Override 自动胜出)。 @@ -120,19 +134,42 @@ public void Register(CapabilityRegistrationContext context) context.AddService(_grantService); } - /// + /// + /// 激活阶段无需处理:所有服务已在注册阶段构造完毕,本能力不持有需启动的后台任务或桥接,直接返回已完成任务。 + /// + /// + /// Nothing to do on activation: every service is built during registration and the capability owns no background work + /// or bridges to start, so a completed task is returned. + /// + /// 能力激活上下文 / Capability activation context + /// 取消令牌 / Cancellation token + /// 已完成的任务 / Completed task public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 停用阶段无需处理:激活时未启动任何资源,因此没有需要释放或撤销的内容,直接返回已完成任务。 + /// + /// + /// Nothing to do on deactivation: activation starts no resources, so there is nothing to release or revoke. + /// + /// 取消令牌 / Cancellation token + /// 已完成的任务 / Completed task public Task DeactivateAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 使用注册阶段得到的发放服务、查询服务、审计读面与交易存储构造资产管理处理器,并登记发放、撤销、钱包账本、资产审计与交易详情等管理动作。 + /// + /// + /// Builds from the grant service, query service, audit reader and transaction store + /// resolved during registration, and registers the grant / revoke / wallet-ledger / asset-audit / transaction-detail admin actions. + /// + /// 管理动作注册表 / Admin action registry public void RegisterAdminActions(AdminActionRegistry registry) { new OnlineAdminAssetHandlers(_grantService, _assetQuery, _audit, _assetTransactionStore).Register(registry); diff --git a/Capability/GameFrameX.Capability.Online.Competition/OnlineCompetitionCapabilityModule.cs b/Capability/GameFrameX.Capability.Online.Competition/OnlineCompetitionCapabilityModule.cs index 0e27c8809..54587807c 100644 --- a/Capability/GameFrameX.Capability.Online.Competition/OnlineCompetitionCapabilityModule.cs +++ b/Capability/GameFrameX.Capability.Online.Competition/OnlineCompetitionCapabilityModule.cs @@ -96,13 +96,30 @@ public sealed class OnlineCompetitionCapabilityModule : ICapabilityModule, IAdmi /// private string _projectionBoardId; - /// + /// + /// 获取竞技能力清单,固定返回静态实例 。 + /// + /// + /// Gets the competition capability manifest; always returns the static . + /// + /// 竞技能力清单 / Competition capability manifest public CapabilityManifest Manifest { get { return ManifestInstance; } } - /// + /// + /// 读取竞技能力选项,懒默认注册内存版排行榜、赛季、锦标赛存储并解析生效实例,构造并注册排行榜服务与活动运营注册表;发放服务在场时再注册赛季服务与锦标赛服务;投影榜单标识非空白且对局结果存储在场时,注册 Match.Settled 排行榜投影器、订阅对局结算事件并添加投影重试的 tick 任务。 + /// + /// + /// Reads , registers in-memory leaderboard / season / tournament stores as lazy + /// defaults and resolves the effective instances, then builds and registers the leaderboard service and the live-ops + /// registry. Season and tournament services are registered only when the optional grant service is present. When the + /// projection board id is not blank and the match result store is present, it registers the Match.Settled leaderboard + /// projector, subscribes it to the match-settled event and adds the leaderboard-projection-retry tick job; + /// otherwise the projection is silently skipped. + /// + /// 能力注册上下文 / Capability registration context public void Register(CapabilityRegistrationContext context) { var options = context.GetOptions(); @@ -147,7 +164,18 @@ public void Register(CapabilityRegistrationContext context) } } - /// + /// + /// 投影榜单标识为空白时直接返回;否则以 Top 1 查询探测目标榜单,已存在则返回,返回资源不存在时按累加计分、降序排序创建该榜单。 + /// + /// + /// Returns immediately when the projection board id is blank. Otherwise probes the target board with a top-1 query; + /// if it already exists nothing else happens, and if the probe reports resource-not-found the board is created with + /// the sum score-update policy and descending sort order. Any other failure aborts activation so the host can roll back. + /// + /// 能力激活上下文,用于解析 Online 作用域 / Capability activation context used to resolve the Online scope + /// 取消令牌 / Cancellation token + /// 表示异步激活操作的任务 / Task representing the asynchronous activation + /// 探测返回资源不存在以外的失败码,或创建榜单失败 / The probe fails with a code other than resource-not-found, or creating the board fails public async Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(_projectionBoardId)) @@ -182,13 +210,28 @@ public async Task ActivateAsync(CapabilityActivationContext context, Cancellatio } } - /// + /// + /// 停用阶段无需处理:事件订阅与 tick 任务由宿主机制在注册时托管,激活仅预建榜单而不持有运行资源,直接返回已完成任务。 + /// + /// + /// Nothing to do on deactivation: the event subscription and tick job are declared to the host during registration, + /// and activation only pre-creates the board without holding runtime resources, so a completed task is returned. + /// + /// 取消令牌 / Cancellation token + /// 已完成的任务 / Completed task public Task DeactivateAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 基于注册阶段构造的活动运营注册表登记活动运营管理动作,并基于排行榜服务登记排行榜查询管理动作。 + /// + /// + /// Registers the live-ops admin actions backed by the live-ops registry and the leaderboard query admin actions backed + /// by the leaderboard service, both built during registration. + /// + /// 管理动作注册表 / Admin action registry public void RegisterAdminActions(AdminActionRegistry registry) { OnlineAdminLiveOpsHandlers.RegisterLiveOps(registry, _liveOps); diff --git a/Capability/GameFrameX.Capability.Online.Competition/OnlineCompetitionOptions.cs b/Capability/GameFrameX.Capability.Online.Competition/OnlineCompetitionOptions.cs index 9911d224b..f548b97a9 100644 --- a/Capability/GameFrameX.Capability.Online.Competition/OnlineCompetitionOptions.cs +++ b/Capability/GameFrameX.Capability.Online.Competition/OnlineCompetitionOptions.cs @@ -49,7 +49,15 @@ public sealed class OnlineCompetitionOptions : ICapabilityOptions /// public OnlineLeaderboardProjectionOptions LeaderboardProjection { get; set; } = new OnlineLeaderboardProjectionOptions(); - /// + /// + /// 校验排行榜组件选项:单次提交最大分数、限流最大提交次数、限流窗口秒数、缓存有效期秒数与最大分页大小均须为正数;投影配置不做校验(空白榜单标识表示不投影)。 + /// + /// + /// Validates the leaderboard options: default maximum score per submission, rate-limit maximum submissions, rate-limit window + /// seconds, cache time-to-live seconds and maximum page size must all be positive. The projection settings are not validated because + /// a blank board id simply disables the projection. Failures are recorded on the validation collector. + /// + /// 选项校验结果收集器 / Options validation collector public void Validate(CapabilityOptionsValidation validation) { validation.RequirePositive("Leaderboard.DefaultMaxScorePerSubmission", Leaderboard.DefaultMaxScorePerSubmission); diff --git a/Capability/GameFrameX.Capability.Online.Foundation/OnlineAuthorizedScopeProvider.cs b/Capability/GameFrameX.Capability.Online.Foundation/OnlineAuthorizedScopeProvider.cs index 94afdebb5..321f9d66b 100644 --- a/Capability/GameFrameX.Capability.Online.Foundation/OnlineAuthorizedScopeProvider.cs +++ b/Capability/GameFrameX.Capability.Online.Foundation/OnlineAuthorizedScopeProvider.cs @@ -54,7 +54,13 @@ public OnlineAuthorizedScopeProvider(OnlineScope authorizedScope) _authorizedScope = authorizedScope ?? throw new ArgumentNullException(nameof(authorizedScope)); } - /// + /// + /// 获取构造时注入的族基建预置授权作用域,只透出不构造。 + /// + /// + /// Gets the family-provisioned authorized scope injected at construction; the provider only exposes it and never builds a default. + /// + /// 授权作用域,恒不为 null / Authorized scope, never null public OnlineScope AuthorizedScope { get { return _authorizedScope; } diff --git a/Capability/GameFrameX.Capability.Online.Foundation/OnlineFoundationCapabilityModule.cs b/Capability/GameFrameX.Capability.Online.Foundation/OnlineFoundationCapabilityModule.cs index 89b8d3cd0..3032dd616 100644 --- a/Capability/GameFrameX.Capability.Online.Foundation/OnlineFoundationCapabilityModule.cs +++ b/Capability/GameFrameX.Capability.Online.Foundation/OnlineFoundationCapabilityModule.cs @@ -98,13 +98,29 @@ public sealed class OnlineFoundationCapabilityModule : ICapabilityModule, IAdmin /// private OnlinePresenceService _presence; - /// + /// + /// 获取平台地基能力清单,固定返回静态实例 。 + /// + /// + /// Gets the foundation capability manifest; always returns the static . + /// + /// 平台地基能力清单 / Foundation capability manifest public CapabilityManifest Manifest { get { return ManifestInstance; } } - /// + /// + /// 懒默认注册内存版身份、在线状态、会话存储并解析生效实例,构造并注册身份服务、会话生命周期管理器、会话令牌服务与在线状态服务,注册会话恢复契约实现及社交、队伍两个在线探针,并添加在线超时、令牌过期、重连窗口三个清扫 tick 任务。 + /// + /// + /// Registers in-memory identity, presence and session stores as lazy defaults and resolves the effective instances, + /// builds and registers the identity service, session manager, session token service and presence service, registers + /// the session reconnect contract implementation plus the social and party presence probes, and adds the + /// presence-timeout-sweep, session-token-expiry-sweep and session-reconnect-window-sweep tick jobs. + /// The presence sweep uses the tenant and app of the family-provisioned scope resolved here. + /// + /// 能力注册上下文 / Capability registration context public void Register(CapabilityRegistrationContext context) { var eventPublisher = context.GetService(); @@ -146,7 +162,17 @@ public void Register(CapabilityRegistrationContext context) context.AddTickJob("session-reconnect-window-sweep", ct => _sessions.SweepAsync(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), ct)); } - /// + /// + /// 发布两个桥:以族基建预置的作用域构造并发布授权作用域提供器,以及发布注册阶段注册的会话恢复契约实现;随后返回已完成任务。 + /// + /// + /// Publishes two bridges: an wrapping the family-provisioned + /// , and the session reconnect contract implementation registered during registration. + /// The work is synchronous, so a completed task is returned. + /// + /// 能力激活上下文,提供服务解析与桥发布 / Capability activation context providing services and bridges + /// 取消令牌 / Cancellation token + /// 已完成的任务 / Completed task public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { // 授权作用域桥:透出族基建预置的 OnlineScope 三元组(全宿主唯一发布者;Hotfix 侧 TryAcquire 失败即显式 8002)。 @@ -157,13 +183,27 @@ public Task ActivateAsync(CapabilityActivationContext context, CancellationToken return Task.CompletedTask; } - /// + /// + /// 停用阶段无需处理:本模块不持有自有资源,清扫任务由宿主机制托管,激活时发布的桥也由机制统一管理,直接返回已完成任务。 + /// + /// + /// Nothing to do on deactivation: the module holds no resources of its own, the sweep tick jobs are owned by the host + /// and the bridges published on activation are managed by the mechanism, so a completed task is returned. + /// + /// 取消令牌 / Cancellation token + /// 已完成的任务 / Completed task public Task DeactivateAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 基于注册阶段构造的在线状态服务登记玩家封禁与解封管理动作。 + /// + /// + /// Registers the suspend / resume player admin action backed by the presence service built during registration. + /// + /// 管理动作注册表 / Admin action registry public void RegisterAdminActions(AdminActionRegistry registry) { OnlineAdminFoundationHandlers.RegisterSuspendResume(registry, _presence); diff --git a/Capability/GameFrameX.Capability.Online.Foundation/OnlineFoundationOptions.cs b/Capability/GameFrameX.Capability.Online.Foundation/OnlineFoundationOptions.cs index ededd5dd5..a300dbf5a 100644 --- a/Capability/GameFrameX.Capability.Online.Foundation/OnlineFoundationOptions.cs +++ b/Capability/GameFrameX.Capability.Online.Foundation/OnlineFoundationOptions.cs @@ -54,7 +54,14 @@ public sealed class OnlineFoundationOptions : ICapabilityOptions /// public OnlinePlayerStorageOptions PlayerStorage { get; set; } = new OnlinePlayerStorageOptions(); - /// + /// + /// 校验玩家键值存储限制参数:最大负载字节数、单集合最大键数与最大分页大小均须为正数。 + /// + /// + /// Validates the player key-value storage limits: maximum payload bytes, maximum keys per collection and maximum page size must + /// all be positive. Failures are recorded on the validation collector. + /// + /// 选项校验结果收集器 / Options validation collector public void Validate(CapabilityOptionsValidation validation) { validation.RequirePositive("PlayerStorage.MaxPayloadBytes", PlayerStorage.MaxPayloadBytes); diff --git a/Capability/GameFrameX.Capability.Online.Foundation/Presence/OnlinePartyPresenceProbe.cs b/Capability/GameFrameX.Capability.Online.Foundation/Presence/OnlinePartyPresenceProbe.cs index 1a4579fec..32b9a72c2 100644 --- a/Capability/GameFrameX.Capability.Online.Foundation/Presence/OnlinePartyPresenceProbe.cs +++ b/Capability/GameFrameX.Capability.Online.Foundation/Presence/OnlinePartyPresenceProbe.cs @@ -60,7 +60,19 @@ public OnlinePartyPresenceProbe(OnlinePresenceService presence) _presence = presence ?? throw new ArgumentNullException(nameof(presence)); } - /// + /// + /// 判定队伍成员是否在线:以租户、应用与成员玩家构造作用域(服务器位为 0)查询在线状态事实源;查询成功且状态既非离线也非封禁时返回 true,查询失败一律按离线返回 false。 + /// + /// + /// Builds a scope from tenant, app and player (server id 0) and reads the presence service; returns true only when the + /// lookup succeeds and the state is neither nor . + /// A failed lookup is treated as offline. + /// + /// 租户标识 / Tenant id + /// 应用标识 / App id + /// 队伍成员玩家标识 / Party member player id + /// 取消令牌 / Cancellation token + /// 成员是否在线 / Whether the member is online public async Task IsOnlineAsync(long tenantId, long appId, long playerId, CancellationToken cancellationToken = default) { var scope = new OnlineScope(tenantId, appId, 0, playerId); diff --git a/Capability/GameFrameX.Capability.Online.Foundation/Presence/OnlineSocialPresenceProbe.cs b/Capability/GameFrameX.Capability.Online.Foundation/Presence/OnlineSocialPresenceProbe.cs index ac66eff13..dd781abfe 100644 --- a/Capability/GameFrameX.Capability.Online.Foundation/Presence/OnlineSocialPresenceProbe.cs +++ b/Capability/GameFrameX.Capability.Online.Foundation/Presence/OnlineSocialPresenceProbe.cs @@ -59,7 +59,19 @@ public OnlineSocialPresenceProbe(OnlinePresenceService presence) _presence = presence ?? throw new ArgumentNullException(nameof(presence)); } - /// + /// + /// 以租户、应用与玩家构造作用域(服务器位为 0)查询在线状态事实源;查询成功且状态既非离线也非封禁时返回 true,查询失败一律按离线返回 false。 + /// + /// + /// Builds a scope from tenant, app and player (server id 0) and reads the presence service; returns true only when the + /// lookup succeeds and the state is neither nor . + /// A failed lookup is treated as offline. + /// + /// 租户标识 / Tenant id + /// 应用标识 / App id + /// 玩家标识 / Player id + /// 取消令牌 / Cancellation token + /// 玩家是否在线 / Whether the player is online public async Task IsOnlineAsync(long tenantId, long appId, long playerId, CancellationToken cancellationToken = default) { var scope = new OnlineScope(tenantId, appId, 0, playerId); diff --git a/Capability/GameFrameX.Capability.Online.Foundation/Session/OnlineSessionReconnectService.cs b/Capability/GameFrameX.Capability.Online.Foundation/Session/OnlineSessionReconnectService.cs index d03775427..d7a96f4a1 100644 --- a/Capability/GameFrameX.Capability.Online.Foundation/Session/OnlineSessionReconnectService.cs +++ b/Capability/GameFrameX.Capability.Online.Foundation/Session/OnlineSessionReconnectService.cs @@ -76,7 +76,18 @@ public OnlineSessionReconnectService(OnlineSessionTokenService tokens, OnlineSes _tokenTimeToLiveSeconds = tokenTimeToLiveSeconds; } - /// + /// + /// 校验作用域与连接标识后,按最新登录胜出策略签发新会话令牌(顶替旧活跃会话),再把新会话标记为已连接到指定连接;任一步失败即返回该步失败码,成功返回令牌、会话标识与过期时间。 + /// + /// + /// Validates the scope and connection id, issues a session token with the latest-wins multi-device policy (kicking the + /// previous active session) using the configured token lifetime, then marks the new session connected on the given + /// connection. Any failing step returns its failure code; on success the token, session id and expiry are returned. + /// + /// 登录玩家所属作用域 / Scope of the logging-in player + /// 物理连接通道标识 / Physical connection id + /// 取消令牌 / Cancellation token + /// 登录凭据结果,失败时携带失败码 / Login credential result carrying the failure code on failure public async Task> IssueForLoginAsync(OnlineScope scope, string connectionId, CancellationToken cancellationToken = default) { var failure = ValidateScopeAndConnection(scope, connectionId); @@ -107,7 +118,20 @@ public async Task> IssueForLoginAsync }); } - /// + /// + /// 作用域为空、连接标识为空或令牌为空时返回参数非法;否则在恢复串行门内依次校验令牌、比对会话作用域、把会话切换到新连接并原子轮换令牌,任一步失败返回对应失败码,成功返回新令牌、玩家、会话标识与过期时间。 + /// + /// + /// Returns parameter-invalid when the scope, connection id or token is missing. Otherwise, inside the resume gate, it + /// validates the token, checks the session scope, moves the session to the new connection and atomically rotates the + /// token so the old fingerprint is invalidated; concurrent duplicate resumes therefore fail at validation. Any failing + /// step returns its code; on success the new token, player id, session id and expiry are returned. + /// + /// 恢复请求声明的作用域 / Scope claimed by the resume request + /// 待恢复会话的令牌 / Token of the session to resume + /// 新的物理连接通道标识 / New physical connection id + /// 取消令牌 / Cancellation token + /// 恢复凭据结果,失败时携带失败码 / Resume credential result carrying the failure code on failure public async Task> ResumeAsync(OnlineScope scope, string token, string connectionId, CancellationToken cancellationToken = default) { if (scope == null) @@ -170,7 +194,18 @@ public async Task> ResumeAsync(Onlin } } - /// + /// + /// 作用域为空、缺少玩家位或重连窗口非正数时返回参数非法;否则把该玩家所有活跃会话标记为断线并开启重连窗口,跳过状态未就绪或会话无效的会话,遇其它失败立即返回该结果,全部处理完返回 true。 + /// + /// + /// Returns parameter-invalid when the scope or player id is missing or the reconnect window is not positive. Otherwise + /// marks every active session of the player disconnected with the given reconnect window, skipping sessions that report + /// state-not-ready or session-invalid; any other failure is returned immediately, and true is returned when all are handled. + /// + /// 断线玩家所属作用域,须带玩家位 / Scope of the disconnected player, must carry a player id + /// 重连窗口秒数 / Reconnect window in seconds + /// 取消令牌 / Cancellation token + /// 处理结果,成功为 true / Operation result, true on success public async Task> NotifyPlayerDisconnectedAsync(OnlineScope scope, long reconnectWindowSeconds, CancellationToken cancellationToken = default) { if (scope == null || scope.PlayerId <= 0) diff --git a/Capability/GameFrameX.Capability.Online.Match/OnlineMatchCapabilityModule.cs b/Capability/GameFrameX.Capability.Online.Match/OnlineMatchCapabilityModule.cs index 21c7f2b73..d927a3a55 100644 --- a/Capability/GameFrameX.Capability.Online.Match/OnlineMatchCapabilityModule.cs +++ b/Capability/GameFrameX.Capability.Online.Match/OnlineMatchCapabilityModule.cs @@ -101,13 +101,29 @@ public sealed class OnlineMatchCapabilityModule : ICapabilityModule, IAdminActio /// private IOnlineMatchDomain _matchDomain; - /// + /// + /// 获取在线对局能力的静态清单(单例实例),声明能力标识、依赖与可选的撮合能力。 + /// + /// + /// Gets the static manifest singleton of the online match capability, declaring its identity, dependencies and the optional matchmaking capability. + /// + /// 能力清单单例 / Capability manifest singleton public CapabilityManifest Manifest { get { return ManifestInstance; } } - /// + /// + /// 注册对局能力:注册内存对局 Actor 存储与结果存储,构造对局运行时并注册石头剪刀布玩法与对局 tick 任务; + /// 装配结算服务与结算管线(资产发放服务缺席时只结算不派发)并注册结算 tick 任务;构造并注册对局桥服务; + /// 仅当票据服务、撮合协调器与票据存储均在场时才装配匹配域服务并订阅撮合分配事件,缺席时不装配也不报错。 + /// + /// + /// Registers in-memory match actor and result stores, builds the match runtime with the rock-paper-scissors game and a match tick job, + /// wires the settlement service and pipeline (settle-only when the grant service is absent) with a settlement tick job, registers the game bridge service, + /// and only when ticket service, matchmaker coordinator and ticket store are all present builds the match domain service and subscribes to assignment-created events; otherwise it silently skips. + /// + /// 能力注册上下文 / Capability registration context public void Register(CapabilityRegistrationContext context) { var options = context.GetOptions(); @@ -147,7 +163,15 @@ public void Register(CapabilityRegistrationContext context) } } - /// + /// + /// 激活对局能力:始终发布对局桥;仅当匹配域服务已在注册期装配时才发布匹配域桥。 + /// + /// + /// Always publishes the match game bridge; publishes the match domain bridge only when the domain service was assembled during registration. + /// + /// 能力激活上下文 / Capability activation context + /// 取消令牌 / Cancellation token + /// 已完成的任务,激活过程为同步操作 / A completed task, as activation is synchronous public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { // 桥发布迁 Activate 期(C294):对局桥恒发布;匹配域桥仅在场发布(缺席态由桥显式失败承载)。 @@ -160,13 +184,26 @@ public Task ActivateAsync(CapabilityActivationContext context, CancellationToken return Task.CompletedTask; } - /// + /// + /// 停用对局能力:本实现不做任何处理,因为桥与 tick 任务由宿主统一管理,模块自身不持有需要释放的资源。 + /// + /// + /// Performs no work, because bridges and tick jobs are owned by the host and the module holds no resources to release. + /// + /// 取消令牌 / Cancellation token + /// 已完成的任务 / A completed task public Task DeactivateAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 注册对局相关管理动作:异常结束对局,以及基于结算管线的对局结算查询。 + /// + /// + /// Registers match admin actions: abnormal match termination and match settlement query backed by the settlement pipeline. + /// + /// 管理动作注册表 / Admin action registry public void RegisterAdminActions(AdminActionRegistry registry) { OnlineAdminMatchHandlers.RegisterEndAbnormalMatch(registry); diff --git a/Capability/GameFrameX.Capability.Online.Match/OnlineMatchDomainService.cs b/Capability/GameFrameX.Capability.Online.Match/OnlineMatchDomainService.cs index 08e48486b..dd8b85022 100644 --- a/Capability/GameFrameX.Capability.Online.Match/OnlineMatchDomainService.cs +++ b/Capability/GameFrameX.Capability.Online.Match/OnlineMatchDomainService.cs @@ -104,7 +104,20 @@ public OnlineMatchDomainService(IOnlineMatchTicketStore store, OnlineMatchTicket _game = game ?? throw new ArgumentNullException(nameof(game)); } - /// + /// + /// 为玩家创建单人匹配票据:依次校验作用域、模式(仅允许 1 或 2)与评分(须大于 0),以默认区域和评分上下窗口建票; + /// 建票成功后同步执行一轮撮合,再按玩家最新票据解析已撮合的数值对局标识(未撮合时为 0)。 + /// + /// + /// Validates scope, mode (only 1 or 2) and rating (must be positive), enqueues a solo ticket in the default region with a rating window, + /// runs one immediate matchmaking pass, then resolves the numeric match id from the player's latest ticket (0 when not yet matched). + /// Invalid mode or rating fails with ParameterInvalid; ticket service failures are propagated. + /// + /// 玩家作用域 / Player scope + /// 匹配模式,仅允许 1 或 2 / Match mode, only 1 or 2 allowed + /// 玩家评分,须大于 0 / Player rating, must be positive + /// 取消令牌 / Cancellation token + /// 入队结果,成功时携带已撮合的对局标识(未撮合为 0) / Enqueue result carrying the matched id (0 if not matched) on success public async Task> EnqueueAsync(OnlineScope scope, int mode, int rating, CancellationToken cancellationToken = default) { var enqueueScopeFailure = ValidateScope(scope); @@ -145,7 +158,17 @@ public async Task> EnqueueAsync(OnlineSco return OnlineResult.Ok(new OnlineMatchDomainEnqueue { MatchId = matchId }); } - /// + /// + /// 取消玩家当前排队中的票据:校验作用域后查找活跃票据;无活跃票据时返回成功且 Cancelled = false,不视为失败; + /// 票据服务取消失败时透传失败码,成功时仅当票据状态变为已取消才标记已取消。 + /// + /// + /// Validates scope and looks up the active ticket; no active ticket yields a successful receipt with Cancelled = false. + /// Ticket service failures are propagated; Cancelled is true only when the ticket ends in the cancelled state. + /// + /// 玩家作用域 / Player scope + /// 取消令牌 / Cancellation token + /// 取消回执结果 / Cancel receipt result public async Task> CancelAsync(OnlineScope scope, CancellationToken cancellationToken = default) { var failureCode = ValidateScope(scope); @@ -173,7 +196,17 @@ public async Task> CancelAsync(OnlineScope }); } - /// + /// + /// 查询玩家匹配状态:校验作用域后读取最新票据;无票据返回未排队未撮合,票据排队中返回排队中, + /// 其余状态解析数值对局标识,非 0 即视为已撮合。 + /// + /// + /// Validates scope and reads the latest ticket: none means neither queuing nor matched, a queued ticket means queuing, + /// otherwise the numeric match id is resolved and a non-zero id means matched. + /// + /// 玩家作用域 / Player scope + /// 取消令牌 / Cancellation token + /// 匹配状态结果 / Match status result public async Task> GetStatusAsync(OnlineScope scope, CancellationToken cancellationToken = default) { var failureCode = ValidateScope(scope); @@ -202,7 +235,20 @@ public async Task> GetStatusAsync(OnlineSc }); } - /// + /// + /// 玩家进入已撮合对局:校验入场请求与分配登记后,按服务器标识派生运行时对局标识并获取或创建对局 Actor; + /// 对局已结束返回 StateEnded,成员表与分配成员不一致返回 ParameterInvalid; + /// 对局处于创建、等待或就绪状态时标记成员就绪并尝试开局;最终返回是否已进入运行状态及成员列表。 + /// + /// + /// Validates the entry and assignment registration, derives the runtime match id from the server id and gets or creates the match actor. + /// Ended matches fail with StateEnded, member mismatches fail with ParameterInvalid; in created, waiting or ready states members are marked ready and the match is started when possible. + /// Returns whether the match is running and the member list. + /// + /// 玩家作用域 / Player scope + /// 数值对局标识 / Numeric match id + /// 取消令牌 / Cancellation token + /// 入场结果 / Entry result public async Task> EnterAsync(OnlineScope scope, long matchId, CancellationToken cancellationToken = default) { var invalidEntry = ValidateEntry(scope, matchId, out var registration); @@ -249,7 +295,19 @@ public async Task> EnterAsync(OnlineScope s }); } - /// + /// + /// 将撮合分配标识解析为数值对局标识、模式与成员列表:分配标识为空返回 ParameterInvalid; + /// 优先使用内存登记,未登记时从票据存储读取分配并登记,分配不存在返回 ResourceNotFound。 + /// + /// + /// Resolves an assignment id to numeric match id, mode and players. Empty id fails with ParameterInvalid; + /// the in-memory registration is preferred, otherwise the assignment is loaded from the ticket store and registered; a missing assignment fails with ResourceNotFound. + /// + /// 租户标识 / Tenant id + /// 应用标识 / Application id + /// 撮合分配标识 / Matchmaking assignment id + /// 取消令牌 / Cancellation token + /// 分配解析结果 / Assignment resolution result public async Task> ResolveAssignmentAsync(long tenantId, long appId, string assignmentId, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(assignmentId)) @@ -277,7 +335,19 @@ public async Task> ResolveAssignmentAs }); } - /// + /// + /// 标记玩家在对局中掉线:校验作用域后按票据、分配登记与运行时成员表定位玩家所属对局; + /// 找不到对局、对局已结束或成员缺失、已离开、被踢出时返回成功且 Marked = false; + /// 否则经重连服务标记掉线(重连令牌留存在成员表、不下发),失败透传失败码。 + /// + /// + /// Validates scope and locates the player's match via ticket, assignment registration and runtime member table. + /// Returns success with Marked = false when no match is found, the match has ended, or the member is missing, left or kicked; + /// otherwise marks the disconnect via the reconnect service (the reconnect token stays server-side) and propagates its failure. + /// + /// 玩家作用域 / Player scope + /// 取消令牌 / Cancellation token + /// 掉线标记结果 / Disconnect marking result public async Task> NotifyPlayerDisconnectedAsync(OnlineScope scope, CancellationToken cancellationToken = default) { var scopeFailure = ValidateScope(scope); @@ -315,7 +385,21 @@ public async Task> NotifyPlayerDisconn return OnlineResult.Ok(new OnlineMatchDomainDisconnect { Marked = true, MatchId = numericMatchId }); } - /// + /// + /// 为重新登录的玩家恢复对局:校验作用域并定位所属对局,无对局时返回成功且 Resumed = false; + /// 成员缺失、已离开或被踢出返回 ScopeDenied,对局已结束返回 StateEnded; + /// 掉线成员用服务端留存的重连令牌经重连服务恢复,在线成员做幂等确认直接以当前快照作为恢复结果; + /// 返回对局状态、服务器序号、成员状态、玩法状态以及是否有增量可用。 + /// + /// + /// Validates scope and locates the match; none yields success with Resumed = false. Missing, left or kicked members fail with ScopeDenied, ended matches with StateEnded. + /// Disconnected members reconnect through the reconnect service using the server-held token; online members get an idempotent confirmation based on the current snapshot. + /// Returns match state, server sequence, member states, game state and whether a delta is available. + /// + /// 玩家作用域 / Player scope + /// 客户端最后确认的序号 / Last sequence acknowledged by the client + /// 取消令牌 / Cancellation token + /// 对局恢复结果 / Match resume result public async Task> TryResumeForPlayerAsync(OnlineScope scope, long lastAcknowledgedSequence, CancellationToken cancellationToken = default) { var scopeFailure = ValidateScope(scope); diff --git a/Capability/GameFrameX.Capability.Online.Match/OnlineMatchGameBridgeService.cs b/Capability/GameFrameX.Capability.Online.Match/OnlineMatchGameBridgeService.cs index 7373c43e1..84cafa677 100644 --- a/Capability/GameFrameX.Capability.Online.Match/OnlineMatchGameBridgeService.cs +++ b/Capability/GameFrameX.Capability.Online.Match/OnlineMatchGameBridgeService.cs @@ -73,7 +73,21 @@ public OnlineMatchGameBridgeService(OnlineMatchRuntime runtime, OnlineRockPaperS _game = game ?? throw new ArgumentNullException(nameof(game)); } - /// + /// + /// 为房间的某一局开局:校验作用域、房间标识、局号与成员数(须等于玩法最小人数)以及请求者成员身份; + /// 按服务器标识、房间与局号派生对局标识并获取或创建对局 Actor;对局已结束返回 StateEnded,成员表不一致返回 ParameterInvalid; + /// 处于创建、等待或就绪状态时准备成员并开局,最后返回对局视图。 + /// + /// + /// Validates scope, room id, round, player count (must equal the game minimum) and requester membership, derives the match id and gets or creates the actor. + /// Ended matches fail with StateEnded, member mismatches with ParameterInvalid; created, waiting or ready matches get members prepared and started. Returns the game view. + /// + /// 请求作用域 / Request scope + /// 房间标识 / Room id + /// 局号 / Round number + /// 房间成员表 / Room player ids + /// 取消令牌 / Cancellation token + /// 对局视图结果 / Game view result public async Task> StartRoomGameAsync(OnlineScope scope, long roomId, int round, IReadOnlyList playerIds, CancellationToken cancellationToken = default) { var invalidRequest = ValidateStartRequest(scope, roomId, round, playerIds); @@ -114,7 +128,20 @@ public async Task> StartRoomGameAsync(On return OnlineResult.Ok(BuildView(roomId, actor)); } - /// + /// + /// 提交石头剪刀布出拳:作用域缺失或无玩家标识返回 ScopeMissing,出拳越界返回 ParameterInvalid,对局不存在返回 ResourceNotFound; + /// 客户端序号由服务端按快照中该成员的最后序号加一派生;提交失败透传失败码,未返回确认返回 InternalError,被拒绝时映射拒绝原因,成功返回对局视图。 + /// + /// + /// Submits a rock-paper-scissors gesture. Missing scope fails with ScopeMissing, out-of-range gestures with ParameterInvalid, unknown matches with ResourceNotFound. + /// The client sequence is derived server-side from the member's last sequence plus one; submission failures are propagated, a missing ack yields InternalError, rejections are mapped, success returns the game view. + /// + /// 请求作用域 / Request scope + /// 房间标识 / Room id + /// 局号 / Round number + /// 出拳值 / Gesture value + /// 取消令牌 / Cancellation token + /// 对局视图结果 / Game view result public async Task> SubmitGestureAsync(OnlineScope scope, long roomId, int round, int gesture, CancellationToken cancellationToken = default) { if (scope == null || scope.PlayerId <= 0) @@ -174,7 +201,19 @@ public async Task> SubmitGestureAsync(On return OnlineResult.Ok(BuildView(roomId, actor)); } - /// + /// + /// 查询房间某一局的对局信息:作用域缺失返回 ScopeMissing,对局不存在返回 ResourceNotFound, + /// 查询者不是未离开、未被踢出的成员时返回 ScopeDenied,否则返回对局视图。 + /// + /// + /// Queries the game of a room round: missing scope fails with ScopeMissing, unknown matches with ResourceNotFound, + /// non-members (or left/kicked members) with ScopeDenied; otherwise returns the game view. + /// + /// 请求作用域 / Request scope + /// 房间标识 / Room id + /// 局号 / Round number + /// 取消令牌 / Cancellation token + /// 对局视图结果 / Game view result public async Task> GetGameInfoAsync(OnlineScope scope, long roomId, int round, CancellationToken cancellationToken = default) { if (scope == null || scope.PlayerId <= 0) diff --git a/Capability/GameFrameX.Capability.Online.Match/OnlineMatchOptions.cs b/Capability/GameFrameX.Capability.Online.Match/OnlineMatchOptions.cs index b52d403a5..18471f36f 100644 --- a/Capability/GameFrameX.Capability.Online.Match/OnlineMatchOptions.cs +++ b/Capability/GameFrameX.Capability.Online.Match/OnlineMatchOptions.cs @@ -52,7 +52,13 @@ public sealed class OnlineMatchOptions : ICapabilityOptions /// public OnlineMatchRuntimeOptions Runtime { get; set; } = new OnlineMatchRuntimeOptions(); - /// + /// + /// 校验合并后的运行时阈值:等待超时、进行中超时、重连窗口、结束留存时长与单局服务端事件上限均须为正数。 + /// + /// + /// Requires waiting timeout, running timeout, reconnect window, ended retention and maximum server events per match to be positive. + /// + /// 选项校验收集器 / Options validation collector public void Validate(CapabilityOptionsValidation validation) { validation.RequirePositive("Runtime.WaitingTimeoutSeconds", Runtime.WaitingTimeoutSeconds); diff --git a/Capability/GameFrameX.Capability.Online.Matchmaking/OnlineMatchmakingCapabilityModule.cs b/Capability/GameFrameX.Capability.Online.Matchmaking/OnlineMatchmakingCapabilityModule.cs index 5c9f1d385..4a488139e 100644 --- a/Capability/GameFrameX.Capability.Online.Matchmaking/OnlineMatchmakingCapabilityModule.cs +++ b/Capability/GameFrameX.Capability.Online.Matchmaking/OnlineMatchmakingCapabilityModule.cs @@ -98,13 +98,29 @@ public sealed class OnlineMatchmakingCapabilityModule : ICapabilityModule, IAdmi /// private OnlinePartyService _partyService; - /// + /// + /// 获取在线撮合能力的静态清单(单例实例)。 + /// + /// + /// Gets the static manifest singleton of the online matchmaking capability. + /// + /// 能力清单单例 / Capability manifest singleton public CapabilityManifest Manifest { get { return ManifestInstance; } } - /// + /// + /// 注册撮合能力:注册内存票据存储、对局列表存储与队伍存储,构造并注册票据服务、撮合协调器与队列观察器; + /// 构造队伍服务(在线探针暂留空,激活期回填)并以命名 party 注册为频道成员资格探针; + /// 注册撮合执行与过期票据清理两个 tick 任务。 + /// + /// + /// Registers in-memory ticket, listing and party stores, builds and registers the ticket service, matchmaker coordinator and queue observer, + /// builds the party service (presence probe attached later at activation) and registers it as the named party channel membership probe, + /// and adds the matchmaker run and expired ticket sweep tick jobs. + /// + /// 能力注册上下文 / Capability registration context public void Register(CapabilityRegistrationContext context) { var options = context.GetOptions(); @@ -142,7 +158,15 @@ public void Register(CapabilityRegistrationContext context) }); } - /// + /// + /// 激活撮合能力:枚举队伍在线探针扩展点,存在实现时将第一个回填到队伍服务;无实现则保持探针为空。 + /// + /// + /// Enumerates party presence probe implementations and attaches the first one to the party service; leaves it unset when none exist. + /// + /// 能力激活上下文 / Capability activation context + /// 取消令牌 / Cancellation token + /// 已完成的任务,激活过程为同步操作 / A completed task, as activation is synchronous public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { // 在线事实探针扩展点注入:实现常由非直接依赖能力(online-foundation)提供,只能 Activate 期枚举。 @@ -155,13 +179,26 @@ public Task ActivateAsync(CapabilityActivationContext context, CancellationToken return Task.CompletedTask; } - /// + /// + /// 停用撮合能力:本实现不做任何处理,因为存储为内存实现、tick 任务由宿主管理,模块不持有需要释放的资源。 + /// + /// + /// Performs no work, because stores are in-memory, tick jobs are host-managed and the module holds no resources to release. + /// + /// 取消令牌 / Cancellation token + /// 已完成的任务 / A completed task public Task DeactivateAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 注册撮合管理动作:基于队列观察器、票据存储与票据服务构造撮合管理处理器并注册到管理动作注册表。 + /// + /// + /// Registers matchmaking admin handlers built from the queue observer, ticket store and ticket service. + /// + /// 管理动作注册表 / Admin action registry public void RegisterAdminActions(AdminActionRegistry registry) { new OnlineAdminMatchmakingHandlers(_matchQueueObserver, _matchTicketStore, _matchTickets).Register(registry); diff --git a/Capability/GameFrameX.Capability.Online.Matchmaking/OnlineMatchmakingOptions.cs b/Capability/GameFrameX.Capability.Online.Matchmaking/OnlineMatchmakingOptions.cs index 96d3e2df9..12c6b681d 100644 --- a/Capability/GameFrameX.Capability.Online.Matchmaking/OnlineMatchmakingOptions.cs +++ b/Capability/GameFrameX.Capability.Online.Matchmaking/OnlineMatchmakingOptions.cs @@ -51,7 +51,13 @@ public sealed class OnlineMatchmakingOptions : ICapabilityOptions /// public OnlineMatchmakerOptions Matchmaker { get; set; } = new OnlineMatchmakerOptions(); - /// + /// + /// 校验合并后的撮合参数:票据存活时长、等待扩窗阈值、扩窗间隔、每次扩窗评分增量、频控最大操作数与频控窗口均须为正数。 + /// + /// + /// Requires ticket time to live, wait expansion threshold, expansion interval, skill expansion per interval, rate limit maximum operations and rate limit window to be positive. + /// + /// 选项校验收集器 / Options validation collector public void Validate(CapabilityOptionsValidation validation) { validation.RequirePositive("Matchmaker.TicketTimeToLiveSeconds", Matchmaker.TicketTimeToLiveSeconds); diff --git a/Capability/GameFrameX.Capability.Online.Operations/HotfixRollback/OnlineHotfixArtifactFetcher.cs b/Capability/GameFrameX.Capability.Online.Operations/HotfixRollback/OnlineHotfixArtifactFetcher.cs index 09334644c..a5ad98d21 100644 --- a/Capability/GameFrameX.Capability.Online.Operations/HotfixRollback/OnlineHotfixArtifactFetcher.cs +++ b/Capability/GameFrameX.Capability.Online.Operations/HotfixRollback/OnlineHotfixArtifactFetcher.cs @@ -85,7 +85,26 @@ public OnlineHotfixArtifactFetcher(OnlineHotfixArtifactFetchOptions options, Htt _httpClient = new HttpClient(handler ?? new SocketsHttpHandler(), true); } - /// + /// + /// 确保指定版本的热更制品已落盘到当前工作目录下的版本目录:先校验版本号、SHA-256 与下载地址格式; + /// 目标制品已存在时校验和一致即直接返回,不一致即拒绝(版本目录一经落盘不可变更); + /// 未落盘且未提供下载地址时抛出文件不存在异常;否则下载到同卷的临时目录(按配置重试并限制大小),校验通过后原子移动到版本目录, + /// 并发移动竞态时按已落盘内容判定幂等,最终总是清理临时目录。 + /// + /// + /// Validates the version, SHA-256 and source URL format. An existing artifact with a matching hash returns immediately; a mismatching one is rejected because version directories are immutable. + /// Without an on-disk artifact and without a source URL a file-not-found exception is thrown; otherwise the artifact is downloaded into a same-volume staging directory with retries and a size limit, + /// verified, and atomically moved into the version directory. Concurrent move races are resolved by re-checking the existing file, and the staging directory is always cleaned up. + /// + /// 热更版本号,禁止包含路径分隔符、卷分隔符或双点段 / Hotfix version, must not contain path or volume separators or double-dot segments + /// 制品下载地址,为空时仅校验已落盘制品 / Artifact source URL; when empty only the on-disk artifact is verified + /// 制品 SHA-256 校验和(64 位十六进制) / Artifact SHA-256 checksum (64 hexadecimal characters) + /// 取消令牌 / Cancellation token + /// 表示异步操作的任务 / A task representing the asynchronous operation + /// 版本号、校验和或下载地址格式非法 / The version, checksum or source URL is malformed + /// 已落盘制品或下载制品校验不一致,或制品超过大小上限 / The on-disk or downloaded artifact hash mismatches, or the artifact exceeds the size limit + /// 仅提供校验和但目标制品未落盘 / Only a checksum is provided but the artifact is not on disk + /// 下载返回不可重试的失败状态,或可重试失败在重试耗尽后仍未成功 / The download returns a non-retryable failure status, or a retryable failure persists after retries are exhausted public async Task EnsureArtifactAsync(string version, string sourceUrl, string artifactSha256, CancellationToken cancellationToken = default) { ValidateVersion(version); diff --git a/Capability/GameFrameX.Capability.Online.Operations/OnlineOperationsCapabilityModule.cs b/Capability/GameFrameX.Capability.Online.Operations/OnlineOperationsCapabilityModule.cs index e45c93217..d3ef57995 100644 --- a/Capability/GameFrameX.Capability.Online.Operations/OnlineOperationsCapabilityModule.cs +++ b/Capability/GameFrameX.Capability.Online.Operations/OnlineOperationsCapabilityModule.cs @@ -110,13 +110,29 @@ public sealed class OnlineOperationsCapabilityModule : ICapabilityModule, IAdmin /// private OnlineHotfixRollbackService _hotfixRollback; - /// + /// + /// 获取运营聚合能力的静态清单(单例实例)。 + /// + /// + /// Gets the static manifest singleton of the online operations capability. + /// + /// 能力清单单例 / Capability manifest singleton public CapabilityManifest Manifest { get { return ManifestInstance; } } - /// + /// + /// 注册运营能力:解析统一审计服务;注册内存热更版本存储,要求宿主提供版本切换执行器,按选项注册制品获取器并装配热更回滚服务; + /// 仅在撮合票据、队伍与对局 Actor 存储均在场时装配总览服务,仅在资产查询、社交关系存储与对局 Actor 存储均在场时装配玩家时间线服务; + /// 最后对全部已知在线事件主题注册事件与审计桥。 + /// + /// + /// Resolves the unified audit service, registers the in-memory hotfix version store, requires the host rollback executor, registers the artifact fetcher from options and builds the hotfix rollback service. + /// The overview service is built only when ticket, party and match actor stores exist; the player timeline only when asset query, social graph and match actor stores exist. + /// Finally subscribes the event and audit bridge to all known online event topics. + /// + /// 能力注册上下文 / Capability registration context public void Register(CapabilityRegistrationContext context) { var options = context.GetOptions(); @@ -158,19 +174,40 @@ public void Register(CapabilityRegistrationContext context) RegisterEventBridge(context); } - /// + /// + /// 激活运营能力:本实现不做任何处理,因为所有服务与事件订阅已在注册期完成装配,且本能力不发布桥。 + /// + /// + /// Performs no work, because all services and event subscriptions are wired during registration and this capability publishes no bridges. + /// + /// 能力激活上下文 / Capability activation context + /// 取消令牌 / Cancellation token + /// 已完成的任务 / A completed task public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 停用运营能力:本实现不做任何处理,因为事件订阅由机制事件总线管理,模块不持有需要释放的资源。 + /// + /// + /// Performs no work, because event subscriptions are owned by the mechanism event bus and the module holds no resources to release. + /// + /// 取消令牌 / Cancellation token + /// 已完成的任务 / A completed task public Task DeactivateAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 注册运营管理动作:控制台动作(总览、时间线与审计,未装配的服务以空值传入)与热更回滚动作。 + /// + /// + /// Registers console actions (overview, timeline and audit; unassembled services are passed as null) and hotfix rollback actions. + /// + /// 管理动作注册表 / Admin action registry public void RegisterAdminActions(AdminActionRegistry registry) { OnlineAdminConsoleHandlers.RegisterConsoleActions(registry, _overview, _timeline, _audit); diff --git a/Capability/GameFrameX.Capability.Online.Operations/OnlineOperationsOptions.cs b/Capability/GameFrameX.Capability.Online.Operations/OnlineOperationsOptions.cs index 1b6efa593..481ab5935 100644 --- a/Capability/GameFrameX.Capability.Online.Operations/OnlineOperationsOptions.cs +++ b/Capability/GameFrameX.Capability.Online.Operations/OnlineOperationsOptions.cs @@ -43,7 +43,13 @@ public sealed class OnlineOperationsOptions : ICapabilityOptions /// public OnlineHotfixArtifactFetchOptions ArtifactFetch { get; set; } = new OnlineHotfixArtifactFetchOptions(); - /// + /// + /// 校验制品获取参数:单次尝试超时须为正时长,最大重试次数不得为负,制品大小上限须为正数。 + /// + /// + /// Requires a positive attempt timeout, a non-negative maximum retry count and a positive maximum artifact size. + /// + /// 选项校验收集器 / Options validation collector public void Validate(CapabilityOptionsValidation validation) { if (ArtifactFetch.AttemptTimeout <= TimeSpan.Zero) diff --git a/Capability/GameFrameX.Capability.Online.Social/OnlineSocialCapabilityModule.cs b/Capability/GameFrameX.Capability.Online.Social/OnlineSocialCapabilityModule.cs index fe6311fe3..762f20a7c 100644 --- a/Capability/GameFrameX.Capability.Online.Social/OnlineSocialCapabilityModule.cs +++ b/Capability/GameFrameX.Capability.Online.Social/OnlineSocialCapabilityModule.cs @@ -145,13 +145,31 @@ public sealed class OnlineSocialCapabilityModule : ICapabilityModule, IAdminActi /// private OnlineScope _scope; - /// + /// + /// 获取在线社交能力的静态清单(单例实例)。 + /// + /// + /// Gets the static manifest singleton of the online social capability. + /// + /// 能力清单单例 / Capability manifest singleton public CapabilityManifest Manifest { get { return ManifestInstance; } } - /// + /// + /// 注册社交能力:解析作用域、会话存储与会话令牌服务;为聊天、好友、群组、通知、举报与社交关系注册内存默认存储; + /// 要求宿主提供玩家目录并装配好友服务,装配社交决策、处罚、通知、聊天审计投影服务; + /// 以默认放行策略声明聊天审核钩子并构造聊天服务(成员资格探针激活期注入);群组服务以命名 group 注册为频道成员资格探针; + /// 将社交决策服务注册为社交门控,并注册通知与好友请求的过期清理 tick 任务。 + /// + /// + /// Resolves scope, session store and session token service, registers in-memory default stores for chat, friends, groups, notifications, reports and the social graph, + /// requires the host player directory and builds friend, decision, punishment, notification and chat audit services, declares the chat moderation hook with an allow-all default + /// and builds the chat service (membership probes injected at activation), registers the group service as the named group membership probe, + /// exposes the decision service as the social gate and adds notification and friend request expiry sweep tick jobs. + /// + /// 能力注册上下文 / Capability registration context public void Register(CapabilityRegistrationContext context) { _options = context.GetOptions(); @@ -215,7 +233,17 @@ public void Register(CapabilityRegistrationContext context) }); } - /// + /// + /// 激活社交能力:发布好友域桥,向聊天服务注入全部已注册的频道成员资格探针; + /// 仅当好友选项开启旧数据迁移时,执行一次旧好友数据迁移。 + /// + /// + /// Publishes the friend domain bridge, attaches all registered channel membership probes to the chat service, + /// and runs the legacy friend data migration only when it is enabled in the friend options. + /// + /// 能力激活上下文 / Capability activation context + /// 取消令牌 / Cancellation token + /// 表示异步操作的任务 / A task representing the asynchronous operation public async Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { // 好友域桥契约面发布(发布者身份 = 本能力;撤销由宿主停止期自动完成)。 @@ -231,13 +259,26 @@ public async Task ActivateAsync(CapabilityActivationContext context, Cancellatio } } - /// + /// + /// 停用社交能力:本实现不做任何处理,因为好友域桥由宿主停止期自动撤销,模块不持有需要释放的资源。 + /// + /// + /// Performs no work, because the friend domain bridge is revoked automatically by the host on stop and the module holds no resources to release. + /// + /// 取消令牌 / Cancellation token + /// 已完成的任务 / A completed task public Task DeactivateAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } - /// + /// + /// 注册社交管理动作:构造社交管理处理器并注册常规社交动作与对局隔离动作。 + /// + /// + /// Builds the social admin handlers and registers the regular social actions and the match isolation actions. + /// + /// 管理动作注册表 / Admin action registry public void RegisterAdminActions(AdminActionRegistry registry) { var handlers = new OnlineAdminSocialHandlers(_sessionStore, _tokens, _punishments, _socialDecisions, _notifications, _reportStore, _chatAudit); diff --git a/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/FileNameMatchTypeAnalyzer.cs b/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/FileNameMatchTypeAnalyzer.cs index 7ddf7e963..5a6b5e4ab 100644 --- a/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/FileNameMatchTypeAnalyzer.cs +++ b/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/FileNameMatchTypeAnalyzer.cs @@ -58,13 +58,26 @@ public sealed class FileNameMatchTypeAnalyzer : DiagnosticAnalyzer DiagnosticSeverity.Error, true); - /// + /// + /// 返回本分析器唯一支持的诊断 GFX0020(文件名必须与唯一顶层类型名一致,严重级别 Error)。 + /// + /// + /// Returns the single diagnostic supported by this analyzer: GFX0020 (file name must match the sole top-level type name, severity Error). + /// + /// 仅包含 GFX0020 描述符的不可变数组 / Immutable array containing only the GFX0020 descriptor public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(SDescriptor); } } - /// + /// + /// 注册分析动作:不分析生成代码,启用并发执行,并为每棵语法树注册文件名与顶层类型名比对动作。 + /// + /// + /// Registers analysis: generated code is skipped, concurrent execution is enabled, and a syntax tree action compares + /// the file name with its top-level type name. The tree action skips non-.cs files and files whose top-level type count is not exactly one. + /// + /// 分析上下文,用于配置并注册语法树动作 / Analysis context used to configure and register the syntax tree action public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); diff --git a/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/OneTypePerFileAnalyzer.cs b/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/OneTypePerFileAnalyzer.cs index 880db6813..f48d94c46 100644 --- a/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/OneTypePerFileAnalyzer.cs +++ b/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/OneTypePerFileAnalyzer.cs @@ -58,13 +58,26 @@ public sealed class OneTypePerFileAnalyzer : DiagnosticAnalyzer DiagnosticSeverity.Error, true); - /// + /// + /// 返回本分析器唯一支持的诊断 GFX0019(每个文件只允许一个顶层类型,严重级别 Error)。 + /// + /// + /// Returns the single diagnostic supported by this analyzer: GFX0019 (one top-level type per file, severity Error). + /// + /// 仅包含 GFX0019 描述符的不可变数组 / Immutable array containing only the GFX0019 descriptor public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(SDescriptor); } } - /// + /// + /// 注册分析动作:不分析生成代码,启用并发执行,并为每棵语法树注册顶层类型计数动作。 + /// + /// + /// Registers analysis: generated code is skipped, concurrent execution is enabled, and a syntax tree action collects top-level types. + /// Declarations sharing the same name and arity (partial parts) count as one type; only the first extra type is reported. + /// + /// 分析上下文,用于配置并注册语法树动作 / Analysis context used to configure and register the syntax tree action public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); diff --git a/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/UsingDeclarationBanAnalyzer.cs b/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/UsingDeclarationBanAnalyzer.cs index 68e696b36..384d13121 100644 --- a/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/UsingDeclarationBanAnalyzer.cs +++ b/GameFrameX.Architecture.Analyzers/Analyzers/CodeStyle/UsingDeclarationBanAnalyzer.cs @@ -59,13 +59,26 @@ public sealed class UsingDeclarationBanAnalyzer : DiagnosticAnalyzer DiagnosticSeverity.Error, true); - /// + /// + /// 返回本分析器唯一支持的诊断 GFX0021(禁止 using 声明,须改用带大括号的 using 语句块,严重级别 Error)。 + /// + /// + /// Returns the single diagnostic supported by this analyzer: GFX0021 (using declarations are forbidden; use a braced using statement block, severity Error). + /// + /// 仅包含 GFX0021 描述符的不可变数组 / Immutable array containing only the GFX0021 descriptor public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(SDescriptor); } } - /// + /// + /// 注册分析动作:不分析生成代码,启用并发执行,并针对局部声明语句节点注册检查动作,带 using 关键字即上报。 + /// + /// + /// Registers analysis: generated code is skipped, concurrent execution is enabled, and a syntax node action on + /// local declaration statements reports any declaration carrying the using keyword at that keyword's location. + /// + /// 分析上下文,用于配置并注册语法节点动作 / Analysis context used to configure and register the syntax node action public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); diff --git a/GameFrameX.Hotfix/Logic/Server/Chat/GameChatModerationHook.cs b/GameFrameX.Hotfix/Logic/Server/Chat/GameChatModerationHook.cs index 3c1b8fabd..ac1ba023a 100644 --- a/GameFrameX.Hotfix/Logic/Server/Chat/GameChatModerationHook.cs +++ b/GameFrameX.Hotfix/Logic/Server/Chat/GameChatModerationHook.cs @@ -58,7 +58,17 @@ public sealed class GameChatModerationHook : IOnlineChatModerationHook /// public const int MaximumContentLength = 500; - /// + /// + /// 本地同步裁决聊天消息:内容为空白或超过 即拒绝并附原因,其余一律放行;不访问外部服务。 + /// + /// + /// Synchronously judges a chat message locally: blank content or content longer than + /// is rejected with a reason; everything else is allowed. No external IO is performed and the cancellation token is not consulted. + /// + /// 待审核的聊天消息 / Chat message to moderate + /// 取消令牌(本实现为同步裁决,未使用) / Cancellation token (unused by this synchronous verdict) + /// 已完成的裁决任务:拒绝(空白或超长)或放行 / Completed verdict task: reject (blank or too long) or allow + /// 为 null / is null public Task CheckAsync(OnlineChatMessage message, CancellationToken cancellationToken = default) { if (message == null) diff --git a/GameFrameX.Launcher/Online/HostPlayerDirectory.cs b/GameFrameX.Launcher/Online/HostPlayerDirectory.cs index b78beb8b7..9bd3b1f0f 100644 --- a/GameFrameX.Launcher/Online/HostPlayerDirectory.cs +++ b/GameFrameX.Launcher/Online/HostPlayerDirectory.cs @@ -59,7 +59,20 @@ namespace GameFrameX.Launcher.Online; /// public sealed class HostPlayerDirectory : IOnlinePlayerDirectory { - /// + /// + /// 按名称关键字搜索本服玩家:关键字去首尾空白后在 GameDb 中按 PlayerState.Name 包含匹配,按玩家 ID 升序取前 limit 条;关键字为空白或 limit 不大于 0 时直接返回空列表。 + /// + /// + /// Searches local players by name keyword: the trimmed keyword is matched with a contains query on PlayerState.Name through GameDb, + /// results are ordered by player ID and truncated to limit. A blank keyword or non-positive limit returns an empty list without querying. + /// Tenant and app IDs are not used for filtering because the host database holds a single server's players; ServerId comes from the current global setting (0 when absent). + /// + /// 租户 ID(本宿主实现不参与过滤) / Tenant ID (not used for filtering by this host implementation) + /// 应用 ID(本宿主实现不参与过滤) / App ID (not used for filtering by this host implementation) + /// 名称关键字 / Name keyword + /// 最大返回条数 / Maximum number of entries to return + /// 取消令牌,透传给数据库查询 / Cancellation token passed to the database query + /// 匹配的玩家目录条目列表,可能为空 / Matching player directory entries, possibly empty public async Task> SearchByNameAsync(long tenantId, long appId, string keyword, int limit, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(keyword) || limit <= 0) @@ -80,7 +93,18 @@ public async Task> SearchByNameAsync(l .ToList(); } - /// + /// + /// 按玩家 ID 批量查询本服玩家:经 GameDb.FindByIdsAsync 读取 PlayerState,过滤掉名称为 null 的记录并按玩家 ID 升序返回;ID 列表为 null 或为空时直接返回空列表。 + /// + /// + /// Looks up local players by ID through GameDb.FindByIdsAsync, drops states whose name is null and orders by player ID. + /// A null or empty ID list returns an empty list without querying. Tenant and app IDs are not used for filtering; ServerId comes from the current global setting (0 when absent). + /// + /// 租户 ID(本宿主实现不参与过滤) / Tenant ID (not used for filtering by this host implementation) + /// 应用 ID(本宿主实现不参与过滤) / App ID (not used for filtering by this host implementation) + /// 待查询的玩家 ID 列表 / Player IDs to look up + /// 取消令牌,透传给数据库查询 / Cancellation token passed to the database query + /// 存在且有名称的玩家目录条目列表,可能为空 / Directory entries for existing named players, possibly empty public async Task> FindAsync(long tenantId, long appId, IReadOnlyList playerIds, CancellationToken cancellationToken = default) { if (playerIds == null || playerIds.Count == 0) diff --git a/GameFrameX.Launcher/Online/HotfixManagerRollbackExecutor.cs b/GameFrameX.Launcher/Online/HotfixManagerRollbackExecutor.cs index cc298b34f..6ef0c3571 100644 --- a/GameFrameX.Launcher/Online/HotfixManagerRollbackExecutor.cs +++ b/GameFrameX.Launcher/Online/HotfixManagerRollbackExecutor.cs @@ -77,7 +77,20 @@ public HotfixManagerRollbackExecutor(AppSetting setting = null) _setting = setting; } - /// + /// + /// 将热更程序集切换到已落盘的目标版本:校验版本号并解析制品路径,在互斥门内经 装载并确认实际装载路径;装载失败时尝试恢复切换前版本后抛出。 + /// + /// + /// Switches the hotfix assembly to an already-downloaded target version. The version is validated and resolved to an artifact path, + /// then under a single-flight gate the artifact must exist on disk (no download at switch time), is loaded via , + /// and the loaded assembly location is verified. On failure the previously loaded version is reloaded before throwing. + /// + /// 目标热更版本号 / Target hotfix version + /// 取消令牌,仅用于等待切换互斥门 / Cancellation token, used only while waiting for the switch gate + /// 表示异步切换操作的任务 / Task representing the asynchronous switch + /// 版本号为空白或含非法路径段 / Version is blank or contains illegal path segments + /// 目标版本制品未落盘 / Target version artifact is not on disk + /// 目标版本装载失败(已恢复或恢复也失败) / Target load failed (original restored, or restoration also failed) public async Task RollbackAsync(string targetVersion, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(targetVersion)) diff --git a/GameFrameX.Launcher/Online/LogHelperCapabilityAssemblyLog.cs b/GameFrameX.Launcher/Online/LogHelperCapabilityAssemblyLog.cs index 4f16db9a5..af3ac99b4 100644 --- a/GameFrameX.Launcher/Online/LogHelperCapabilityAssemblyLog.cs +++ b/GameFrameX.Launcher/Online/LogHelperCapabilityAssemblyLog.cs @@ -44,13 +44,25 @@ namespace GameFrameX.Launcher.Online; /// public sealed class LogHelperCapabilityAssemblyLog : ICapabilityAssemblyLog { - /// + /// + /// 将能力装配的信息日志直接转发到宿主 LogHelper.Info。 + /// + /// + /// Forwards capability assembly informational messages directly to the host LogHelper.Info. + /// + /// 日志消息 / Log message public void Info(string message) { LogHelper.Info(message); } - /// + /// + /// 将能力装配的错误日志直接转发到宿主 LogHelper.Error。 + /// + /// + /// Forwards capability assembly error messages directly to the host LogHelper.Error. + /// + /// 日志消息 / Log message public void Error(string message) { LogHelper.Error(message); diff --git a/GameFrameX.Templates/templates/gfx-online/{{Name}}/EmptyPlayerDirectory.cs b/GameFrameX.Templates/templates/gfx-online/{{Name}}/EmptyPlayerDirectory.cs index e92e12f41..a7f5f3a57 100644 --- a/GameFrameX.Templates/templates/gfx-online/{{Name}}/EmptyPlayerDirectory.cs +++ b/GameFrameX.Templates/templates/gfx-online/{{Name}}/EmptyPlayerDirectory.cs @@ -46,13 +46,36 @@ namespace {{Name}}; /// public sealed class EmptyPlayerDirectory : IOnlinePlayerDirectory { - /// + /// + /// 模板缺省实现:最小 Online 宿主没有玩家存储,任何关键字搜索都返回空列表;接入真实玩家数据时须替换本类。 + /// + /// + /// Template default: the minimal Online host has no player store, so every name search returns an empty list. + /// Replace this class when wiring real player data. + /// + /// 租户 ID(未使用) / Tenant ID (unused) + /// 应用 ID(未使用) / App ID (unused) + /// 名称关键字(未使用) / Name keyword (unused) + /// 最大返回条数(未使用) / Maximum number of entries (unused) + /// 取消令牌(未使用) / Cancellation token (unused) + /// 已完成的空列表任务 / Completed task with an empty list public Task> SearchByNameAsync(long tenantId, long appId, string keyword, int limit, CancellationToken cancellationToken = default) { return Task.FromResult>(new List()); } - /// + /// + /// 模板缺省实现:最小 Online 宿主没有玩家存储,任何 ID 查询都返回空列表;接入真实玩家数据时须替换本类。 + /// + /// + /// Template default: the minimal Online host has no player store, so every ID lookup returns an empty list. + /// Replace this class when wiring real player data. + /// + /// 租户 ID(未使用) / Tenant ID (unused) + /// 应用 ID(未使用) / App ID (unused) + /// 玩家 ID 列表(未使用) / Player IDs (unused) + /// 取消令牌(未使用) / Cancellation token (unused) + /// 已完成的空列表任务 / Completed task with an empty list public Task> FindAsync(long tenantId, long appId, IReadOnlyList playerIds, CancellationToken cancellationToken = default) { return Task.FromResult>(new List()); diff --git a/GameFrameX.Templates/templates/gfx-online/{{Name}}/UnsupportedHotfixRollbackExecutor.cs b/GameFrameX.Templates/templates/gfx-online/{{Name}}/UnsupportedHotfixRollbackExecutor.cs index 3eddc5043..728840ed7 100644 --- a/GameFrameX.Templates/templates/gfx-online/{{Name}}/UnsupportedHotfixRollbackExecutor.cs +++ b/GameFrameX.Templates/templates/gfx-online/{{Name}}/UnsupportedHotfixRollbackExecutor.cs @@ -46,7 +46,16 @@ namespace {{Name}}; /// public sealed class UnsupportedHotfixRollbackExecutor : IOnlineHotfixRollbackExecutor { - /// + /// + /// 模板缺省实现:最小 Online 宿主不运行热更运行时,回滚请求一律抛出不支持异常;需要热更回滚时须替换为真实执行器。 + /// + /// + /// Template default: the minimal Online host runs no hotfix runtime, so every rollback request throws a not-supported exception. + /// Replace with a real executor when hotfix rollback is needed. + /// + /// 目标版本号,仅写入异常消息 / Target version, only included in the exception message + /// 取消令牌(未使用) / Cancellation token (unused) + /// 不会正常返回,始终抛出 NotSupportedException / Never returns normally; always throws NotSupportedException public Task RollbackAsync(string targetVersion, CancellationToken cancellationToken = default) { throw new NotSupportedException("This minimal Online host does not run a hotfix runtime; rollback to version '" + targetVersion + "' is not supported."); diff --git a/Tests/GameFrameX.Hotfix.Tests/ComponentAgentEventDispatchTests.cs b/Tests/GameFrameX.Hotfix.Tests/ComponentAgentEventDispatchTests.cs index 571f40964..cf90f2a7e 100644 --- a/Tests/GameFrameX.Hotfix.Tests/ComponentAgentEventDispatchTests.cs +++ b/Tests/GameFrameX.Hotfix.Tests/ComponentAgentEventDispatchTests.cs @@ -152,7 +152,15 @@ internal static void Reset() ReceivedAgent = null; } - /// + /// + /// 记录收到的玩家组件代理到静态字段,供测试断言派发命中本监听器且代理归属正确;不做其他处理。 + /// + /// + /// Records the received player component agent into a static field so tests can assert dispatch reached this listener with the correct agent; performs no other work. + /// + /// 收到事件的玩家组件代理 / Player component agent that received the event + /// 探针事件参数(本实现不读取) / Probe event arguments (not read by this implementation) + /// 记录完成后立即返回的已完成任务 / Completed task returned immediately after recording protected override Task HandleEventAsync(PlayerComponentAgent agent, GameEventArgs gameEventArgs) { ReceivedAgent = agent; @@ -175,7 +183,15 @@ internal static void Reset() Triggered = false; } - /// + /// + /// 将触发标记置为 true,供测试断言其他 actor 类型的监听器未被派发;不做其他处理。 + /// + /// + /// Sets the triggered flag to true so tests can assert that listeners of other actor types are not dispatched; performs no other work. + /// + /// 收到事件的服务器组件代理(本实现不读取) / Server component agent that received the event (not read by this implementation) + /// 探针事件参数(本实现不读取) / Probe event arguments (not read by this implementation) + /// 置位后立即返回的已完成任务 / Completed task returned immediately after setting the flag protected override Task HandleEventAsync(ServerComponentAgent agent, GameEventArgs gameEventArgs) { Triggered = true; diff --git a/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeAssemblyLog.cs b/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeAssemblyLog.cs index 44967a5f5..1d18800a1 100644 --- a/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeAssemblyLog.cs +++ b/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeAssemblyLog.cs @@ -43,13 +43,25 @@ public sealed class HotfixBridgeAssemblyLog : ICapabilityAssemblyLog /// Error 级装配日志。 public List Errors { get; } = new List(); - /// + /// + /// 将信息日志追加到 Infos 列表,供测试断言装配过程输出的信息条目。 + /// + /// + /// Appends the informational message to the Infos list so tests can assert assembly informational output. + /// + /// 信息日志内容 / Informational log message public void Info(string message) { Infos.Add(message); } - /// + /// + /// 将错误日志追加到 Errors 列表,供测试断言装配过程输出的错误条目。 + /// + /// + /// Appends the error message to the Errors list so tests can assert assembly error output. + /// + /// 错误日志内容 / Error log message public void Error(string message) { Errors.Add(message); diff --git a/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeStubModule.cs b/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeStubModule.cs index a97924078..8597a25bb 100644 --- a/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeStubModule.cs +++ b/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeStubModule.cs @@ -49,19 +49,39 @@ public sealed class HotfixBridgeStubModule : ICapabilityModule /// private static readonly CapabilityManifest ManifestInstance = new CapabilityManifest(CapabilityId, "1.0.0"); - /// + /// + /// 获取桩模块的能力清单,固定返回静态的 ManifestInstance。 + /// + /// + /// Gets the stub module capability manifest; always returns the static ManifestInstance. + /// + /// 桩模块固定的能力清单实例 / Fixed capability manifest instance of the stub module public CapabilityManifest Manifest { get { return ManifestInstance; } } - /// + /// + /// 注册期不做任何声明:桥契约只能在激活期发布,因此桩模块无需注册服务。 + /// + /// + /// Declares nothing during registration, because bridge contracts may only be published at activation time; the stub module needs no service registration. + /// + /// 能力注册上下文(本实现不使用) / Capability registration context (unused by this implementation) public void Register(CapabilityRegistrationContext context) { // 桩模块无注册期声明:桥契约只能在激活期发布。 } - /// + /// + /// 按测试槽位发布桥:好友域与匹配域槽位非空时分别发布 IOnlineFriendDomain 与 IOnlineMatchDomain,开启作用域开关时发布授权作用域提供者桩。 + /// + /// + /// Publishes bridges according to the test slots: the friend and match domain bridges when their slots are non-null, and the authorized scope provider stub when the scope switch is enabled. + /// + /// 能力激活上下文,用于发布桥 / Capability activation context used to publish bridges + /// 取消令牌(本实现不使用) / Cancellation token (unused by this implementation) + /// 发布完成后立即返回的已完成任务 / Completed task returned immediately after publishing public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { var friendDomain = HotfixBridgeStubSlots.FriendDomain; @@ -84,7 +104,14 @@ public Task ActivateAsync(CapabilityActivationContext context, CancellationToken return Task.CompletedTask; } - /// + /// + /// 停用时不做任何处理:已发布的桥由机制在停止期自动撤销,模块不得自行撤销。 + /// + /// + /// Does nothing on deactivation, because published bridges are retracted automatically by the mechanism during stop and the module must not retract them itself. + /// + /// 取消令牌(本实现不使用) / Cancellation token (unused by this implementation) + /// 立即返回的已完成任务 / Completed task returned immediately public Task DeactivateAsync(CancellationToken cancellationToken) { // 桥由机制在停止期自动撤销,模块不得自行撤销。 diff --git a/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeStubScopeProvider.cs b/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeStubScopeProvider.cs index ded12b788..7c7f4b24c 100644 --- a/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeStubScopeProvider.cs +++ b/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeStubScopeProvider.cs @@ -50,7 +50,13 @@ public sealed class HotfixBridgeStubScopeProvider : IOnlineAuthorizedScopeProvid /// private readonly OnlineScope _authorizedScope = new OnlineScope(TenantId, AppId, ServerId); - /// + /// + /// 获取桩授权作用域,固定返回租户 1、应用 1、区服 1001 构成的单例作用域。 + /// + /// + /// Gets the stub authorized scope; always returns the singleton scope built from tenant 1, application 1 and server 1001. + /// + /// 固定的桩授权作用域 / Fixed stub authorized scope public OnlineScope AuthorizedScope { get { return _authorizedScope; } diff --git a/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeTestFamily.cs b/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeTestFamily.cs index 5a5fcd0de..35af63f07 100644 --- a/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeTestFamily.cs +++ b/Tests/GameFrameX.Hotfix.Tests/HotfixBridgeTestFamily.cs @@ -38,25 +38,49 @@ namespace GameFrameX.Hotfix.Tests; /// public sealed class HotfixBridgeTestFamily : ICapabilityFamily { - /// + /// + /// 获取测试能力族标识,固定返回 hotfix-bridge-tests。 + /// + /// + /// Gets the test capability family identifier; always returns hotfix-bridge-tests. + /// + /// 固定的族标识 / Fixed family identifier public string FamilyId { get { return "hotfix-bridge-tests"; } } - /// + /// + /// 获取测试能力族的配置节名,固定返回 HotfixBridgeTests。 + /// + /// + /// Gets the configuration section name of the test family; always returns HotfixBridgeTests. + /// + /// 固定的配置节名 / Fixed configuration section name public string ConfigurationSectionName { get { return "HotfixBridgeTests"; } } - /// + /// + /// 获取部署程序集前缀,固定返回 GameFrameX.Hotfix.Tests,使本测试程序集内的桩模块参与发现。 + /// + /// + /// Gets the deployment assembly prefix; always returns GameFrameX.Hotfix.Tests so stub modules in this test assembly are discovered. + /// + /// 固定的部署程序集前缀 / Fixed deployment assembly prefix public string DeploymentAssemblyPrefix { get { return "GameFrameX.Hotfix.Tests"; } } - /// + /// + /// 不注册任何族基建:域桥测试的桥契约全部由桩模块在激活期发布。 + /// + /// + /// Registers no family infrastructure, because all bridge contracts in the domain bridge tests are published by the stub module at activation time. + /// + /// 能力族上下文(本实现不使用) / Capability family context (unused by this implementation) public void RegisterInfrastructure(CapabilityFamilyContext context) { // 域桥测试不需要族基建:桥契约全部由桩模块在激活期发布。 diff --git a/Tests/GameFrameX.Tests/DataBase/PostgreSqlDbServiceCompatibilityTests.cs b/Tests/GameFrameX.Tests/DataBase/PostgreSqlDbServiceCompatibilityTests.cs index 9bedd0f11..14d49239b 100644 --- a/Tests/GameFrameX.Tests/DataBase/PostgreSqlDbServiceCompatibilityTests.cs +++ b/Tests/GameFrameX.Tests/DataBase/PostgreSqlDbServiceCompatibilityTests.cs @@ -335,7 +335,13 @@ private sealed class LegacyProbeState : BaseCacheState /// public List Items { get; set; } - /// + /// + /// 将 Id|Name|Level 拼接为文本并按 UTF-8 编码为字节,作为旧格式探针状态的简易序列化结果。 + /// + /// + /// Joins Id|Name|Level into text and encodes it as UTF-8 bytes, serving as a simple serialization of the legacy probe state. + /// + /// 拼接文本的 UTF-8 字节 / UTF-8 bytes of the joined text public override byte[] ToBytes() { var data = $"{Id}|{Name}|{Level}"; @@ -380,7 +386,13 @@ private sealed class IndexProbeState : BaseCacheState /// public string Name { get; set; } - /// + /// + /// 将 Id|Score 拼接为文本并按 UTF-8 编码为字节,作为索引探针状态的简易序列化结果。 + /// + /// + /// Joins Id|Score into text and encodes it as UTF-8 bytes, serving as a simple serialization of the index probe state. + /// + /// 拼接文本的 UTF-8 字节 / UTF-8 bytes of the joined text public override byte[] ToBytes() { var data = $"{Id}|{Score}"; @@ -404,7 +416,13 @@ private sealed class RebuildProbeState : BaseCacheState /// public string Name { get; set; } - /// + /// + /// 将 Id|Score 拼接为文本并按 UTF-8 编码为字节,作为索引重建探针状态的简易序列化结果。 + /// + /// + /// Joins Id|Score into text and encodes it as UTF-8 bytes, serving as a simple serialization of the index rebuild probe state. + /// + /// 拼接文本的 UTF-8 字节 / UTF-8 bytes of the joined text public override byte[] ToBytes() { var data = $"{Id}|{Score}"; @@ -427,7 +445,13 @@ private sealed class SortNullProbeState : BaseCacheState /// public string Name { get; set; } - /// + /// + /// 将 Id|Score 拼接为文本并按 UTF-8 编码为字节,作为空值排序探针状态的简易序列化结果。 + /// + /// + /// Joins Id|Score into text and encodes it as UTF-8 bytes, serving as a simple serialization of the null sorting probe state. + /// + /// 拼接文本的 UTF-8 字节 / UTF-8 bytes of the joined text public override byte[] ToBytes() { var data = $"{Id}|{Score}"; diff --git a/Tests/GameFrameX.Tests/Online/CapabilityBindingTestOptions.cs b/Tests/GameFrameX.Tests/Online/CapabilityBindingTestOptions.cs index ba2caf313..24385168e 100644 --- a/Tests/GameFrameX.Tests/Online/CapabilityBindingTestOptions.cs +++ b/Tests/GameFrameX.Tests/Online/CapabilityBindingTestOptions.cs @@ -49,7 +49,13 @@ public sealed class CapabilityBindingTestOptions : ICapabilityOptions /// 获取或设置嵌套参数段(嵌套字段路径验证位)。 public NestedSection Nested { get; set; } = new NestedSection(); - /// + /// + /// 校验 Alpha、Beta、Gamma 与 Nested.Depth 均为正数;嵌套段为 null 时按 0 计入,从而报告校验失败。 + /// + /// + /// Validates that Alpha, Beta, Gamma and Nested.Depth are all positive; a null nested section counts as 0 and is therefore reported as a validation failure. + /// + /// 收集校验失败的能力选项校验器 / Capability options validation collector that records failures public void Validate(CapabilityOptionsValidation validation) { validation.RequirePositive("Alpha", Alpha); diff --git a/Tests/GameFrameX.Tests/Online/CapabilityDependencyCheckTests.cs b/Tests/GameFrameX.Tests/Online/CapabilityDependencyCheckTests.cs index 9f79353d7..f37970ae6 100644 --- a/Tests/GameFrameX.Tests/Online/CapabilityDependencyCheckTests.cs +++ b/Tests/GameFrameX.Tests/Online/CapabilityDependencyCheckTests.cs @@ -69,7 +69,13 @@ public ScopeProbeService(string name) Name = name; } - /// + /// + /// 获取构造时传入的探针名,供测试按名称区分解析到的探针实例。 + /// + /// + /// Gets the probe name passed at construction so tests can tell resolved probe instances apart by name. + /// + /// 探针名 / Probe name public string Name { get; } } diff --git a/Tests/GameFrameX.Tests/Online/CapabilityHostServiceAndHookTests.cs b/Tests/GameFrameX.Tests/Online/CapabilityHostServiceAndHookTests.cs index b9ac4d50f..a2220ec2a 100644 --- a/Tests/GameFrameX.Tests/Online/CapabilityHostServiceAndHookTests.cs +++ b/Tests/GameFrameX.Tests/Online/CapabilityHostServiceAndHookTests.cs @@ -114,7 +114,13 @@ public NamedImplementation(string name) Name = name; } - /// + /// + /// 获取构造时传入的实现标记,供测试按标记断言宿主服务或钩子解析到的是哪个实例。 + /// + /// + /// Gets the implementation marker passed at construction so tests can assert which instance a host service or hook resolved to. + /// + /// 实现标记 / Implementation marker public string Name { get; } } diff --git a/Tests/GameFrameX.Tests/Online/CapabilityLifecycleAndBridgeTests.cs b/Tests/GameFrameX.Tests/Online/CapabilityLifecycleAndBridgeTests.cs index c52cea390..96d22f9a5 100644 --- a/Tests/GameFrameX.Tests/Online/CapabilityLifecycleAndBridgeTests.cs +++ b/Tests/GameFrameX.Tests/Online/CapabilityLifecycleAndBridgeTests.cs @@ -122,7 +122,13 @@ public BridgeImplementation(string owner) Owner = owner; } - /// + /// + /// 获取构造时传入的发布者标记,供测试断言桥解析到的是哪个发布者的实例。 + /// + /// + /// Gets the publisher marker passed at construction so tests can assert which publisher's instance a bridge resolved to. + /// + /// 发布者标记 / Publisher marker public string Owner { get; } } diff --git a/Tests/GameFrameX.Tests/Online/CapabilitySchedulerTests.cs b/Tests/GameFrameX.Tests/Online/CapabilitySchedulerTests.cs index a23f55ad9..b6f4bd673 100644 --- a/Tests/GameFrameX.Tests/Online/CapabilitySchedulerTests.cs +++ b/Tests/GameFrameX.Tests/Online/CapabilitySchedulerTests.cs @@ -74,7 +74,13 @@ public ManualSchedulerClock(DateTimeOffset start) _utcNow = start; } - /// + /// + /// 在锁内读取手动维护的虚拟时刻;时刻只随测试显式推进而变化,不读取系统时钟。 + /// + /// + /// Reads the manually maintained virtual time under a lock; it changes only when the test advances it explicitly and never reads the system clock. + /// + /// 当前虚拟时刻 / Current virtual time public DateTimeOffset UtcNow { get @@ -188,7 +194,15 @@ public TickRoundRecord[] TickRounds } } - /// + /// + /// 在锁内记录一条作业失败(类型、名称、异常),供测试断言调度器上报的失败。 + /// + /// + /// Records a job failure (kind, name, exception) under a lock so tests can assert failures reported by the scheduler. + /// + /// 失败作业类型 / Kind of the failed job + /// 失败作业名称 / Name of the failed job + /// 作业抛出的异常 / Exception thrown by the job public void OnJobFailed(CapabilitySchedulerJobKind jobKind, string jobName, Exception exception) { lock (_sync) @@ -197,7 +211,15 @@ public void OnJobFailed(CapabilitySchedulerJobKind jobKind, string jobName, Exce } } - /// + /// + /// 在锁内记录一轮 tick 的执行作业数与失败作业数,供测试断言调度轮次统计;耗时不记录。 + /// + /// + /// Records the executed and failed job counts of a tick round under a lock so tests can assert round statistics; the elapsed time is not recorded. + /// + /// 本轮耗时(本实现不记录) / Elapsed time of the round (not recorded by this implementation) + /// 本轮执行的作业数 / Number of jobs executed in the round + /// 本轮失败的作业数 / Number of jobs failed in the round public void OnTickRoundCompleted(TimeSpan elapsed, int executedJobCount, int failedJobCount) { lock (_sync) diff --git a/Tests/GameFrameX.Tests/Online/CollectingCapabilityAssemblyLog.cs b/Tests/GameFrameX.Tests/Online/CollectingCapabilityAssemblyLog.cs index c43bc1a13..39f5f1cad 100644 --- a/Tests/GameFrameX.Tests/Online/CollectingCapabilityAssemblyLog.cs +++ b/Tests/GameFrameX.Tests/Online/CollectingCapabilityAssemblyLog.cs @@ -57,13 +57,25 @@ public sealed class CollectingCapabilityAssemblyLog : ICapabilityAssemblyLog /// Error 级日志流。 public readonly List Errors = new(); - /// + /// + /// 将信息日志追加到 Infos 列表,供测试断言能力装配输出的信息条目。 + /// + /// + /// Appends the informational message to the Infos list so tests can assert capability assembly informational output. + /// + /// 信息日志内容 / Informational log message public void Info(string message) { Infos.Add(message); } - /// + /// + /// 将错误日志追加到 Errors 列表,供测试断言能力装配输出的错误条目。 + /// + /// + /// Appends the error message to the Errors list so tests can assert capability assembly error output. + /// + /// 错误日志内容 / Error log message public void Error(string message) { Errors.Add(message); diff --git a/Tests/GameFrameX.Tests/Online/HotfixManagerRollbackExecutorTests.cs b/Tests/GameFrameX.Tests/Online/HotfixManagerRollbackExecutorTests.cs index 492bd8b02..128a892e9 100644 --- a/Tests/GameFrameX.Tests/Online/HotfixManagerRollbackExecutorTests.cs +++ b/Tests/GameFrameX.Tests/Online/HotfixManagerRollbackExecutorTests.cs @@ -205,7 +205,15 @@ public PayloadHandler(byte[] payload) _payload = payload; } - /// + /// + /// 递增请求计数后,对任意请求固定返回 200 响应,响应体为构造时传入的制品字节;不发起真实网络请求。 + /// + /// + /// Increments the request counter and returns a fixed 200 response whose body is the artifact bytes passed at construction, for any request; no real network call is made. + /// + /// HTTP 请求(本实现不读取) / HTTP request (not read by this implementation) + /// 取消令牌(本实现不使用) / Cancellation token (unused by this implementation) + /// 携带制品字节的 200 响应任务 / Task yielding a 200 response carrying the artifact bytes protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { CallCount++; diff --git a/Tests/GameFrameX.Tests/Online/MechanismFirstSlotModule.cs b/Tests/GameFrameX.Tests/Online/MechanismFirstSlotModule.cs index 27fba6f99..f1375f193 100644 --- a/Tests/GameFrameX.Tests/Online/MechanismFirstSlotModule.cs +++ b/Tests/GameFrameX.Tests/Online/MechanismFirstSlotModule.cs @@ -39,32 +39,65 @@ namespace GameFrameX.Tests.Online; /// 槽位一模块(发现序最先)。 public sealed class MechanismFirstSlotModule : ICapabilityModule, IAdminActionContributor { - /// + /// + /// 获取槽位一(类型名排序后最先被发现的槽位)的能力清单:每次读取都由 现场生成,能力标识取用例覆写值,未覆写时为缺省 mech-first,版本固定 1.0.0,并带上用例设置的动作、必需依赖、可选依赖与参数类型。 + /// + /// + /// Builds the manifest of slot first (the slot discovered first by type-name ordering) on every read from MechanismScenario.First: the capability identifier is the per-test override or the default mech-first, version is fixed at 1.0.0, and actions, required and optional dependencies and options type come from the slot setup. + /// + /// 槽位一当前场景对应的能力清单 / Capability manifest reflecting the current setup of slot first public CapabilityManifest Manifest { get { return MechanismScenario.First.ToManifest(); } } - /// + /// + /// 把注册阶段转交给槽位一的 Register 委托,供用例在 mech-first 上注入服务或记录注册顺序;用例未设置委托时不做任何注册。 + /// + /// + /// Forwards the registration phase to the Register delegate of slot first so tests can inject services or record ordering for mech-first; registers nothing when no delegate is set. + /// + /// 能力注册上下文,原样传给槽位一委托 / Registration context passed unchanged to the slot first delegate public void Register(CapabilityRegistrationContext context) { MechanismScenario.First.Register?.Invoke(context); } - /// + /// + /// 把激活阶段转交给槽位一的 Activate 委托并返回其任务,用于验证 mech-first 的激活顺序、激活失败与回滚等机制;未设置委托时直接返回已完成任务,即视为激活成功。 + /// + /// + /// Forwards activation to the Activate delegate of slot first and returns its task, letting tests drive ordering, failure and rollback for mech-first; returns a completed task (successful activation) when no delegate is set. + /// + /// 能力激活上下文,原样传给槽位一委托 / Activation context passed unchanged to the slot first delegate + /// 取消令牌,原样传给委托 / Cancellation token passed to the delegate + /// 委托返回的任务;无委托时为已完成任务 / Task returned by the delegate, or a completed task when none is set public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { return MechanismScenario.First.Activate?.Invoke(context, cancellationToken) ?? Task.CompletedTask; } - /// + /// + /// 同步调用槽位一的 Deactivate 委托(用例借此记录 mech-first 的停用顺序),随后返回已完成任务;委托为同步形式,因此没有需要等待的异步工作。 + /// + /// + /// Synchronously invokes the Deactivate delegate of slot first (used to record the deactivation order of mech-first) and returns a completed task, because the delegate is synchronous and nothing needs awaiting. + /// + /// 取消令牌,原样传给委托 / Cancellation token passed to the delegate + /// 已完成的任务 / Completed task public Task DeactivateAsync(CancellationToken cancellationToken) { MechanismScenario.First.Deactivate?.Invoke(cancellationToken); return Task.CompletedTask; } - /// + /// + /// 把管理动作注册转交给槽位一的 RegisterAdminActions 委托,用于验证 mech-first 贡献的管理面动作;未设置委托时不注册任何动作。 + /// + /// + /// Forwards admin action registration to the RegisterAdminActions delegate of slot first to exercise admin actions contributed by mech-first; registers no action when no delegate is set. + /// + /// 管理动作注册表,原样传给槽位一委托 / Admin action registry passed unchanged to the slot first delegate public void RegisterAdminActions(AdminActionRegistry registry) { MechanismScenario.First.RegisterAdminActions?.Invoke(registry); diff --git a/Tests/GameFrameX.Tests/Online/MechanismFourthSlotModule.cs b/Tests/GameFrameX.Tests/Online/MechanismFourthSlotModule.cs index b261b5ffd..edb90dad1 100644 --- a/Tests/GameFrameX.Tests/Online/MechanismFourthSlotModule.cs +++ b/Tests/GameFrameX.Tests/Online/MechanismFourthSlotModule.cs @@ -39,32 +39,65 @@ namespace GameFrameX.Tests.Online; /// 槽位四模块。 public sealed class MechanismFourthSlotModule : ICapabilityModule, IAdminActionContributor { - /// + /// + /// 获取槽位四(发现顺序按类型名 MechanismFourthSlotModule 排序决定,而非槽位序号)的能力清单:每次读取都由 现场生成,能力标识取用例覆写值,未覆写时为缺省 mech-fourth,版本固定 1.0.0,并带上用例设置的动作、必需依赖、可选依赖与参数类型。 + /// + /// + /// Builds the manifest of slot fourth (discovery order follows the type name MechanismFourthSlotModule, not the slot number) on every read from MechanismScenario.Fourth: the capability identifier is the per-test override or the default mech-fourth, version is fixed at 1.0.0, and actions, required and optional dependencies and options type come from the slot setup. + /// + /// 槽位四当前场景对应的能力清单 / Capability manifest reflecting the current setup of slot fourth public CapabilityManifest Manifest { get { return MechanismScenario.Fourth.ToManifest(); } } - /// + /// + /// 把注册阶段转交给槽位四的 Register 委托,供用例在 mech-fourth 上注入服务或记录注册顺序;用例未设置委托时不做任何注册。 + /// + /// + /// Forwards the registration phase to the Register delegate of slot fourth so tests can inject services or record ordering for mech-fourth; registers nothing when no delegate is set. + /// + /// 能力注册上下文,原样传给槽位四委托 / Registration context passed unchanged to the slot fourth delegate public void Register(CapabilityRegistrationContext context) { MechanismScenario.Fourth.Register?.Invoke(context); } - /// + /// + /// 把激活阶段转交给槽位四的 Activate 委托并返回其任务,用于验证 mech-fourth 的激活顺序、激活失败与回滚等机制;未设置委托时直接返回已完成任务,即视为激活成功。 + /// + /// + /// Forwards activation to the Activate delegate of slot fourth and returns its task, letting tests drive ordering, failure and rollback for mech-fourth; returns a completed task (successful activation) when no delegate is set. + /// + /// 能力激活上下文,原样传给槽位四委托 / Activation context passed unchanged to the slot fourth delegate + /// 取消令牌,原样传给委托 / Cancellation token passed to the delegate + /// 委托返回的任务;无委托时为已完成任务 / Task returned by the delegate, or a completed task when none is set public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { return MechanismScenario.Fourth.Activate?.Invoke(context, cancellationToken) ?? Task.CompletedTask; } - /// + /// + /// 同步调用槽位四的 Deactivate 委托(用例借此记录 mech-fourth 的停用顺序),随后返回已完成任务;委托为同步形式,因此没有需要等待的异步工作。 + /// + /// + /// Synchronously invokes the Deactivate delegate of slot fourth (used to record the deactivation order of mech-fourth) and returns a completed task, because the delegate is synchronous and nothing needs awaiting. + /// + /// 取消令牌,原样传给委托 / Cancellation token passed to the delegate + /// 已完成的任务 / Completed task public Task DeactivateAsync(CancellationToken cancellationToken) { MechanismScenario.Fourth.Deactivate?.Invoke(cancellationToken); return Task.CompletedTask; } - /// + /// + /// 把管理动作注册转交给槽位四的 RegisterAdminActions 委托,用于验证 mech-fourth 贡献的管理面动作;未设置委托时不注册任何动作。 + /// + /// + /// Forwards admin action registration to the RegisterAdminActions delegate of slot fourth to exercise admin actions contributed by mech-fourth; registers no action when no delegate is set. + /// + /// 管理动作注册表,原样传给槽位四委托 / Admin action registry passed unchanged to the slot fourth delegate public void RegisterAdminActions(AdminActionRegistry registry) { MechanismScenario.Fourth.RegisterAdminActions?.Invoke(registry); diff --git a/Tests/GameFrameX.Tests/Online/MechanismSecondSlotModule.cs b/Tests/GameFrameX.Tests/Online/MechanismSecondSlotModule.cs index 7b2c8b16c..03565c31c 100644 --- a/Tests/GameFrameX.Tests/Online/MechanismSecondSlotModule.cs +++ b/Tests/GameFrameX.Tests/Online/MechanismSecondSlotModule.cs @@ -39,32 +39,65 @@ namespace GameFrameX.Tests.Online; /// 槽位二模块。 public sealed class MechanismSecondSlotModule : ICapabilityModule, IAdminActionContributor { - /// + /// + /// 获取槽位二(发现顺序按类型名 MechanismSecondSlotModule 排序决定,而非槽位序号)的能力清单:每次读取都由 现场生成,能力标识取用例覆写值,未覆写时为缺省 mech-second,版本固定 1.0.0,并带上用例设置的动作、必需依赖、可选依赖与参数类型。 + /// + /// + /// Builds the manifest of slot second (discovery order follows the type name MechanismSecondSlotModule, not the slot number) on every read from MechanismScenario.Second: the capability identifier is the per-test override or the default mech-second, version is fixed at 1.0.0, and actions, required and optional dependencies and options type come from the slot setup. + /// + /// 槽位二当前场景对应的能力清单 / Capability manifest reflecting the current setup of slot second public CapabilityManifest Manifest { get { return MechanismScenario.Second.ToManifest(); } } - /// + /// + /// 把注册阶段转交给槽位二的 Register 委托,供用例在 mech-second 上注入服务或记录注册顺序;用例未设置委托时不做任何注册。 + /// + /// + /// Forwards the registration phase to the Register delegate of slot second so tests can inject services or record ordering for mech-second; registers nothing when no delegate is set. + /// + /// 能力注册上下文,原样传给槽位二委托 / Registration context passed unchanged to the slot second delegate public void Register(CapabilityRegistrationContext context) { MechanismScenario.Second.Register?.Invoke(context); } - /// + /// + /// 把激活阶段转交给槽位二的 Activate 委托并返回其任务,用于验证 mech-second 的激活顺序、激活失败与回滚等机制;未设置委托时直接返回已完成任务,即视为激活成功。 + /// + /// + /// Forwards activation to the Activate delegate of slot second and returns its task, letting tests drive ordering, failure and rollback for mech-second; returns a completed task (successful activation) when no delegate is set. + /// + /// 能力激活上下文,原样传给槽位二委托 / Activation context passed unchanged to the slot second delegate + /// 取消令牌,原样传给委托 / Cancellation token passed to the delegate + /// 委托返回的任务;无委托时为已完成任务 / Task returned by the delegate, or a completed task when none is set public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { return MechanismScenario.Second.Activate?.Invoke(context, cancellationToken) ?? Task.CompletedTask; } - /// + /// + /// 同步调用槽位二的 Deactivate 委托(用例借此记录 mech-second 的停用顺序),随后返回已完成任务;委托为同步形式,因此没有需要等待的异步工作。 + /// + /// + /// Synchronously invokes the Deactivate delegate of slot second (used to record the deactivation order of mech-second) and returns a completed task, because the delegate is synchronous and nothing needs awaiting. + /// + /// 取消令牌,原样传给委托 / Cancellation token passed to the delegate + /// 已完成的任务 / Completed task public Task DeactivateAsync(CancellationToken cancellationToken) { MechanismScenario.Second.Deactivate?.Invoke(cancellationToken); return Task.CompletedTask; } - /// + /// + /// 把管理动作注册转交给槽位二的 RegisterAdminActions 委托,用于验证 mech-second 贡献的管理面动作;未设置委托时不注册任何动作。 + /// + /// + /// Forwards admin action registration to the RegisterAdminActions delegate of slot second to exercise admin actions contributed by mech-second; registers no action when no delegate is set. + /// + /// 管理动作注册表,原样传给槽位二委托 / Admin action registry passed unchanged to the slot second delegate public void RegisterAdminActions(AdminActionRegistry registry) { MechanismScenario.Second.RegisterAdminActions?.Invoke(registry); diff --git a/Tests/GameFrameX.Tests/Online/MechanismTestFamily.cs b/Tests/GameFrameX.Tests/Online/MechanismTestFamily.cs index 19e06b058..62c6ed6d7 100644 --- a/Tests/GameFrameX.Tests/Online/MechanismTestFamily.cs +++ b/Tests/GameFrameX.Tests/Online/MechanismTestFamily.cs @@ -42,19 +42,37 @@ namespace GameFrameX.Tests.Online; /// public sealed class MechanismTestFamily : ICapabilityFamily { - /// + /// + /// 获取机制测试族的族标识,固定返回 mechanism-tests,与业务族区分,避免机制用例和真实能力族互相干扰。 + /// + /// + /// Returns the fixed family identifier mechanism-tests, keeping mechanism test cases separate from real capability families. + /// + /// 固定值 mechanism-tests / Fixed value mechanism-tests public string FamilyId { get { return "mechanism-tests"; } } - /// + /// + /// 获取机制测试族的配置段名,固定返回 MechanismTests,用例按这个段名提供能力参数配置。 + /// + /// + /// Returns the fixed configuration section name MechanismTests, under which test cases supply capability options. + /// + /// 固定值 MechanismTests / Fixed value MechanismTests public string ConfigurationSectionName { get { return "MechanismTests"; } } - /// + /// + /// 获取部署程序集名前缀,固定返回 GameFrameX.Tests,让发现流程能扫描到按部署命名约定复制出的 GameFrameX.Tests.CapabilityStubs.dll 中的四个槽位模块。 + /// + /// + /// Returns the fixed deployment assembly prefix GameFrameX.Tests, so discovery picks up the four slot modules from the convention-named copy GameFrameX.Tests.CapabilityStubs.dll. + /// + /// 固定值 GameFrameX.Tests / Fixed value GameFrameX.Tests public string DeploymentAssemblyPrefix { get { return "GameFrameX.Tests"; } @@ -63,7 +81,13 @@ public string DeploymentAssemblyPrefix /// 最近一次组合的事件发布口捕获(事件总线行为用例经它发布)。 public static ICapabilityEventPublisher LastEventPublisher; - /// + /// + /// 预置管理面测试适配器:注册一组五个错误码位都相同(代码 0、名称 mechanism.test)的 ,注册恒放行的 作为 ,并把上下文的事件发布口保存到 供事件总线用例使用;不绑定任何 Online 业务语义。 + /// + /// + /// Seeds the admin API test adapters: registers AdminApiErrorCodes whose five slots all share one code (0, mechanism.test), registers the always-allow MechanismTestScopeAdapter as IAdminApiScopeAdapter, and stores the context event publisher in LastEventPublisher for event bus test cases. No Online business semantics are bound. + /// + /// 族基础设施注册上下文,用于登记服务并提供事件发布口 / Family infrastructure context used to add services and supply the event publisher public void RegisterInfrastructure(CapabilityFamilyContext context) { // 管理面测试适配器:五个机制用错误码位 + 恒放行作用域(机制口径,不绑 Online 语义)。 diff --git a/Tests/GameFrameX.Tests/Online/MechanismTestScopeAdapter.cs b/Tests/GameFrameX.Tests/Online/MechanismTestScopeAdapter.cs index fed0feece..5b7d3974d 100644 --- a/Tests/GameFrameX.Tests/Online/MechanismTestScopeAdapter.cs +++ b/Tests/GameFrameX.Tests/Online/MechanismTestScopeAdapter.cs @@ -41,7 +41,15 @@ namespace GameFrameX.Tests.Online; /// public sealed class MechanismTestScopeAdapter : IAdminApiScopeAdapter { - /// + /// + /// 从管理面请求中读取声明的租户、应用、服务器三元组;读取成功时据此构造声明作用域并返回 true,否则输出 null 并返回 false。 + /// + /// + /// Reads the claimed tenant, app and server triple from the admin API request; on success builds the claimed scope and returns true, otherwise outputs null and returns false. + /// + /// 管理面请求 / Admin API request + /// 读取成功时为声明作用域,失败时为 null / Claimed scope on success, null on failure + /// 请求中带有完整三元组时为 true,否则为 false / true when the request carries the full triple, otherwise false public bool TryReadClaimedScope(AdminApiRequest request, out AdminApiClaimedScope claimedScope) { if (request.TryReadClaimedScope(out var tenantId, out var appId, out var serverId)) @@ -54,7 +62,15 @@ public bool TryReadClaimedScope(AdminApiRequest request, out AdminApiClaimedScop return false; } - /// + /// + /// 恒放行:不比较声明作用域与授权作用域,始终返回 null 表示校验通过;作用域守卫的拒绝语义由 Online 侧用例单独覆盖,这里只服务机制层测试。 + /// + /// + /// Always allows: never compares the claimed and authorized scopes and always returns null (validation passed). Rejection semantics of the scope guard are covered separately by Online test cases; this adapter only serves mechanism tests. + /// + /// 请求声明的作用域(未使用) / Scope claimed by the request (unused) + /// 已授权的作用域(未使用) / Authorized scope (unused) + /// 始终为 null,表示无错误 / Always null, meaning no error public AdminApiErrorCode ValidateClaimed(AdminApiClaimedScope claimed, AdminApiClaimedScope authorized) { return null; diff --git a/Tests/GameFrameX.Tests/Online/MechanismThirdSlotModule.cs b/Tests/GameFrameX.Tests/Online/MechanismThirdSlotModule.cs index 574151ced..2476d4731 100644 --- a/Tests/GameFrameX.Tests/Online/MechanismThirdSlotModule.cs +++ b/Tests/GameFrameX.Tests/Online/MechanismThirdSlotModule.cs @@ -39,32 +39,65 @@ namespace GameFrameX.Tests.Online; /// 槽位三模块。 public sealed class MechanismThirdSlotModule : ICapabilityModule, IAdminActionContributor { - /// + /// + /// 获取槽位三(发现顺序按类型名 MechanismThirdSlotModule 排序决定,而非槽位序号)的能力清单:每次读取都由 现场生成,能力标识取用例覆写值,未覆写时为缺省 mech-third,版本固定 1.0.0,并带上用例设置的动作、必需依赖、可选依赖与参数类型。 + /// + /// + /// Builds the manifest of slot third (discovery order follows the type name MechanismThirdSlotModule, not the slot number) on every read from MechanismScenario.Third: the capability identifier is the per-test override or the default mech-third, version is fixed at 1.0.0, and actions, required and optional dependencies and options type come from the slot setup. + /// + /// 槽位三当前场景对应的能力清单 / Capability manifest reflecting the current setup of slot third public CapabilityManifest Manifest { get { return MechanismScenario.Third.ToManifest(); } } - /// + /// + /// 把注册阶段转交给槽位三的 Register 委托,供用例在 mech-third 上注入服务或记录注册顺序;用例未设置委托时不做任何注册。 + /// + /// + /// Forwards the registration phase to the Register delegate of slot third so tests can inject services or record ordering for mech-third; registers nothing when no delegate is set. + /// + /// 能力注册上下文,原样传给槽位三委托 / Registration context passed unchanged to the slot third delegate public void Register(CapabilityRegistrationContext context) { MechanismScenario.Third.Register?.Invoke(context); } - /// + /// + /// 把激活阶段转交给槽位三的 Activate 委托并返回其任务,用于验证 mech-third 的激活顺序、激活失败与回滚等机制;未设置委托时直接返回已完成任务,即视为激活成功。 + /// + /// + /// Forwards activation to the Activate delegate of slot third and returns its task, letting tests drive ordering, failure and rollback for mech-third; returns a completed task (successful activation) when no delegate is set. + /// + /// 能力激活上下文,原样传给槽位三委托 / Activation context passed unchanged to the slot third delegate + /// 取消令牌,原样传给委托 / Cancellation token passed to the delegate + /// 委托返回的任务;无委托时为已完成任务 / Task returned by the delegate, or a completed task when none is set public Task ActivateAsync(CapabilityActivationContext context, CancellationToken cancellationToken) { return MechanismScenario.Third.Activate?.Invoke(context, cancellationToken) ?? Task.CompletedTask; } - /// + /// + /// 同步调用槽位三的 Deactivate 委托(用例借此记录 mech-third 的停用顺序),随后返回已完成任务;委托为同步形式,因此没有需要等待的异步工作。 + /// + /// + /// Synchronously invokes the Deactivate delegate of slot third (used to record the deactivation order of mech-third) and returns a completed task, because the delegate is synchronous and nothing needs awaiting. + /// + /// 取消令牌,原样传给委托 / Cancellation token passed to the delegate + /// 已完成的任务 / Completed task public Task DeactivateAsync(CancellationToken cancellationToken) { MechanismScenario.Third.Deactivate?.Invoke(cancellationToken); return Task.CompletedTask; } - /// + /// + /// 把管理动作注册转交给槽位三的 RegisterAdminActions 委托,用于验证 mech-third 贡献的管理面动作;未设置委托时不注册任何动作。 + /// + /// + /// Forwards admin action registration to the RegisterAdminActions delegate of slot third to exercise admin actions contributed by mech-third; registers no action when no delegate is set. + /// + /// 管理动作注册表,原样传给槽位三委托 / Admin action registry passed unchanged to the slot third delegate public void RegisterAdminActions(AdminActionRegistry registry) { MechanismScenario.Third.RegisterAdminActions?.Invoke(registry); diff --git a/Tests/GameFrameX.Tests/Online/OnlineCapabilityTestHarness.cs b/Tests/GameFrameX.Tests/Online/OnlineCapabilityTestHarness.cs index f6bfc13e6..1583dbbf6 100644 --- a/Tests/GameFrameX.Tests/Online/OnlineCapabilityTestHarness.cs +++ b/Tests/GameFrameX.Tests/Online/OnlineCapabilityTestHarness.cs @@ -176,13 +176,34 @@ public static async Task WithRuntimeAsync(Func body, st /// public sealed class EmptyPlayerDirectory : IOnlinePlayerDirectory { - /// + /// + /// 按名称搜索玩家目录;本桩不接任何目录数据,固定返回空集合,表示部署未接入玩家目录。 + /// + /// + /// Searches the player directory by name; this stub has no directory data and always returns an empty collection. + /// + /// 租户标识(本桩忽略) / Tenant identifier (ignored by this stub) + /// 应用标识(本桩忽略) / Application identifier (ignored by this stub) + /// 搜索关键字(本桩忽略) / Search keyword (ignored by this stub) + /// 返回条数上限(本桩忽略) / Maximum number of results (ignored by this stub) + /// 取消令牌(本桩忽略) / Cancellation token (ignored by this stub) + /// 固定为空的目录条目集合 / An always-empty collection of directory entries public Task> SearchByNameAsync(long tenantId, long appId, string keyword, int limit, CancellationToken cancellationToken = default) { return Task.FromResult>(Array.Empty()); } - /// + /// + /// 按玩家标识批量解析目录条目;本桩不接任何目录数据,固定返回空集合。 + /// + /// + /// Resolves directory entries by player identifiers; this stub has no directory data and always returns an empty collection. + /// + /// 租户标识(本桩忽略) / Tenant identifier (ignored by this stub) + /// 应用标识(本桩忽略) / Application identifier (ignored by this stub) + /// 待解析的玩家标识集合(本桩忽略) / Player identifiers to resolve (ignored by this stub) + /// 取消令牌(本桩忽略) / Cancellation token (ignored by this stub) + /// 固定为空的目录条目集合 / An always-empty collection of directory entries public Task> FindAsync(long tenantId, long appId, IReadOnlyList playerIds, CancellationToken cancellationToken = default) { return Task.FromResult>(Array.Empty()); @@ -194,7 +215,15 @@ public Task> FindAsync(long tenantId, /// public sealed class NoopHotfixRollbackExecutor : IOnlineHotfixRollbackExecutor { - /// + /// + /// 执行热更回滚;本桩仅用于满足宿主服务依赖,测试不验证回滚效果,因此不做任何操作直接完成。 + /// + /// + /// Performs a hotfix rollback; this stub only satisfies the host service requirement and completes immediately without doing anything. + /// + /// 回滚目标版本(本桩忽略) / Target rollback version (ignored by this stub) + /// 取消令牌(本桩忽略) / Cancellation token (ignored by this stub) + /// 已完成的任务 / An already completed task public Task RollbackAsync(string targetVersion, CancellationToken cancellationToken = default) { return Task.CompletedTask; diff --git a/Tests/GameFrameX.Tests/Online/OnlineEventPublisherConsumerTests.cs b/Tests/GameFrameX.Tests/Online/OnlineEventPublisherConsumerTests.cs index fa8fa068d..154493f19 100644 --- a/Tests/GameFrameX.Tests/Online/OnlineEventPublisherConsumerTests.cs +++ b/Tests/GameFrameX.Tests/Online/OnlineEventPublisherConsumerTests.cs @@ -53,7 +53,15 @@ private sealed class RecordingCapabilityEventPublisher : ICapabilityEventPublish /// 已发布载荷(发布序,装箱原件)。 public readonly List Payloads = new(); - /// + /// + /// 记录一次机制事件发布:按发布顺序追加主题与载荷原件,不做任何分发,供测试断言委托口径。 + /// + /// + /// Records a mechanism event publication by appending the topic and the original payload in publish order, without dispatching. + /// + /// 事件载荷类型 / Event payload type + /// 事件主题,追加到 Topics / Event topic, appended to Topics + /// 事件载荷,装箱后追加到 Payloads / Event payload, boxed and appended to Payloads public void Publish(string topic, TEvent eventPayload) { Topics.Add(topic); diff --git a/Tests/GameFrameX.Tests/Online/OnlineGameDbStorePersistenceTests.cs b/Tests/GameFrameX.Tests/Online/OnlineGameDbStorePersistenceTests.cs index 1710808dc..0f53682f2 100644 --- a/Tests/GameFrameX.Tests/Online/OnlineGameDbStorePersistenceTests.cs +++ b/Tests/GameFrameX.Tests/Online/OnlineGameDbStorePersistenceTests.cs @@ -602,7 +602,15 @@ private static OnlinePlayerStorageEntry BuildEntry(OnlineStorageEntryKey key, by /// private sealed class NopEventPublisher : IOnlineEventPublisher { - /// + /// + /// 发布在线事件;本桩仅满足存储构造所需的事件出口,持久化测试不关心事件,因此直接丢弃并完成。 + /// + /// + /// Publishes an online event; this stub only satisfies the event sink dependency and discards the event, completing immediately. + /// + /// 待发布的在线事件(被丢弃) / Online event to publish (discarded) + /// 取消令牌(本桩忽略) / Cancellation token (ignored by this stub) + /// 已完成的任务 / An already completed task public Task PublishAsync(OnlineEvent onlineEvent, CancellationToken cancellationToken = default) { return Task.CompletedTask; diff --git a/Tests/GameFrameX.Tests/Online/OnlineMatchSettledLeaderboardProjectorTests.cs b/Tests/GameFrameX.Tests/Online/OnlineMatchSettledLeaderboardProjectorTests.cs index 86af1283f..1cdd50c13 100644 --- a/Tests/GameFrameX.Tests/Online/OnlineMatchSettledLeaderboardProjectorTests.cs +++ b/Tests/GameFrameX.Tests/Online/OnlineMatchSettledLeaderboardProjectorTests.cs @@ -350,13 +350,29 @@ private sealed class TickRoundRecorder : ICapabilitySchedulerObserver /// 最近一轮 tick 执行的 job 数(-1 = 尚未完成任何一轮)。 public int LastExecutedJobCount = -1; - /// + /// + /// 记录失败的调度 job:把 job 名追加到 FailedJobNames,供断言哪些 job 执行失败。 + /// + /// + /// Records a failed scheduler job by appending its name to FailedJobNames for assertions. + /// + /// job 类型(本桩忽略) / Job kind (ignored by this stub) + /// 失败的 job 名 / Name of the failed job + /// 失败异常(本桩忽略) / Failure exception (ignored by this stub) public void OnJobFailed(CapabilitySchedulerJobKind jobKind, string jobName, Exception exception) { FailedJobNames.Add(jobName); } - /// + /// + /// 记录一轮 tick 完成:保存本轮执行的 job 数到 LastExecutedJobCount,用于断言重投 job 是否已注册。 + /// + /// + /// Records a completed tick round by storing the executed job count in LastExecutedJobCount. + /// + /// 本轮耗时(本桩忽略) / Round elapsed time (ignored by this stub) + /// 本轮执行的 job 数 / Number of jobs executed in this round + /// 本轮失败的 job 数(本桩忽略) / Number of failed jobs in this round (ignored by this stub) public void OnTickRoundCompleted(TimeSpan elapsed, int executedJobCount, int failedJobCount) { LastExecutedJobCount = executedJobCount; diff --git a/Tests/GameFrameX.Tests/Online/OnlineMatchSettlementPipelineTests.cs b/Tests/GameFrameX.Tests/Online/OnlineMatchSettlementPipelineTests.cs index a7dad1dbf..8634f8272 100644 --- a/Tests/GameFrameX.Tests/Online/OnlineMatchSettlementPipelineTests.cs +++ b/Tests/GameFrameX.Tests/Online/OnlineMatchSettlementPipelineTests.cs @@ -367,31 +367,81 @@ public bool FailureEnabled set; } - /// + /// + /// 查询钱包账户;原样委托给内部真实存储,不受失败注入影响。 + /// + /// + /// Finds a wallet account by delegating to the inner real store; unaffected by failure injection. + /// + /// 租户标识 / Tenant identifier + /// 应用标识 / Application identifier + /// 玩家标识 / Player identifier + /// 货币标识 / Currency identifier + /// 取消令牌 / Cancellation token + /// 内部存储返回的钱包账户 / Wallet account returned by the inner store public Task FindWalletAsync(long tenantId, long appId, long playerId, string currencyId, CancellationToken cancellationToken = default) { return _inner.FindWalletAsync(tenantId, appId, playerId, currencyId, cancellationToken); } - /// + /// + /// 查询背包堆叠;原样委托给内部真实存储,不受失败注入影响。 + /// + /// + /// Finds an inventory stack by delegating to the inner real store; unaffected by failure injection. + /// + /// 租户标识 / Tenant identifier + /// 应用标识 / Application identifier + /// 玩家标识 / Player identifier + /// 物品标识 / Item identifier + /// 取消令牌 / Cancellation token + /// 内部存储返回的背包堆叠 / Inventory stack returned by the inner store public Task FindInventoryAsync(long tenantId, long appId, long playerId, string itemId, CancellationToken cancellationToken = default) { return _inner.FindInventoryAsync(tenantId, appId, playerId, itemId, cancellationToken); } - /// + /// + /// 列出玩家全部钱包账户;原样委托给内部真实存储。 + /// + /// + /// Lists all wallet accounts of the player by delegating to the inner real store. + /// + /// 租户标识 / Tenant identifier + /// 应用标识 / Application identifier + /// 玩家标识 / Player identifier + /// 取消令牌 / Cancellation token + /// 内部存储返回的钱包账户集合 / Wallet accounts returned by the inner store public Task> ListWalletAccountsAsync(long tenantId, long appId, long playerId, CancellationToken cancellationToken = default) { return _inner.ListWalletAccountsAsync(tenantId, appId, playerId, cancellationToken); } - /// + /// + /// 列出玩家全部背包堆叠;原样委托给内部真实存储。 + /// + /// + /// Lists all inventory stacks of the player by delegating to the inner real store. + /// + /// 租户标识 / Tenant identifier + /// 应用标识 / Application identifier + /// 玩家标识 / Player identifier + /// 取消令牌 / Cancellation token + /// 内部存储返回的背包堆叠集合 / Inventory stacks returned by the inner store public Task> ListInventoryStacksAsync(long tenantId, long appId, long playerId, CancellationToken cancellationToken = default) { return _inner.ListInventoryStacksAsync(tenantId, appId, playerId, cancellationToken); } - /// + /// + /// 应用资产变更批次;开启 FailureEnabled 时不触达内部存储,直接返回 InternalError 失败结果(无流水),否则委托给内部真实存储。 + /// + /// + /// Applies an asset change batch; when FailureEnabled is set it returns an injected InternalError failure with no ledger entries, otherwise delegates to the inner store. + /// + /// 资产变更批次 / Asset change batch + /// 取消令牌 / Cancellation token + /// 注入的失败结果或内部存储的应用结果 / Injected failure result or the inner store's apply result public Task ApplyAsync(OnlineAssetChangeBatch batch, CancellationToken cancellationToken = default) { if (FailureEnabled) @@ -402,25 +452,60 @@ public Task ApplyAsync(OnlineAssetChangeBatch batch, Can return _inner.ApplyAsync(batch, cancellationToken); } - /// + /// + /// 分页查询资产流水;原样委托给内部真实存储。 + /// + /// + /// Queries ledger entries page by page by delegating to the inner real store. + /// + /// 流水分页查询条件 / Ledger page query + /// 取消令牌 / Cancellation token + /// 内部存储返回的流水集合 / Ledger entries returned by the inner store public Task> ListLedgerEntriesAsync(OnlineLedgerPageQuery query, CancellationToken cancellationToken = default) { return _inner.ListLedgerEntriesAsync(query, cancellationToken); } - /// + /// + /// 按事务标识查询资产流水;原样委托给内部真实存储,供断言注入失败后未落流水。 + /// + /// + /// Finds ledger entries by transaction identifier by delegating to the inner real store. + /// + /// 事务标识 / Transaction identifier + /// 取消令牌 / Cancellation token + /// 内部存储返回的流水集合 / Ledger entries returned by the inner store public Task> FindLedgerEntriesByTransactionIdAsync(string transactionId, CancellationToken cancellationToken = default) { return _inner.FindLedgerEntriesByTransactionIdAsync(transactionId, cancellationToken); } - /// + /// + /// 按资产汇总玩家流水增量;原样委托给内部真实存储。 + /// + /// + /// Sums the player's ledger deltas per asset by delegating to the inner real store. + /// + /// 租户标识 / Tenant identifier + /// 应用标识 / Application identifier + /// 玩家标识 / Player identifier + /// 取消令牌 / Cancellation token + /// 资产标识到增量合计的映射 / Mapping from asset identifier to summed delta public Task> SumLedgerDeltasByAssetAsync(long tenantId, long appId, long playerId, CancellationToken cancellationToken = default) { return _inner.SumLedgerDeltasByAssetAsync(tenantId, appId, playerId, cancellationToken); } - /// + /// + /// 列出拥有资产记录的玩家标识;原样委托给内部真实存储。 + /// + /// + /// Lists player identifiers that have asset records by delegating to the inner real store. + /// + /// 租户标识 / Tenant identifier + /// 应用标识 / Application identifier + /// 取消令牌 / Cancellation token + /// 内部存储返回的玩家标识集合 / Player identifiers returned by the inner store public Task> ListPlayerIdsAsync(long tenantId, long appId, CancellationToken cancellationToken = default) { return _inner.ListPlayerIdsAsync(tenantId, appId, cancellationToken); diff --git a/Tests/GameFrameX.Tests/Online/OnlineSocialCapabilityPackageTests.cs b/Tests/GameFrameX.Tests/Online/OnlineSocialCapabilityPackageTests.cs index 01e0bf8a2..84a87275a 100644 --- a/Tests/GameFrameX.Tests/Online/OnlineSocialCapabilityPackageTests.cs +++ b/Tests/GameFrameX.Tests/Online/OnlineSocialCapabilityPackageTests.cs @@ -236,7 +236,15 @@ public RejectingModerationHook(string reason) _reason = reason; } - /// + /// + /// 审核聊天消息;本桩不看消息内容,始终以构造时给定的理由返回拒绝判定,用于验证拒绝路径。 + /// + /// + /// Moderates a chat message; this stub ignores the content and always returns a rejection verdict with the configured reason. + /// + /// 待审核的聊天消息(本桩忽略) / Chat message to moderate (ignored by this stub) + /// 取消令牌(本桩忽略) / Cancellation token (ignored by this stub) + /// 携带固定拒绝理由的拒绝判定 / Rejection verdict carrying the fixed reason public Task CheckAsync(OnlineChatMessage message, CancellationToken cancellationToken = default) { return Task.FromResult(OnlineChatModerationVerdict.Reject(_reason)); diff --git a/Tests/GameFrameX.Tests/Online/RockPaperScissorsMatchBridgeTests.cs b/Tests/GameFrameX.Tests/Online/RockPaperScissorsMatchBridgeTests.cs index 7146dc4cc..a07ee4b2c 100644 --- a/Tests/GameFrameX.Tests/Online/RockPaperScissorsMatchBridgeTests.cs +++ b/Tests/GameFrameX.Tests/Online/RockPaperScissorsMatchBridgeTests.cs @@ -377,7 +377,13 @@ public StubScopeProvider(OnlineScope scope) _scope = scope; } - /// + /// + /// 获取授权作用域;固定返回构造时注入的作用域。 + /// + /// + /// Gets the authorized scope; always returns the scope injected at construction. + /// + /// 构造时注入的授权作用域 / Authorized scope injected at construction public OnlineScope AuthorizedScope { get { return _scope; } @@ -422,7 +428,18 @@ private sealed class StubMatchBridge : IOnlineMatchGameBridge /// 最近一次提交出拳值。 public int LastSubmitGesture; - /// + /// + /// 开局桩:累加 StartCallCount 并记录作用域、房间、局号与玩家集合,固定返回成功的保密视图。 + /// + /// + /// Start stub: increments StartCallCount, records scope, room, round and players, and always returns a successful secret view. + /// + /// 授权作用域,记录到 LastStartScope / Authorized scope, recorded to LastStartScope + /// 房间标识,记录到 LastStartRoomId / Room identifier, recorded to LastStartRoomId + /// 局号,记录到 LastStartRound / Round number, recorded to LastStartRound + /// 玩家集合,记录到 LastStartPlayerIds / Player identifiers, recorded to LastStartPlayerIds + /// 取消令牌(本桩忽略) / Cancellation token (ignored by this stub) + /// 成功的保密对局视图 / Successful secret game view public Task> StartRoomGameAsync(OnlineScope scope, long roomId, int round, IReadOnlyList playerIds, CancellationToken cancellationToken = default) { StartCallCount++; @@ -433,7 +450,18 @@ public Task> StartRoomGameAsync(OnlineSc return Task.FromResult(OnlineResult.Ok(SecretView())); } - /// + /// + /// 出拳提交桩:累加 SubmitCallCount 并记录作用域、房间、局号与出拳值,返回 SubmitResult 工厂的结果(可注入失败或异常)。 + /// + /// + /// Submit stub: increments SubmitCallCount, records scope, room, round and gesture, and returns the result of the SubmitResult factory. + /// + /// 授权作用域,记录到 LastSubmitScope / Authorized scope, recorded to LastSubmitScope + /// 房间标识,记录到 LastSubmitRoomId / Room identifier, recorded to LastSubmitRoomId + /// 局号,记录到 LastSubmitRound / Round number, recorded to LastSubmitRound + /// 出拳值,记录到 LastSubmitGesture / Gesture value, recorded to LastSubmitGesture + /// 取消令牌(本桩忽略) / Cancellation token (ignored by this stub) + /// SubmitResult 工厂产出的结果 / Result produced by the SubmitResult factory public Task> SubmitGestureAsync(OnlineScope scope, long roomId, int round, int gesture, CancellationToken cancellationToken = default) { SubmitCallCount++; @@ -444,7 +472,17 @@ public Task> SubmitGestureAsync(OnlineSc return Task.FromResult(SubmitResult()); } - /// + /// + /// 查询对局信息桩:不记录调用,固定返回成功的保密视图。 + /// + /// + /// Game info stub: records nothing and always returns a successful secret view. + /// + /// 授权作用域(本桩忽略) / Authorized scope (ignored by this stub) + /// 房间标识(本桩忽略) / Room identifier (ignored by this stub) + /// 局号(本桩忽略) / Round number (ignored by this stub) + /// 取消令牌(本桩忽略) / Cancellation token (ignored by this stub) + /// 成功的保密对局视图 / Successful secret game view public Task> GetGameInfoAsync(OnlineScope scope, long roomId, int round, CancellationToken cancellationToken = default) { return Task.FromResult(OnlineResult.Ok(SecretView()));