CsTrees 1.0.5

dotnet add package CsTrees --version 1.0.5
                    
NuGet\Install-Package CsTrees -Version 1.0.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CsTrees" Version="1.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CsTrees" Version="1.0.5" />
                    
Directory.Packages.props
<PackageReference Include="CsTrees" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CsTrees --version 1.0.5
                    
#r "nuget: CsTrees, 1.0.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CsTrees@1.0.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CsTrees&version=1.0.5
                    
Install as a Cake Addin
#tool nuget:?package=CsTrees&version=1.0.5
                    
Install as a Cake Tool

CsTrees NuGet Version

一个 .NET 行为树框架,基本设计复刻了 py_trees

特性

  • 复刻py_trees的节点类型和大部分API:Behaviours、Composites和Decorators
  • 基于C#改造的黑板系统:类型安全的键值对共享状态,访问控制的源生成器
  • 流式构建器:基于栈的声明式 API,支持黑板作用域嵌套,可继承的泛型 CRTP 基类
  • 行为源生成:通过 [GenerateTreeBuilderExtension] 自动生成扩展方法,或通过 IBehaviourCatalog 构建领域特定构建器
  • 扩展的显示:除了自带ASCII渲染以外,可按需扩展;构建中也可输出预览
  • 交班机制:柔性中断,循环调用 Handoff() 让树有序地完成在途补偿并释放资源

快速开始

直接构建行为树

using CsTrees;
using CsTrees.Composites;
using CsTrees.Behaviours;

var tree = new Selector("Root", children: new[]
{
    new Sequence("Check & Act", children: new[]
    {
        new Success("Condition Check"),
        new Success("Execute Action")
    }),
    new Failure("Fallback")
});

await tree.TickOnce();

流式构建器

using CsTrees.FluentBuilder;

var bb = new CsTrees.Blackboard.Blackboard();

var tree = new DefaultTreeBuilder()
    .Selector("Root")
        .Sequence("Check & Act")
            .WithBlackboard(bb)
                .MyCheck("Check")
                .MyBehaviour("Act")
            .End()
        .End()
        .Failure("Fallback")
    .End()
    .Build();

显示行为树

using CsTrees.Display;

string ascii = Display.AsciiTree(tree, showStatus: true, showFeedbackMessage: true);
Console.WriteLine(ascii);

经典节点类型

CsTrees 实现了 py_trees 的大多数节点类型,详细的节点说明请参阅 py_trees 文档

其他复刻的功能点也请翻阅仓库代码并和原版比对。

交班(Handoff)

托比欧(Doppio):不敢相信……居然在岸边找到公用电话……Boss,你在哪里?

Boss:我现在要去你那里,你保持好伪装不要引起他们的注意!

托比欧:我应该怎么做?Boss!

Boss:用「Handoff」!你至少把鱼竿收了……(鱼已上钩,而托比欧却面目呆滞、握着鱼竿愣在那里)

交班是一种全新设计的行为树语义。它从根出发去寻找 Running 的节点,并尝试运行预埋在行为树内的子树,来完成中断和收尾。

// 交班:反复调用直到根节点交接完毕
while (tree.Root.Status == Status.Running)
    await tree.Handoff();

经典节点的交班方式:

节点 交班行为
叶子 直接置为 Invalid
Sequence / Selector 仅解除当前运行的子树(CurrentChild),其余子树保持原状
Parallel 所有 Running 子树各推进一步,互不阻塞
Decorator 转发给被装饰节点,待其解除完毕后再作废自身

交班特化节点:Try 与 Always

新节点把补偿语义做进了 Handoff——交班过程中能推进必须跑完的清理工作。它们建立在 Mediator 基础设施之上(按命名槽位容纳子树的复合节点基类),目前已经实现了 TryAlways

Try(try/finally)

提供 try/finally 语义:先执行 try 子树,无论其成败,finally 子树必定随后执行;仅当两棵子树都成功时整体才成功。即使 try 已失败,finally 仍会运行。交班时先解除 body,再逐 tick 推进 finally 补偿子树。

var tree = new DefaultTreeBuilder()
    .Try("HandleRequest")
        .Success("Process")
    .Finally()
        .Success("Cleanup")
    .End()
    .Build();
Always(always/then)

Tick 采用无记忆语义:每轮都先执行 always 守卫子树,仅当其成功才执行 then 子树;守卫失败则整体立即失败。交班时若 then 仍在运行,须每轮重新通过守卫才推进 then 的解除。

