Skip to content

feat(godot): 添加协程扩展功能支持Mediator模式#30

Merged
GeWuYou merged 1 commit into
mainfrom
feature/godot-coroutine-mediator-extension
Feb 16, 2026
Merged

feat(godot): 添加协程扩展功能支持Mediator模式#30
GeWuYou merged 1 commit into
mainfrom
feature/godot-coroutine-mediator-extension

Conversation

@GeWuYou
Copy link
Copy Markdown
Owner

@GeWuYou GeWuYou commented Feb 16, 2026

  • 新增ContextAwareCoroutineExtensions类,提供IContextAware接口的协程扩展方法
  • 实现RunCommandCoroutine、RunQueryCoroutine和RunPublishCoroutine方法
  • 将原有CoroutineExtensions重命名为CoroutineNodeExtensions并迁移相关功能
  • 添加文件头版权信息到新的协程扩展类
  • 重构协程生命周期管理方法,包括RunCoroutine和CancelWith系列方法
  • 移除测试文件中关于日志行为的占位测试用例

Summary by Sourcery

Add context-aware coroutine extensions for Mediator integration and refine Godot coroutine lifecycle utilities.

New Features:

  • Introduce context-aware coroutine extension methods to run Mediator commands, queries, and notifications as coroutines.

Enhancements:

  • Rename and scope existing coroutine utilities to CoroutineNodeExtensions for Godot node-based lifecycle management.
  • Add license header and minor improvements to coroutine cancellation helpers using node liveness checks.

Tests:

  • Remove obsolete placeholder test for unimplemented logging behavior in Mediator advanced feature tests.

- 新增ContextAwareCoroutineExtensions类,提供IContextAware接口的协程扩展方法
- 实现RunCommandCoroutine、RunQueryCoroutine和RunPublishCoroutine方法
- 将原有CoroutineExtensions重命名为CoroutineNodeExtensions并迁移相关功能
- 添加文件头版权信息到新的协程扩展类
- 重构协程生命周期管理方法,包括RunCoroutine和CancelWith系列方法
- 移除测试文件中关于日志行为的占位测试用例
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Feb 16, 2026

Reviewer's Guide

Adds context-aware coroutine extensions to integrate Mediator-style commands/queries/notifications with Godot coroutines, refactors existing coroutine node extensions for clearer lifecycle management, and removes an obsolete logging-related test placeholder.

Sequence diagram for RunCommandCoroutine integration with Mediator and Godot coroutine timing

sequenceDiagram
    actor GodotNode
    participant ContextAware as IContextAware
    participant Mediator as MediatorPipeline
    participant TaskApi as TaskExtensions
    participant CoroutineNodeExtensions
    participant Timing

    GodotNode->>ContextAware: RunCommandCoroutine(command, segment, tag, cancellationToken)
    activate ContextAware

    ContextAware->>Mediator: SendCommandAsync(command, cancellationToken)
    activate Mediator
    Mediator-->>ContextAware: ValueTask
    deactivate Mediator

    ContextAware->>TaskApi: AsTask() on ValueTask
    activate TaskApi
    TaskApi-->>ContextAware: Task
    deactivate TaskApi

    ContextAware->>TaskApi: ToCoroutineEnumerator(Task)
    activate TaskApi
    TaskApi-->>ContextAware: IEnumerator IYieldInstruction
    deactivate TaskApi

    ContextAware->>CoroutineNodeExtensions: RunCoroutine(coroutineEnumerator, segment, tag)
    activate CoroutineNodeExtensions
    CoroutineNodeExtensions->>Timing: RunCoroutine(coroutineEnumerator, segment, tag)
    activate Timing
    Timing-->>CoroutineNodeExtensions: CoroutineHandle
    deactivate Timing

    CoroutineNodeExtensions-->>GodotNode: CoroutineHandle
    deactivate CoroutineNodeExtensions
    deactivate ContextAware
Loading

Sequence diagram for node-lifecycle-aware CancelWith coroutine wrapper

sequenceDiagram
    participant GameNode as Node
    participant Caller as CallerScript
    participant CoroutineNodeExtensions
    participant Timing

    Caller->>CoroutineNodeExtensions: CancelWith(coroutine, node)
    activate CoroutineNodeExtensions
    loop while Timing.IsNodeAlive(node) and coroutine.MoveNext()
        CoroutineNodeExtensions->>Timing: IsNodeAlive(node)
        Timing-->>CoroutineNodeExtensions: bool
        alt node alive
            CoroutineNodeExtensions->>CoroutineNodeExtensions: coroutine.MoveNext()
            CoroutineNodeExtensions-->>Caller: yield coroutine.Current
        else node destroyed
            note right of CoroutineNodeExtensions: break
        end
    end
    deactivate CoroutineNodeExtensions
Loading

Class diagram for new context-aware and node coroutine extensions

