### Basic FSM Setup and Usage Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/fsm.md Demonstrates how to define states, initialize the FSM with a blackboard, register states, start the FSM, and update it within the game loop. Requires importing FSM and Blackboard from '@rbxts/state-management'. ```typescript import { FSM, Blackboard } from "@rbxts/state-management"; // Define states by implementing IFSMState class IdleState implements FSM.IFSMState { OnEnter(bb: Blackboard) { print("Entering Idle State"); } Update(dt: number, bb: Blackboard) { // Idle logic } OnExit(bb: Blackboard) { print("Exiting Idle State"); } } class PatrolState implements FSM.IFSMState { OnEnter(bb: Blackboard) { print("Entering Patrol State"); } Update(dt: number, bb: Blackboard) { const currentWaypoint = bb.GetWild("currentWaypoint") ?? 0; // ... patrol movement logic } OnExit(bb: Blackboard) { print("Exiting Patrol State"); } } class AlertState implements FSM.IFSMState { OnEnter(bb: Blackboard) { print("Entering Alert State"); bb.SetWild("alertTime", 5.0); } Update(dt: number, bb: Blackboard) { const alertTime = bb.UpdateWild("alertTime", (current) => (current ?? 0) - dt); if (alertTime <= 0) bb.SetWild("alertFinished", true); } OnExit(bb: Blackboard) { bb.SetWild("alertFinished", false); } } const blackboard = new Blackboard({ enemySpotted: false }); const fsm = new FSM.FSM("Idle", blackboard); fsm.RegisterState("Idle", new IdleState()); fsm.RegisterState("Patrol", new PatrolState()); fsm.RegisterState("Alert", new AlertState()); fsm.Start(); // Game loop game.GetService("RunService").Heartbeat.Connect((dt) => { fsm.Update(dt); }); ``` -------------------------------- ### Install @rbxts/state-management Source: https://github.com/velover/state-management-package-rbxts/blob/master/README.md Install the state management package using npm or bun. ```bash npm install @rbxts/state-management # or bun add @rbxts/state-management ``` -------------------------------- ### Basic GOAP Agent Setup and Usage Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/goap.md Demonstrates the core setup of a GOAP agent, including WorldState, custom Actions, and Goals. The agent is updated on each frame using the Heartbeat service. ```typescript import { Goap, Blackboard } from "@rbxts/state-management"; interface WorldData { hasWeapon: boolean; enemyVisible: boolean; isSafe: boolean; } const worldState = new Goap.WorldState({ hasWeapon: false, enemyVisible: false, isSafe: true, }); class PickupWeaponAction extends Goap.Action { GetStaticEffects(_ws: Goap.WorldState) { return new Map([["hasWeapon", Goap.Effect.Set(true)]]); } GetStaticRequirements(_ws: Goap.WorldState) { return new Map([["isSafe", Goap.Comparison.Is()]]); } GetCost(_ws: Goap.WorldState) { return 1; } protected OnTick() { print("Picking up weapon..."); return Goap.EActionStatus.SUCCESS; } } class AttackEnemyAction extends Goap.Action { GetStaticEffects(_ws: Goap.WorldState) { return new Map() .set("enemyVisible", Goap.Effect.Set(false)) .set("isSafe", Goap.Effect.Set(true)); } GetStaticRequirements(_ws: Goap.WorldState) { return new Map() .set("hasWeapon", Goap.Comparison.Is()) .set("enemyVisible", Goap.Comparison.Is()); } GetCost(_ws: Goap.WorldState) { return 2; } protected OnTick() { print("Attacking enemy..."); return Goap.EActionStatus.SUCCESS; } } const combatGoal = new Goap.Goal("Combat", 10).AddRequirement( "enemyVisible", Goap.Comparison.IsNot(), ); const agent = new Goap.Agent( worldState, [new PickupWeaponAction(), new AttackEnemyAction()], [combatGoal], ); game.GetService("RunService").Heartbeat.Connect((dt) => { agent.Update(dt); }); ``` -------------------------------- ### Create and Run FSM Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Instantiate an FSM with a default state and a Blackboard, register all defined states, and then start the FSM. The FSM should be updated in the game loop. ```typescript const blackboard = new Blackboard({ enemySpotted: false }); const fsm = new FSM.FSM("Idle", blackboard); // Register all states fsm.RegisterState("Idle", new IdleState()); fsm.RegisterState("Patrol", new PatrolState()); fsm.RegisterState("Alert", new AlertState()); // Start the FSM (enters default state) fsm.Start(); // Run in game loop game.GetService("RunService").Heartbeat.Connect((dt) => { fsm.Update(dt); }); ``` -------------------------------- ### Action Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Action nodes run a callback function each tick. The callback should return SUCCESS, FAILURE, or RUNNING. ```typescript const moveAction = new BTree.Action((bb, dt) => { const target = bb.GetWild("targetPosition"); if (!target) return BTree.ENodeStatus.FAILURE; // Move toward target const distance = moveToward(target, dt); if (distance < 1) return BTree.ENodeStatus.SUCCESS; return BTree.ENodeStatus.RUNNING; }); ``` -------------------------------- ### IfThenElse Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt IfThenElse evaluates a condition once at the start and executes either the 'then' or 'else' branch based on the result. ```typescript // IfThenElse - evaluates condition once at start const ifThenElse = new BTree.IfThenElse() .AddChild(new BTree.Condition((bb) => bb.Get("energyLevel") > 50)) .AddChild(aggressiveBehavior) // then branch .AddChild(defensiveBehavior); // else branch ``` -------------------------------- ### Inverter Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Inverter swaps SUCCESS and FAILURE results of its child node. RUNNING results are passed through unchanged. ```typescript const notNearEnemy = new BTree.Inverter( new BTree.Condition((bb) => bb.Get("enemyNearby")) ); ``` -------------------------------- ### Repeat Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Repeat executes its child node a specified number of times. Configure when to repeat using ERepeatCondition. ```typescript const patrol5Times = new BTree.Repeat( patrolStep, 5, // repeat count BTree.ERepeatCondition.SUCCESS // only repeat on success ); // ERepeatCondition options: ALWAYS, SUCCESS, FAILURE ``` -------------------------------- ### Fallback Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Use Fallback to run children left-to-right, succeeding as soon as one child succeeds, and failing only if all children fail. ```typescript const fallback = new BTree.Fallback() .AddChild(new BTree.Condition((bb) => bb.Get("canFly"))) .AddChild(new BTree.Condition((bb) => bb.Get("canSwim"))) .AddChild(new BTree.Action((bb) => { print("Walking instead"); return BTree.ENodeStatus.SUCCESS; })); ``` -------------------------------- ### Building Behavior Trees with BTCreator in TypeScript Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Construct behavior trees at runtime by registering actions, conditions, and sub-trees, then loading a JSON definition. This example demonstrates setting up a combat tree. ```typescript import { BTCreator, Blackboard, BTree } from "@rbxts/state-management"; const blackboard = new Blackboard({ hasTarget: false, health: 100 }); const creator = new BTCreator(); // Register named actions creator.RegisterAction("AttackTarget", (bb, dt) => { print("Attacking target!"); bb.Set("hasTarget", false); return BTree.ENodeStatus.SUCCESS; }); creator.RegisterAction("Patrol", (bb, dt) => { print("Patrolling..."); return BTree.ENodeStatus.SUCCESS; }); // Register named conditions creator.RegisterCondition("HasTarget", (bb, dt) => { return bb.Get("hasTarget") === true; }); creator.RegisterCondition("HealthAbove50", (bb, dt) => { return bb.Get("health") > 50; }); // Register named callbacks (always SUCCESS) creator.RegisterCallback("LogState", (bb, dt) => { print(`Health: ${bb.Get("health")}, Target: ${bb.Get("hasTarget")}`); }); // Register sub-tree factories creator.RegisterSubTree("CombatTree", (bb) => { const root = new BTree.Sequence() .AddChild(new BTree.Condition((b) => b.Get("hasTarget"))) .AddChild(new BTree.Action((b) => BTree.ENodeStatus.SUCCESS)); return new BTree.BehaviorTree(root, bb); }); // Load JSON and build tree const jsonString = `{ ... }`; // JSON as shown above creator.LoadData(jsonString); // Throws if invalid const tree = creator.Build(blackboard); // Run the tree game.GetService("RunService").Heartbeat.Connect((dt) => { tree.Tick(dt); }); ``` -------------------------------- ### Switch Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Switch selects a child to execute based on the string value of a specified blackboard key. Default case is executed if no matching case is found. ```typescript const weaponSwitch = new BTree.Switch("currentWeapon") .Case("sword", swordCombatTree) .Case("bow", bowCombatTree) .Case("staff", magicCombatTree) .Default(unarmedCombatTree); ``` -------------------------------- ### TryCatch Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt The TryCatch node runs the 'try' branch. If it fails, it runs the 'catch' branch. The 'finally' branch is always executed if provided. ```typescript const tryCatch = new BTree.TryCatch() .AddChild(riskyOperation) // try .AddChild(errorHandler) // catch .AddChild(cleanupAction); // finally (optional) ``` -------------------------------- ### Build Basic Behavior Tree Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Construct a hierarchical Behavior Tree (BTree) for AI decision-making. This example demonstrates creating a tree that attempts to attack, find a target, or rest based on conditions and actions. ```typescript import { BTree, Blackboard } from "@rbxts/state-management"; const blackboard = new Blackboard({ hasTarget: false, energyLevel: 100, }); // Build a tree that tries to attack, otherwise finds targets, otherwise rests const findTargetSequence = new BTree.Sequence() .AddChild(new BTree.Condition((bb) => bb.Get("energyLevel") > 20)) .AddChild( new BTree.Action((bb) => { if (math.random() > 0.7) { bb.Set("hasTarget", true); return BTree.ENodeStatus.SUCCESS; } return BTree.ENodeStatus.FAILURE; }), ); const attackSequence = new BTree.Sequence() .AddChild(new BTree.Condition((bb) => bb.Get("hasTarget") === true)) .AddChild( new BTree.Cooldown( new BTree.Action((bb) => { bb.Set("energyLevel", bb.Get("energyLevel") - 10); bb.Set("hasTarget", false); return BTree.ENodeStatus.SUCCESS; }), 2.0, // 2 second cooldown between attacks ), ); const restAction = new BTree.Action((bb) => { bb.Set("energyLevel", bb.Get("energyLevel") + 1); return BTree.ENodeStatus.SUCCESS; }); const root = new BTree.Fallback() .AddChild(attackSequence) .AddChild(findTargetSequence) .AddChild(restAction); const tree = new BTree.BehaviorTree(root, blackboard); // Tick the tree in game loop game.GetService("RunService").Heartbeat.Connect((dt) => { const status = tree.Tick(dt); print(`Tree status: ${status}`); }); ``` -------------------------------- ### Callback Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Callback nodes execute a void callback function and always return SUCCESS. Useful for logging or side effects. ```typescript const logCallback = new BTree.Callback((bb, dt) => { bb.SetWild("lastUpdateTime", tick()); print("State logged at", tick()); }); ``` -------------------------------- ### Manage Wild Keys in Blackboard Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/blackboard.md Shows how to use wild keys for storing arbitrary, untyped data. Useful for dynamic or less structured information. Includes setting, getting with fallbacks, and updating. ```typescript // Set a wild key blackboard.SetWild("lastKnownPosition", new Vector3(10, 0, 5)); // Get a wild key (returns T | undefined) const pos = blackboard.GetWild("lastKnownPosition"); // Get with a default fallback const pos2 = blackboard.GetWildOrDefault("lastKnownPosition", new Vector3(0, 0, 0)); // Update a wild key with a callback const newHealth = blackboard.UpdateWild("health", (current) => (current ?? 100) - 10); print(newHealth); // 80 // Check existence and delete blackboard.HasWild("lastKnownPosition"); // true blackboard.DeleteWild("lastKnownPosition"); ``` -------------------------------- ### Switch Node Example Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md A Switch node selects and executes a child based on the value of a specified blackboard key. It allows defining specific behaviors for different key values and a default behavior. ```typescript new BTree.Switch("currentWeapon") .Case("sword", swordBehavior) .Case("bow", bowBehavior) .Default(unarmedBehavior); ``` -------------------------------- ### Condition Node Examples Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Condition nodes check a boolean predicate. They return SUCCESS if the predicate is true and FAILURE if false. ```typescript const hasTargetCondition = new BTree.Condition((bb, dt) => { return bb.Get("hasTarget") === true; }); const healthAbove50 = new BTree.Condition((bb) => { return (bb.GetWild("health") ?? 0) > 50; }); ``` -------------------------------- ### Switch Node Configuration in Behavior Tree JSON Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Example JSON structure for a Switch node in a Behavior Tree. This node allows branching logic based on a parameter's value. ```json { "name": "Switch", "children": [], "switch_case": { "parameter_name": "currentWeapon", "cases": { "sword": "sword_behavior_id", "bow": "bow_behavior_id", "staff": "staff_behavior_id" }, "default": "unarmed_behavior_id" } } ``` -------------------------------- ### Sequence Node Example Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md A Sequence node executes its children from left to right. It fails immediately if any child fails, and succeeds only if all children succeed. Requires at least two child nodes. ```typescript new BTree.Sequence().AddChild(conditionNode).AddChild(actionNode); ``` -------------------------------- ### WaitGate Leaf Node Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Similar to Wait, but returns FAILURE until the duration elapses, then returns SUCCESS. It does not return RUNNING. This example waits for 1 second. ```typescript new BTree.WaitGate(1.0); ``` -------------------------------- ### Parallel Node Example Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md A Parallel node runs all its children simultaneously each tick. It supports different policies for determining the overall success or failure based on child outcomes. ```typescript new BTree.Parallel( BTree.EParallelPolicy.ONE, // succeed when ONE child succeeds BTree.EParallelPolicy.ALL, // fail when ALL children fail ) .AddChild(monitorNode) .AddChild(actionNode); ``` -------------------------------- ### KeepRunningUntilSuccess and KeepRunningUntilFailure Node Examples Source: https://context7.com/velover/state-management-package-rbxts/llms.txt KeepRunningUntilSuccess retries a child until it succeeds, with an optional maximum attempt count. KeepRunningUntilFailure retries until the child fails. ```typescript // Keep trying until success (max 5 attempts) const retryUntilWin = new BTree.KeepRunningUntilSuccess(unreliableAction, 5); // Keep monitoring until failure (unlimited attempts) const monitorForever = new BTree.KeepRunningUntilFailure(monitorAction, -1); ``` -------------------------------- ### ForceSuccess and ForceFailure Node Examples Source: https://context7.com/velover/state-management-package-rbxts/llms.txt ForceSuccess and ForceFailure override the child's result to always be SUCCESS or FAILURE, respectively, unless the child returns RUNNING. ```typescript const alwaysSucceed = new BTree.ForceSuccess(unreliableAction); const alwaysFail = new BTree.ForceFailure(successfulAction); ``` -------------------------------- ### WhileDoElse Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt WhileDoElse re-evaluates its condition every tick. It executes the 'while' branch as long as the condition is true, and the 'else' branch when false. ```typescript // WhileDoElse - re-evaluates condition every tick const whileDoElse = new BTree.WhileDoElse() .AddChild(new BTree.Condition((bb) => bb.GetWild("onDuty") ?? true)) .AddChild(patrolBehavior) // while condition is true .AddChild(restBehavior); // while condition is false ``` -------------------------------- ### Build ReactiveSequence and MemorySequence Nodes Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Implement Sequence nodes for Behavior Trees. ReactiveSequence re-evaluates all children from the start on each tick, while MemorySequence resumes execution from the last running child. ```typescript // ReactiveSequence - restarts from first child each tick const reactiveSeq = new BTree.ReactiveSequence() .AddChild(new BTree.Condition((bb) => bb.Get("stillValid"))) .AddChild(longRunningAction); // MemorySequence - continues from last running child const memorySeq = new BTree.MemorySequence() .AddChild(new BTree.Wait(1.0)) .AddChild(new BTree.Wait(2.0)) .AddChild(new BTree.Wait(3.0)); ``` -------------------------------- ### FSM Connector for Behavior Trees Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Integrates a Finite State Machine (FSM) as a node within a behavior tree. The FSM is started on OnStart, ticked on OnTick, and halted on OnHalt of the behavior tree node. ```typescript const fsmConnector = new BTree.FSMConnector(guardFSM); new BTree.Sequence() .AddChild(new BTree.Condition((bb) => bb.Get("shouldActivateGuard"))) .AddChild(fsmConnector); ``` -------------------------------- ### GOAP Action with Conditional Requirements and Effects Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/goap.md An example of a GOAP action demonstrating dynamic requirements based on world state and effects that modify the world state. The `GetStaticRequirements` and `GetStaticEffects` methods can use the provided `WorldState` to adapt. ```typescript class ConditionalAction extends Goap.Action { GetStaticRequirements(ws: Goap.WorldState) { const reqs = new Map(); reqs.set("hasAmmo", Goap.Comparison.GreaterThan(0)); if (ws.GetWild("isNight")) { reqs.set("hasTorch", Goap.Comparison.Is()); } return reqs; } GetStaticEffects(ws: Goap.WorldState) { return new Map([["ammoUsed", Goap.Effect.Increment(1)]]); } GetCost(_ws: Goap.WorldState) { return 1; } protected OnTick() { return Goap.EActionStatus.SUCCESS; } } ``` -------------------------------- ### Action Leaf Node Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Runs a callback function on each tick while the node is active. The callback should return SUCCESS, FAILURE, or RUNNING. This example always returns SUCCESS. ```typescript new BTree.Action((bb, dt) => { // return SUCCESS, FAILURE, or RUNNING return BTree.ENodeStatus.SUCCESS; }); ``` -------------------------------- ### Callback Leaf Node Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Executes a void callback function and always returns SUCCESS. This example sets a blackboard entry 'lastUpdateTime' to the current tick time. ```typescript new BTree.Callback((bb, dt) => { bb.SetWild("lastUpdateTime", tick()); }); ``` -------------------------------- ### IfThenElse Node Example Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md An IfThenElse node evaluates a condition and then executes either the 'then' branch (if the condition succeeds) or the 'else' branch (if the condition fails). It requires at least two children. ```typescript new BTree.IfThenElse() .AddChild(new BTree.Condition((bb) => bb.Get("energyLevel") > 50)) .AddChild(aggressiveBehavior) .AddChild(defensiveBehavior); ``` -------------------------------- ### ForceSuccess and ForceFailure Decorator Examples Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md ForceSuccess ensures a node always returns SUCCESS (unless it's RUNNING), while ForceFailure ensures it always returns FAILURE (unless RUNNING). These decorators override the child's actual outcome. ```typescript new BTree.ForceSuccess(actionThatMightFail); new BTree.ForceFailure(actionThatMightSucceed); ``` -------------------------------- ### Fallback Node Example Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md A Fallback node executes its children from left to right. It succeeds as soon as any child succeeds, and fails only if all children fail. Useful for defining primary and alternative actions. ```typescript new BTree.Fallback().AddChild(primaryAction).AddChild(fallbackAction); ``` -------------------------------- ### Dynamic Requirements and Effects in Goap Actions Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Define actions with requirements and effects that can change based on the world state at planning time. This example shows an action that requires ammo and an optional torch at night. ```typescript class ConditionalAction extends Goap.Action { GetStaticRequirements(ws: Goap.WorldState) { const reqs = new Map(); reqs.set("hasAmmo", Goap.Comparison.GreaterThan(0)); // Add extra requirement at night if (ws.GetWild("isNight")) { reqs.set("hasTorch", Goap.Comparison.Is()); } return reqs; } GetStaticEffects(ws: Goap.WorldState) { return new Map([ ["ammoUsed", Goap.Effect.Increment(1)] ]); } GetCost(ws: Goap.WorldState) { // Higher cost at night return ws.GetWild("isNight") ? 3 : 1; } protected OnTick() { return Goap.EActionStatus.SUCCESS; } } ``` -------------------------------- ### WhileDoElse Node Example Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md A WhileDoElse node repeatedly evaluates a condition each tick. It executes the 'do' branch as long as the condition succeeds and the 'else' branch when the condition fails. It requires at least two children. ```typescript new BTree.WhileDoElse() .AddChild(new BTree.Condition((bb) => bb.GetWild("onDuty") ?? true)) .AddChild(patrolBehavior) .AddChild(restBehavior); ``` -------------------------------- ### Create and Use Typed Blackboard Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/blackboard.md Demonstrates how to create a typed blackboard, set initial values, and retrieve them. Recommended for structured data. ```typescript import { Blackboard } from "@rbxts/state-management"; // Define a type for your blackboard data (optional but recommended) interface MyAgentBlackboard { health: number; target?: Instance; isAlert: boolean; } // Create a blackboard with initial data const blackboard = new Blackboard({ health: 100, isAlert: false, }); // Set and get typed values blackboard.Set("health", 90); const currentHealth = blackboard.Get("health"); // number print(currentHealth); // 90 // Update a typed value with a callback blackboard.Update("health", (current) => current - 10); ``` -------------------------------- ### TypeScript Behavior Tree Creator Usage Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/btcreator.md Demonstrates how to use BTCreator to build and run a Behavior Tree. Requires importing BTCreator, Blackboard, and BTree from '@rbxts/state-management'. ```typescript import { BTCreator, Blackboard, BTree } from "@rbxts/state-management"; const blackboard = new Blackboard({ hasTarget: false }); const creator = new BTCreator(); // Register named actions creator.RegisterAction("AttackTarget", (bb, dt) => { print("Attacking!"); return BTree.ENodeStatus.SUCCESS; }); // Register named conditions creator.RegisterCondition("HasTarget", (bb, dt) => { return bb.Get("hasTarget") === true; }); // Register named callbacks (always returns SUCCESS) creator.RegisterCallback("LogState", (bb, dt) => { print("State logged"); }); // Register a sub-tree factory creator.RegisterSubTree("CombatTree", (bb) => { const root = new BTree.Action((_b) => BTree.ENodeStatus.SUCCESS); return new BTree.BehaviorTree(root, bb); }); // Register a custom node type creator.AddNodeCreator("MyCustomNode", (c) => { const label = c.GetCurrentNodeParameter("label", "string"); return new BTree.Action((bb) => { print(label); return BTree.ENodeStatus.SUCCESS; }); }); // Load JSON and build creator.LoadData(jsonString); // throws if schema is invalid const tree = creator.Build(blackboard); game.GetService("RunService").Heartbeat.Connect((dt) => { tree.Tick(dt); }); ``` -------------------------------- ### Cooldown Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Cooldown enforces a cooldown period after the child node finishes execution. It returns FAILURE while on cooldown. ```typescript const attackWithCooldown = new BTree.Cooldown( attackAction, 2.0, // 2 second cooldown false // don't reset cooldown on halt ); ``` -------------------------------- ### Basic Behavior Tree Implementation Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Sets up a basic Behavior Tree with a root fallback node, sequences for attacking and finding targets, and actions. The tree ticks every frame using the Heartbeat service. ```typescript import { BTree, Blackboard } from "@rbxts/state-management"; const blackboard = new Blackboard({ hasTarget: false, energyLevel: 100, }); const findTargetSequence = new BTree.Sequence() .AddChild(new BTree.Condition((bb) => bb.Get("energyLevel") > 20)) .AddChild( new BTree.Action((bb) => { if (math.random() > 0.7) { bb.Set("hasTarget", true); return BTree.ENodeStatus.SUCCESS; } return BTree.ENodeStatus.FAILURE; }), ); const attackSequence = new BTree.Sequence() .AddChild(new BTree.Condition((bb) => bb.Get("hasTarget") === true)) .AddChild( new BTree.Cooldown( new BTree.Action((bb) => { bb.Set("energyLevel", bb.Get("energyLevel") - 10); bb.Set("hasTarget", false); return BTree.ENodeStatus.SUCCESS; }), 2.0, // 2 second cooldown ), ); const root = new BTree.Fallback() .AddChild(attackSequence) .AddChild(findTargetSequence) .AddChild( new BTree.Action((bb) => { bb.Set("energyLevel", bb.Get("energyLevel") + 1); return BTree.ENodeStatus.SUCCESS; }), ); const tree = new BTree.BehaviorTree(root, blackboard); game.GetService("RunService").Heartbeat.Connect((dt) => { tree.Tick(dt); }); ``` -------------------------------- ### Wait Leaf Node Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Waits for a specified duration. Returns RUNNING until the duration elapses, then returns SUCCESS. This example waits for 2 seconds. ```typescript new BTree.Wait(2.0); // 2 seconds ``` -------------------------------- ### Create and Run GOAP Agent (TypeScript) Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Initializes a GOAP agent with a world state, available actions, and goals. Configures the planning interval and runs the agent within the game loop using the Heartbeat event. ```typescript const worldState = new Goap.WorldState({ hasWeapon: false, enemyVisible: false, isSafe: true, ammoCount: 0, }); const agent = new Goap.Agent( worldState, [new PickupWeaponAction(), new AttackEnemyAction(), new ReloadAction()], [combatGoal, patrolGoal], ); // Configure planning interval agent.SetPlanningInterval(0.5); // Re-evaluate plan every 0.5 seconds // Run in game loop game.GetService("RunService").Heartbeat.Connect((dt) => { agent.Update(dt); // Debug info if (!agent.IsIdle()) { const currentGoal = agent.GetCurrentGoal(); const currentPlan = agent.GetCurrentPlan(); print(`Pursuing: ${currentGoal?.GetName()}, Plan steps: ${currentPlan?.size()}`); } }); ``` -------------------------------- ### FSM Event Transitions Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/fsm.md Sets up transitions that are triggered by specific events. These are useful for immediate responses to game events. Optional conditions can be added to further refine when the event transition occurs. ```typescript // Register the transition fsm.AddEventTransition("Idle", "Alert", "enemySighted", 1); fsm.AddEventTransition("Patrol", "Alert", "enemySighted", 1); // Optional condition fsm.AddEventTransition("Alert", "Flee", "damageTaken", 1, (bb) => { return (bb.GetWild("health") ?? 100) < 20; }); // Trigger the event fsm.HandleEvent("enemySighted"); ``` -------------------------------- ### OneShot Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt OneShot executes its child node once and caches the result. The cache can be reset when the node becomes inactive if the reset flag is true. ```typescript // Run expensive computation once, remember forever const cachedResult = new BTree.OneShot(expensiveComputation); // Reset cache when node becomes inactive const resettableOneShot = new BTree.OneShot(expensiveComputation, true); ``` -------------------------------- ### Timeout Node Example Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Timeout fails or succeeds a child node if it runs longer than the specified duration. Configure the behavior on timeout using ETimeoutBehavior. ```typescript const timedAction = new BTree.Timeout( longRunningSearch, 10.0, // 10 second timeout BTree.ETimeoutBehavior.FAILURE // return FAILURE on timeout ); ``` -------------------------------- ### Callback and Node Registration Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/btcreator.md Functions for registering custom actions, conditions, callbacks, sub-trees, and node creators. ```APIDOC ## RegisterAction ### Description Register an action callback. ### Method `RegisterAction(name, fn)` ### Parameters - **name** (string) - Required - The name of the action. - **fn** (function) - Required - The callback function for the action. ``` ```APIDOC ## RegisterCondition ### Description Register a condition callback. ### Method `RegisterCondition(name, fn)` ### Parameters - **name** (string) - Required - The name of the condition. - **fn** (function) - Required - The callback function for the condition. ``` ```APIDOC ## RegisterCallback ### Description Register a void callback. ### Method `RegisterCallback(name, fn)` ### Parameters - **name** (string) - Required - The name of the callback. - **fn** (function) - Required - The callback function. ``` ```APIDOC ## RegisterSubTree ### Description Register a sub-tree factory. ### Method `RegisterSubTree(name, fn)` ### Parameters - **name** (string) - Required - The name of the sub-tree. - **fn** (function) - Required - The factory function for the sub-tree. ``` ```APIDOC ## AddNodeCreator ### Description Register a custom node type. ### Method `AddNodeCreator(name, fn)` ### Parameters - **name** (string) - Required - The name of the custom node type. - **fn** (function) - Required - The creator function for the node. ``` -------------------------------- ### Define GOAP Goals (TypeScript) Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Illustrates creating different types of GOAP goals: static priority, combat, dynamic priority based on world state, and goals with weighted requirements. Ensure the goal name and priority are correctly set. ```typescript // Static priority goal const patrolGoal = new Goap.Goal("Patrol", 5) .AddRequirement("atWaypoint", Goap.Comparison.Is()); // Combat goal - eliminate visible enemies const combatGoal = new Goap.Goal("Combat", 10) .AddRequirement("enemyVisible", Goap.Comparison.IsNot()); // Dynamic priority goal - priority based on world state const survivalGoal = new Goap.Goal("Survival", (worldState, agent) => { const health = worldState.GetWild("health") ?? 100; return health < 30 ? 20 : 5; // High priority when low health }) .AddRequirement("isSafe", Goap.Comparison.Is()); // Weighted requirements affect planner heuristics const urgentGoal = new Goap.Goal("UrgentTask", 15) .AddRequirement("criticalKey", Goap.Comparison.Is(), 5); // weight: 5 ``` -------------------------------- ### Create WasEntryUpdated Node Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/Changelog/0-3-6.md Instantiate a WasEntryUpdated node to monitor changes in specified blackboard keys. Set skipFirst to true to avoid an initial false positive. ```typescript new BTree.WasEntryUpdated(["health", "target"], /* skipFirst */ true); ``` -------------------------------- ### Implement FullAction Node Source: https://context7.com/velover/state-management-package-rbxts/llms.txt FullAction is a convenience node that bundles all lifecycle callbacks into a single configuration object for complex actions. ```typescript const fullAction = new BTree.FullAction({ OnStart: (bb) => { print("Starting action"); return BTree.ENodeStatus.RUNNING; }, OnTick: (dt, bb) => { const progress = bb.UpdateWild("progress", (p) => (p ?? 0) + dt); if (progress >= 1.0) return BTree.ENodeStatus.SUCCESS; return BTree.ENodeStatus.RUNNING; }, OnHalt: (bb) => { print("Action halted"); }, OnSuccess: (bb) => { print("Action succeeded"); }, OnFailure: (bb) => { print("Action failed"); }, OnExit: (status, bb) => { print(`Action exited with ${status}`); }, OnBecameActivated: (bb) => { print("Node became active"); }, OnBecameInactive: (bb) => { print("Node became inactive"); }, }); ``` -------------------------------- ### Condition Leaf Node Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Evaluates a boolean predicate. Returns SUCCESS if the predicate is true, and FAILURE otherwise. This example checks if the blackboard entry 'hasTarget' is true. ```typescript new BTree.Condition((bb, dt) => bb.Get("hasTarget") === true); ``` -------------------------------- ### Inverter Decorator Example Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md The Inverter decorator swaps the SUCCESS and FAILURE results of its child node. RUNNING results are passed through unchanged. It wraps a single child node. ```typescript new BTree.Inverter(new BTree.Condition((bb) => bb.Get("enemyNearby"))); ``` -------------------------------- ### Create a Timer Node Source: https://context7.com/velover/state-management-package-rbxts/llms.txt The Timer node reads a blackboard key as a countdown and succeeds when the value reaches zero. ```typescript const alertTimer = new BTree.Timer<{ alertTimeLeft: number }>("alertTimeLeft"); ``` -------------------------------- ### Import State Management Modules Source: https://github.com/velover/state-management-package-rbxts/blob/master/README.md Import core modules like BTree, FSM, Goap, Blackboard, and BTCreator for use in your roblox-ts project. ```typescript import { BTree, FSM, Goap, Blackboard, BTCreator } from "@rbxts/state-management"; ``` -------------------------------- ### Create Plug Node with Fixed Status Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/Changelog/0-3-6.md Instantiate a Plug node to act as a placeholder, always returning a fixed status. Useful for development and testing. ```typescript new BTree.Plug(BTree.ENodeStatus.SUCCESS); // always SUCCESS (default) ``` ```typescript new BTree.Plug(BTree.ENodeStatus.FAILURE); ``` ```typescript new BTree.Plug(BTree.ENodeStatus.RUNNING); ``` -------------------------------- ### Define Hierarchical GOAP Goals (TypeScript) Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Shows how to create a composite GOAP goal that breaks down into a sequence of sub-goals. The 'isComposite' flag must be set to true, and sub-goals are added using AddSubGoal. ```typescript const survivalGoal = new Goap.Goal("Survival", 15, /* isComposite */ true) .AddSubGoal( new Goap.Goal("GetWeapon", 10) .AddRequirement("hasWeapon", Goap.Comparison.Is()) ) .AddSubGoal(combatGoal); ``` -------------------------------- ### Repeat Node Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Repeats a child node a specified number of times. The repeat condition can be set to ALWAYS, SUCCESS, or FAILURE. This example repeats a patrol step 5 times, only repeating on success. ```typescript new BTree.Repeat( patrolStep, 5, // repeat 5 times BTree.ERepeatCondition.SUCCESS, // only repeat on success ); ``` -------------------------------- ### Timeout Decorator Example Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md The Timeout decorator fails or succeeds a child node if it runs longer than a specified duration. It requires the node to execute, the duration, and the desired timeout behavior (FAILURE or SUCCESS). ```typescript new BTree.Timeout(longRunningNode, 10.0, BTree.ETimeoutBehavior.FAILURE); ``` -------------------------------- ### Create Fixed Status Plug Nodes Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Plug nodes always return a fixed status, useful for testing or stubbing behavior tree logic. ```typescript const alwaysSuccess = new BTree.Plug(BTree.ENodeStatus.SUCCESS); ``` ```typescript const alwaysFail = new BTree.Plug(BTree.ENodeStatus.FAILURE); ``` ```typescript const alwaysRunning = new BTree.Plug(BTree.ENodeStatus.RUNNING); ``` -------------------------------- ### State Management API Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/fsm.md This section covers the core API methods for interacting with the state management package. ```APIDOC ## RegisterState ### Description Register a state implementation with the FSM. ### Method `RegisterState` ### Parameters - **name** (string) - Required - The name of the state to register. - **state** (object) - Required - The state implementation. ### Request Example ```json { "name": "MyState", "state": { ... } } ``` ### Response (No specific response details provided in the source text) ``` ```APIDOC ## Start ### Description Start the FSM. This action will cause the FSM to enter its default state. ### Method `Start` ### Endpoint (Not applicable, this is a method call) ### Response (No specific response details provided in the source text) ``` ```APIDOC ## Stop ### Description Stop the FSM. This action will cause the FSM to exit its current state. ### Method `Stop` ### Endpoint (Not applicable, this is a method call) ### Response (No specific response details provided in the source text) ``` ```APIDOC ## Update ### Description Tick the FSM. This method checks for pending transitions and calls the `Update` method of the current state. ### Method `Update` ### Parameters - **dt** (number) - Required - The time delta since the last update. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## AddTransition ### Description Add a condition-based transition between two states. ### Method `AddTransition` ### Parameters - **from** (string) - Required - The name of the starting state. - **to** (string) - Required - The name of the target state. - **priority** (number) - Required - The priority of this transition. - **condition** (function) - Optional - A function that returns true if the transition should occur. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## AddAnyTransition ### Description Add a transition that can occur from any current state. ### Method `AddAnyTransition` ### Parameters - **to** (string) - Required - The name of the target state. - **priority** (number) - Required - The priority of this transition. - **condition** (function) - Optional - A function that returns true if the transition should occur. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## AddEventTransition ### Description Add a transition that is triggered by a specific event, from a specific state. ### Method `AddEventTransition` ### Parameters - **from** (string) - Required - The name of the starting state. - **to** (string) - Required - The name of the target state. - **event** (string) - Required - The name of the event that triggers the transition. - **priority** (number) - Required - The priority of this transition. - **condition** (function) - Optional - A function that returns true if the transition should occur. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## AddAnyEventTransition ### Description Add a global transition that is triggered by a specific event, from any state. ### Method `AddAnyEventTransition` ### Parameters - **to** (string) - Required - The name of the target state. - **event** (string) - Required - The name of the event that triggers the transition. - **priority** (number) - Required - The priority of this transition. - **condition** (function) - Optional - A function that returns true if the transition should occur. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## HandleEvent ### Description Fire an event, which will trigger any matching event-based transitions. ### Method `HandleEvent` ### Parameters - **event** (string) - Required - The name of the event to fire. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## ForceSetState ### Description Immediately switch the FSM to a specified state, bypassing normal transition logic. ### Method `ForceSetState` ### Parameters - **state** (string) - Required - The name of the state to switch to. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## BindOnEnter ### Description Bind a callback function that will be executed whenever the FSM enters any state. ### Method `BindOnEnter` ### Parameters - **fn** (function) - Required - The callback function to execute on state entry. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## BindOnExit ### Description Bind a callback function that will be executed whenever the FSM exits any state. ### Method `BindOnExit` ### Parameters - **fn** (function) - Required - The callback function to execute on state exit. ### Response (No specific response details provided in the source text) ``` ```APIDOC ## BindUpdate ### Description Bind a callback function that will be executed after each FSM update cycle. ### Method `BindUpdate` ### Parameters - **fn** (function) - Required - The callback function to execute after each update. ### Response (No specific response details provided in the source text) ``` -------------------------------- ### Custom Node Lifecycle Implementation Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/behavior-tree.md Extends BTree.Node by overriding lifecycle methods such as OnStart, OnTick, OnExit, OnHalt, OnBecameActivated, and OnBecameInactive. Use this to define custom node behavior within a behavior tree. ```typescript class CustomPatrolNode extends BTree.Node { protected OnStart(bb: Blackboard): BTree.ENodeStatus { bb.SetWild("patrolStartTime", tick()); return BTree.ENodeStatus.RUNNING; } protected OnTick(dt: number, bb: Blackboard): BTree.ENodeStatus { const elapsed = tick() - (bb.GetWild("patrolStartTime") ?? 0); return elapsed > 10 ? BTree.ENodeStatus.SUCCESS : BTree.ENodeStatus.RUNNING; } protected OnExit(status: BTree.ENodeStatus, bb: Blackboard): void { bb.SetWild("patrolEndTime", tick()); } protected OnHalt(bb: Blackboard): void { bb.SetWild("patrolInterrupted", true); } OnBecameActivated(bb: Blackboard): void { print("Patrol node became active"); } OnBecameInactive(bb: Blackboard): void { print("Patrol node became inactive"); } } ``` -------------------------------- ### FSM Any-State and Any-Event Transitions Source: https://github.com/velover/state-management-package-rbxts/blob/master/docs/fsm.md Allows transitions to be triggered from any currently active state. 'AddAnyTransition' uses conditions, while 'AddAnyEventTransition' is triggered by specific events. Useful for global interrupts or global event handling. ```typescript fsm.AddAnyTransition("Alert", 2, (bb) => { return bb.GetWild("emergencyAlert") === true; }); fsm.AddAnyEventTransition("Dead", "killed", 10); ``` -------------------------------- ### Blackboard Typed Data Storage Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Use the Blackboard to create a typed key-value store for sharing data between AI systems. It supports strongly-typed keys via generics and dynamic 'wild' keys. ```typescript import { Blackboard } from "@rbxts/state-management"; // Define typed blackboard schema interface AgentData { health: number; target?: Instance; isAlert: boolean; } // Create blackboard with initial values const blackboard = new Blackboard({ health: 100, isAlert: false, }); // Typed access - compile-time type checking blackboard.Set("health", 90); const currentHealth = blackboard.Get("health"); // number blackboard.Update("health", (current) => current - 10); // Wild (untyped) access - for dynamic data blackboard.SetWild("lastKnownPosition", new Vector3(10, 0, 5)); const pos = blackboard.GetWild("lastKnownPosition"); // Vector3 | undefined const posWithDefault = blackboard.GetWildOrDefault("lastKnownPosition", new Vector3(0, 0, 0)); // Update wild values with callbacks const newHealth = blackboard.UpdateWild("dynamicHealth", (current) => (current ?? 100) - 10); // Check existence and delete if (blackboard.HasWild("lastKnownPosition")) { blackboard.DeleteWild("lastKnownPosition"); } // Type-safe wild access with runtime checking const hp = blackboard.GetWildOfType("health", 0); // warns if wrong type const hpSafe = blackboard.GetOrDefaultWildOfType("health", 0, 100); // fallback on wrong type ``` -------------------------------- ### Create Wait and WaitGate Nodes Source: https://context7.com/velover/state-management-package-rbxts/llms.txt Use Wait for a duration before succeeding, and WaitGate to fail until a duration elapses. ```typescript const wait2Seconds = new BTree.Wait(2.0); const gate1Second = new BTree.WaitGate(1.0); ```