var tree = new DefaultTreeBuilder()
    .Always("GuardedWork")
        .Success("CheckPermission")
    .Then()
        .Success("DoWork")
    .End()
    .Build();

黑板(Blackboard)

基本理念和 py_trees 黑板 相同。

CsTrees 的黑板并不是单例的,且没有采用Client的设计。
CsTrees 提供了两种方式与黑板交互:手动注册端口通过 [BlackboardKey] 特性自动生成

通过 [BlackboardKey] 特性声明端口(推荐)

partial 行为类上,使用 [BlackboardKey] 特性标记 BehaviourKeyAccess<T> 类型的属性即可。源生成器(CsTrees.SourceGenerator)会自动生成以下代码:

  • 带黑板参数的构造函数重载 — 自动注册所有端口,无需手动调用 GrantRead/GrantWrite
  • SetupPorts(Blackboard) 方法 — 手动注册端口(可选)

注意:TreeBuilder 扩展方法不会自动生成。需要额外标注 [GenerateTreeBuilderExtension] 特性才会生成(见下方说明)。

using CsTrees;
using CsTrees.Blackboard;
using CsTrees.FluentBuilder;
using System.Threading.Tasks;

[GenerateTreeBuilderExtension]
public partial class DetectButton : Behaviour
{
    [BlackboardKey("btn_x", Access = Access.Write)]
    public BehaviourKeyAccess<int> X { get; private set; } = null!;

    [BlackboardKey("btn_y", Access = Access.Write)]
    public BehaviourKeyAccess<int> Y { get; private set; } = null!;

    // 构造函数需为 private,源生成器会生成带 Blackboard 参数的 public 重载
    private DetectButton(string name) : base(name) { }

    protected override async Task<Status> Update()
    {
        X.Set(42);
        Y.Set(99);
        return Status.Success;
    }
}

[GenerateTreeBuilderExtension] 自动生成 TreeBuilder 扩展方法

在 Behaviour 子类上标注 [GenerateTreeBuilderExtension] 后,源生成器会为该类生成静态扩展方法类(如 DetectButtonBuilderExtensions),包含一个或多个扩展方法(对应每个 private 构造函数一个)。这些方法:

  • 接收 this TBuilder builderstring name 参数
  • 自动从构建器当前黑板作用域获取 Blackboard 并注入构造函数
  • 支持可选的端口 key 覆盖参数(如 xKey: "custom_x"
// 生成的扩展方法使用方式
var tree = new DefaultTreeBuilder()
    .Sequence("Pipeline")
        .WithBlackboard(bb)
            .DetectButton("检测按钮")  // SG 生成的扩展方法,bb 自动注入
        .End()
    .End()
    .Build();

使用建议:通用行为(如传感器检测、基础移动)使用 [GenerateTreeBuilderExtension] 生成全局扩展方法;业务预设行为通过 IBehaviourCatalog 构建领域构建器(见下方)。

手动注册端口

不依赖源生成器时,可以手动调用 GrantRead/GrantWrite/GrantExclusiveWrite

using CsTrees.Blackboard;

var bb = new Blackboard();

var readAccess = bb.GrantRead<int>(behaviour, "/sensor/value");
var writeAccess = bb.GrantWrite<string>(behaviour, "/actor/state");
var exclusiveAccess = bb.GrantExclusiveWrite<bool>(behaviour, "/locked");

// 在行为的 Update() 中
var value = readAccess.Get();
writeAccess.Set("active");
exclusiveAccess.Set(true);
readAccess.Unset();

流式构建器(TreeBuilder)

TreeBuilder 提供基于栈的声明式 API,是更流行的选择。

使用 DefaultTreeBuilder

DefaultTreeBuilder 是框架内置的构建器,内置三个 Catalog(CompositesCatalog、DecoratorsCatalog、DefaultBehavioursCatalog),涵盖了所有标准节点类型。大多数情况下直接使用即可:

var tree = new DefaultTreeBuilder()
    .Sequence("Root")
        .Retry("Attempt", numFailures: 3)
            .Success("Action")
        .End()
    .End()
    .Build();

配合黑板使用(推荐)

在大多数时刻我们只用到一块黑板,因此可以通过黑板作用域的设计来简化代码

通过 WithBlackboard() 为子节点注入黑板作用域。标注了 [GenerateTreeBuilderExtension] 的行为会生成 TreeBuilder 扩展方法,黑板会自动从当前作用域获取:

var bb = new Blackboard();

var tree = new DefaultTreeBuilder()
    .Selector("Root")
        .Sequence("Pipeline")
            .WithBlackboard(bb)
                // 利用源生成器生成的扩展方法,可以在 WithBlackboard 作用域内省略 bb 的显式注入
                .DetectButton("检测按钮")
                .MoveTo("移动到目标")
            .End()
        .End()
    .End()
    .Build();

预览

Preview() 方法可以在构建过程中随时预览当前的树结构:

var builder = new DefaultTreeBuilder()
    .Selector("Root")
        .Sequence("Part1")
            .Success("Step1");

// 预览当前状态(Part1 未闭合)
var preview = builder.Preview();
Console.WriteLine(Display.AsciiTree(preview));

// 继续构建
builder
    .Success("Step2")
    .End()
    .End()
    .Build();

继承 TreeBuilder 构建领域特定构建器

TreeBuilder 基于 CRTP 模式实现为泛型基类 TreeBuilder<TBuilder>,支持继承以创建领域特定的行为树构建器。

框架自带 DefaultTreeBuilder,内置了常用的 Composites、Decorators、Leaf 节点,直接可用。你也可以通过继承 TreeBuilder<TBuilder> 自定义领域构建器。

通过 IBehaviourCatalog 自动生成构建方法

源生成器会扫描 TreeBuilder<TBuilder> 子类中声明的私有 IBehaviourCatalog 类型字段或属性,自动为 Catalog 中的每个 public 工厂方法生成对应的 fluent 构建方法。

支持同时使用多个 Catalog,意味着你可以拼配构建器的能力。

// 1. 定义行为目录类
public class GameComposites : IBehaviourCatalog
{
    public Composite CombatSequence(string name, bool memory, IEnumerable<Behaviour> children)
        => new Composites.Sequence(name, memory, children);
}

public class GameBehaviours : IBehaviourCatalog
{
    public Behaviour MakePlayerIdle(string name) => new Idle(name);

    public Behaviour MakeCollectItem(string name, Blackboard bb)
        => new CollectItem(name, bb);
}

// 2. 定义领域构建器
public partial class GameBuilder : TreeBuilder<GameBuilder>
{
    private readonly CompositesCatalog compositesCatalog = new();
    private readonly DecoratorsCatalog decoratorsCatalog = new();
    private readonly GameComposites gameComposites = new();
    private readonly GameBehaviours gameBehaviours = new();
}

// 3. 使用
var tree = new GameBuilder()
    .CombatSequence("Gameplay")
        .Sequence("顺序执行", memory: true)
            .MakePlayerIdle("待机")
            .MakeCollectItem("拾取物品")
        .End()
    .End()
    .Build();

Catalog 工厂方法的参数规则:

  • 返回类型必须为 Behaviour 或其子类
  • 如果参数中包含 Blackboard 类型,生成的构建方法会自动注入当前作用域的黑板
  • 如果参数中包含 IEnumerable<Behaviour> 类型,会被识别为 Composite 的 children 参数
  • 如果参数中包含 Behaviour 类型,会被识别为 Decorator 的 child 参数(Mediator 工厂方法中则作为槽位参数,按声明顺序与 [MediatorSlots] 槽位配对)
  • 参数默认值会被保留到生成的方法签名中
  • 如果返回类型是 Mediator 子类,其必须标注 [MediatorSlots] 声明槽位名与顺序,源生成器才会为它生成构建方法与切槽方法

[GenerateTreeBuilderExtension]IBehaviourCatalog 是两种互补的代码生成路径:前者生成全局静态扩展方法,适合通用行为;后者生成实例方法挂在领域构建器上,适合业务预设。

扩展包

  • CsTrees.MEAI — 将 TreeBuilder 的 IBehaviourCatalog 工厂方法自动转换为 AI Agent 可调用的工具方法(配合 Microsoft.Extensions.AI 使用),让 LLM 能逐步构建和运行行为树。

许可证

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on CsTrees:

Package Downloads
CsTrees.MEAI

MEAI integration for CsTrees behaviour tree framework

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.5 266 9/9/2026
1.0.4 562 8/27/2026
1.0.3 264 8/23/2026
1.0.2 129 8/19/2026
1.0.1 786 8/9/2026
1.0.0 120 8/8/2026