Install-Package BehaviourTree
https://www.youtube.com/watch?v=OeVo2l-O0vU
- Generic context
 - Extensible
 - Fluent Builder
 - Basic node types included
 - Tree visualizer (Coming soon)
 
var behaviourTree = FluentBuilder.Create<MyContext>()
    .Sequence("root")
        .Do("walk to door", WalkToDoorFunc)
        .Selector("open door sequence")
            .Do("open door", OpenDoorFunc)
            .Sequence("locked door sequence")
                .Do("unlock door", UnlockDoorFunc)
                .Do("open door", OpenDoorFunc)
            .End()
            .Do("smash door", SmashDoorFunc)
        .End()
        .Do("walk through door", WalkThroughDoorFunc)
        .Do("close door", CloseDoorFunc)
    .End()
    .Build();builder.Do("my-action", context => BehaviourStatus.Succeeded)builder.Wait("my-wait", 3000) // 3 secondsbuilder.Condition("my-condition", context => true)builder.Sequence("my-sequence")
    .Do("action1", context => BehaviourStatus.Succeeded)
    .Do("action2", context => BehaviourStatus.Succeeded)
    .Do("action3", context => BehaviourStatus.Succeeded)
    ...
.End()builder.Selector("my-selector")
    .Do("action1", context => BehaviourStatus.Failed)
    .Do("action2", context => BehaviourStatus.Succeeded)
    .Do("action3", context => BehaviourStatus.Succeeded)
    ...
.End()builder.RandomSequence("my-random-sequence")
    .Do("action1", context => BehaviourStatus.Succeeded)
    .Do("action2", context => BehaviourStatus.Succeeded)
    .Do("action3", context => BehaviourStatus.Succeeded)
    ...
.End()builder.RandomSelector("my-random-selector")
    .Do("action1", context => BehaviourStatus.Failed)
    .Do("action2", context => BehaviourStatus.Succeeded)
    .Do("action3", context => BehaviourStatus.Succeeded)
    ...
.End()builder.PrioritySequence("my-priority-sequence")
    .Do("action1", context => BehaviourStatus.Succeeded)
    .Do("action2", context => BehaviourStatus.Succeeded)
    .Do("action3", context => BehaviourStatus.Succeeded)
    ...
.End()builder.PrioritySelector("my-priority-selector")
    .Do("action1", context => BehaviourStatus.Failed)
    .Do("action2", context => BehaviourStatus.Succeeded)
    .Do("action3", context => BehaviourStatus.Succeeded)
    ...
.End()public enum SimpleParallelPolicy
{
    BothMustSucceed,
    OnlyOneMustSucceed
}
var policy = SimpleParallelPolicy.BothMustSucceed;
builder.SimpleParallel("my-parallel", policy)
    .Do("action1", context => BehaviourStatus.Running)
    .Do("action2", context => BehaviourStatus.Running)
.End()builder.Cooldown("my-cooldown", 4000) // 4 seconds
    .Do("action1", context => BehaviourStatus.Failed)
.End()builder.AlwaysFail("my-failer")
    .Do("action1", context => BehaviourStatus.Succeeded)
.End()builder.AlwaysSucceed("my-succeeder")
    .Do("action1", context => BehaviourStatus.Failed)
.End()builder.Invert("my-inverter")
    .Do("action1", context => BehaviourStatus.Failed)
.End()builder.LimitCallRate("my-rate-limiter", 1000) // 1 second
    .Do("action1", context => BehaviourStatus.Failed)
.End()builder.Repeat("my-repeater", 5)
    .Do("action1", context => BehaviourStatus.Failed)
.End()builder.TimeLimit("my-time-limit", 5000) // has 5 seconds to complete or will fail
    .Do("action1", context => BehaviourStatus.Running)
.End()builder.UntilSuccess("my-until-success")
    .Do("action1", context => BehaviourStatus.Failed)
.End()builder.UntilFailed("my-until-failed")
    .Do("action1", context => BehaviourStatus.Succeeded)
.End()builder.Random("my-random", 0.6) // will call child 60% of the time
    .Do("action1", context => BehaviourStatus.Succeeded)
.End()builder.SubTree("my-sub-tree", otherBehaviourTree)