classDiagram
    direction LR

    class ContextAwareCoroutineExtensions {
        <<static>>
        +CoroutineHandle RunCommandCoroutine(IContextAware contextAware, ICommand command, Segment segment, string tag, CancellationToken cancellationToken)
        +CoroutineHandle RunCommandCoroutine~TResponse~(IContextAware contextAware, ICommand~TResponse~ command, Segment segment, string tag, CancellationToken cancellationToken)
        +CoroutineHandle RunQueryCoroutine~TResponse~(IContextAware contextAware, IQuery~TResponse~ query, Segment segment, string tag, CancellationToken cancellationToken)
        +CoroutineHandle RunPublishCoroutine(IContextAware contextAware, INotification notification, Segment segment, string tag, CancellationToken cancellationToken)
    }

    class CoroutineNodeExtensions {
        <<static>>
        +CoroutineHandle RunCoroutine(IEnumerator~IYieldInstruction~ coroutine, Segment segment, string tag)
        +IEnumerator~IYieldInstruction~ CancelWith(IEnumerator~IYieldInstruction~ coroutine, Node node)
        +IEnumerator~IYieldInstruction~ CancelWith(IEnumerator~IYieldInstruction~ coroutine, Node node1, Node node2)
        +IEnumerator~IYieldInstruction~ CancelWith(IEnumerator~IYieldInstruction~ coroutine, Node[] nodes)
        -bool AllNodesAlive(Node[] nodes)
    }

    class Timing {
        +static CoroutineHandle RunCoroutine(IEnumerator~IYieldInstruction~ coroutine, Segment segment, string tag)
        +static bool IsNodeAlive(Node node)
    }

    class IContextAware {
        <<interface>>
        +ValueTask SendCommandAsync(ICommand command, CancellationToken cancellationToken)
        +ValueTask~TResponse~ SendCommandAsync~TResponse~(ICommand~TResponse~ command, CancellationToken cancellationToken)
        +ValueTask~TResponse~ SendQueryAsync~TResponse~(IQuery~TResponse~ query, CancellationToken cancellationToken)
        +ValueTask PublishEventAsync(INotification notification, CancellationToken cancellationToken)
    }

    class ICommand {
        <<interface>>
    }

    class ICommandTResponse {
        <<interface>>
        ICommand~TResponse~
    }

    class IQueryTResponse {
        <<interface>>
        IQuery~TResponse~
    }

    class INotification {
        <<interface>>
    }

    class CoroutineHandle
    class IYieldInstruction
    class Node
    class Segment
    class CancellationToken
    class IEnumeratorIYieldInstruction {
        IEnumerator~IYieldInstruction~
    }

    ContextAwareCoroutineExtensions ..> IContextAware : extends
    ContextAwareCoroutineExtensions ..> ICommand
    ContextAwareCoroutineExtensions ..> ICommandTResponse
    ContextAwareCoroutineExtensions ..> IQueryTResponse
    ContextAwareCoroutineExtensions ..> INotification
    ContextAwareCoroutineExtensions ..> CoroutineHandle
    ContextAwareCoroutineExtensions ..> Segment
    ContextAwareCoroutineExtensions ..> CancellationToken
    ContextAwareCoroutineExtensions ..> CoroutineNodeExtensions : uses RunCoroutine

    CoroutineNodeExtensions ..> IEnumeratorIYieldInstruction
    CoroutineNodeExtensions ..> IYieldInstruction
    CoroutineNodeExtensions ..> CoroutineHandle
    CoroutineNodeExtensions ..> Segment
    CoroutineNodeExtensions ..> Node
    CoroutineNodeExtensions ..> Timing : uses

    Timing ..> CoroutineHandle
    Timing ..> IYieldInstruction
    Timing ..> Node

    IContextAware ..> ICommand
    IContextAware ..> ICommandTResponse
    IContextAware ..> IQueryTResponse
    IContextAware ..> INotification
Loading

File-Level Changes

Change Details Files
Introduce context-aware coroutine extensions that bridge Mediator operations into the coroutine system.
  • Add ContextAwareCoroutineExtensions static class under GFramework.Godot.coroutine.
  • Implement RunCommandCoroutine overloads for ICommand and ICommand using SendCommandAsync + ToCoroutineEnumerator + RunCoroutine.
  • Implement RunQueryCoroutine for IQuery using SendQueryAsync + ToCoroutineEnumerator + RunCoroutine.
  • Implement RunPublishCoroutine for INotification using PublishEventAsync + ToCoroutineEnumerator + RunCoroutine.
  • Wire in required namespaces for rules, coroutine utilities, and Mediator abstractions.
GFramework.Godot/coroutine/ContextAwareCoroutineExtensions.cs
Refactor and rename Godot coroutine node extensions for clearer API and lifecycle semantics.
  • Rename CoroutineExtensions to CoroutineNodeExtensions to better reflect its purpose.
  • Tighten XML comments wording and parameter descriptions for lifecycle-related extension methods.
  • Refactor CancelWith overloads to use a new Node[] extension AllNodesAlive instead of a private helper.
  • Change AllNodesAlive into an extension method on Node[] and simplify while-loop condition usage.
  • Normalize method signatures formatting without altering behavior for RunCoroutine and CancelWith overloads.
GFramework.Godot/coroutine/CoroutineNodeExtensions.cs
Clean up obsolete mediator advanced features test related to logging behavior.
  • Remove ignored placeholder test that asserted logging behavior was not yet implemented, keeping only meaningful validation tests.
GFramework.Core.Tests/mediator/MediatorAdvancedFeaturesTests.cs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@GeWuYou GeWuYou merged commit 7552337 into main Feb 16, 2026
6 checks passed
@GeWuYou GeWuYou deleted the feature/godot-coroutine-mediator-extension branch February 16, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant