Skip to main content

Builder

Stacks the parts of an AI and builds an Agent from them.

local agent = VluxyAI.new(model)
	:UseBrain(Stalker)
	:UsePathfinder(VluxyAI.Pathfinders.Navmesh.new({ AgentRadius = 2 }))
	:UseMover(VluxyAI.Movers.Humanoid.new(model))
	:AddSense(VluxyAI.Senses.Sight.new({ Range = 40 }))
	:Build()
	:Start()

Every method returns the builder. Builder:Build validates the definition and errors with the path of the first bad field. A builder makes one agent; call VluxyAI.new again for the next.

Functions​

new​

Builder.new(
entity: Model?--

The model the AI drives. Needs a PrimaryPart. Leave it out for a headless agent, whose mover holds the pivot (Record); name it with Builder:SetName.

) → Builder

UseBrain​

Builder.UseBrain(
self: Builder,
brain: Brain
) → Builder

UsePathfinder​

Builder.UsePathfinder(
self: Builder,
pathfinder: Pathfinder
) → Builder

UseMover​

Builder.UseMover(
self: Builder,
mover: Mover
) → Builder

UseDirect​

Builder.UseDirect(
self: Builder,
pathfinder: Pathfinder--

Answers whether the agent can walk straight at its target. Must not yield. Straight is made for it.

) → Builder

Walk straight at the target whenever the way is clear, and only plan when it is not. The navigator asks pathfinder every DirectInterval seconds; while it returns a path, the mover walks that line and nothing is planned. When it fails, or the agent stops making progress for DirectStuckTime seconds, the agent plans with the ordinary pathfinder, and after getting stuck it does not try straight again for DirectCooldown seconds. Tune those three in Builder:SetNavigation.

:UsePathfinder(VluxyAI.Pathfinders.Navmesh.new())
:UseDirect(VluxyAI.Pathfinders.Straight.new())

Needs a pathfinder and a mover. A labelled step (a door) is never on a direct line: a closed door blocks the check, so the plan that goes through the door takes over.

AddSense​

Builder.AddSense(
self: Builder,
sense: Sense
) → Builder

Adds a sense. Senses tick in the order they were added.

SetBlackboard​

Builder.SetBlackboard(
self: Builder,
values: Blackboard--

Initial blackboard values, deep-copied per agent.

) → Builder

SetData​

Builder.SetData(
self: Builder,
values: {[string]: any}--

Initial agent.Data, deep-copied per agent.

) → Builder

SetTick​

Builder.SetTick(
self: Builder,
seconds: number--

Seconds between ticks. Default 0.1.

) → Builder

SetNavigation​

Builder.SetNavigation(
self: Builder,
) → Builder

OnStep​

Builder.OnStep(
self: Builder,
label: string,--

The step Label this handles: "Door", "Ladder", "Vault".

handler: StepHandler | StepRegistration,--

Runs when a step with that label is reached; may yield. Return false when the step could not be taken. A whole registration, such as Doors.Step returns, is taken as it is.

options: OnStepOptions?--

How to find the instance for a step that lacks one. Overrides the registration's own Tag and Radius.

) → Builder

Types

​

interface OnStepOptions {
Tag: string?--

Find the door for a step that has no Instance: the nearest instance with this CollectionService tag within Radius of the step. Default none.

Radius: number?--

Studs. Default 8.

}

What the agent does at a labelled step. The navigator holds the mover there, reports Interacting, runs the handler in its own thread, and walks on when it returns. A graph link brings its Instance along; a navmesh PathfindingLink or modifier does not, so give Tag and the nearest tagged instance is looked up for it, and the handler is the same for both.

:OnStep("Door", function(agent, step)
	if step.Instance:GetAttribute("Locked") then
		return false, 15 -- go another way for a while
	end
	Doors.Open(step.Instance)
	task.wait(0.4)
	return true
end, { Tag = "VLUXYAI_DOOR" })

Or let Doors do all of that over your door script:

:OnStep("Door", VluxyAI.Doors.Step())

SetStrictBlackboard​

Builder.SetStrictBlackboard(
self: Builder,
enabled: boolean?--

Default true.

) → Builder

Development aid: the agent warns once for a blackboard read that looks like a typo of a key something has written (SeenTaget for SeenTarget). Nothing is typed; the check is by spelling, so a legitimate nil read of a real key stays quiet.

SetName​

Builder.SetName(
self: Builder,
name: string--

Used in warnings and errors. Default the entity's name.

) → Builder

GetDefinition​

Builder.GetDefinition(self: Builder) → AgentDefinition--

A shallow copy of what has been stacked so far.

For inspection, tests, or handing to VluxyAI.NewAgent later.

Validate​

Builder.Validate(self: Builder) → ()

Validates without building. Useful to check a content module in a test.

Errors

TypeDescription
stringThe path and problem of the first bad field.

Build​

Builder.Build(self: Builder) → Agent

Validates and builds the agent. The agent is not running; chain Agent:Start.

Errors

TypeDescription
stringThe path and problem of the first bad field, or the builder was already used.
Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "",
            "params": [
                {
                    "name": "entity",
                    "desc": "The model the AI drives. Needs a `PrimaryPart`. Leave it out for a headless agent, whose mover holds the pivot ([Record]); name it with [Builder:SetName].",
                    "lua_type": "Model?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 50,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "UseBrain",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "brain",
                    "desc": "",
                    "lua_type": "Brain"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 67,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "UsePathfinder",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "pathfinder",
                    "desc": "",
                    "lua_type": "Pathfinder"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 77,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "UseMover",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "mover",
                    "desc": "",
                    "lua_type": "Mover"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 87,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "UseDirect",
            "desc": "Walk straight at the target whenever the way is clear, and only plan when it is not. The\nnavigator asks `pathfinder` every `DirectInterval` seconds; while it returns a path, the mover\nwalks that line and nothing is planned. When it fails, or the agent stops making progress for\n`DirectStuckTime` seconds, the agent plans with the ordinary pathfinder, and after getting\nstuck it does not try straight again for `DirectCooldown` seconds. Tune those three in\n[Builder:SetNavigation].\n\n```lua\n:UsePathfinder(VluxyAI.Pathfinders.Navmesh.new())\n:UseDirect(VluxyAI.Pathfinders.Straight.new())\n```\n\nNeeds a pathfinder and a mover. A labelled step (a door) is never on a direct line: a closed\ndoor blocks the check, so the plan that goes through the door takes over.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "pathfinder",
                    "desc": "Answers whether the agent can walk straight at its target. Must not yield. [Straight] is made for it.",
                    "lua_type": "Pathfinder"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 112,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "AddSense",
            "desc": "Adds a sense. Senses tick in the order they were added.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "sense",
                    "desc": "",
                    "lua_type": "Sense"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 124,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "SetBlackboard",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "values",
                    "desc": "Initial blackboard values, deep-copied per agent.",
                    "lua_type": "Blackboard"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 136,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "SetData",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "values",
                    "desc": "Initial `agent.Data`, deep-copied per agent.",
                    "lua_type": "{ [string]: any }"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 146,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "SetTick",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "seconds",
                    "desc": "Seconds between ticks. Default `0.1`.",
                    "lua_type": "number"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 156,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "SetNavigation",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "options",
                    "desc": "",
                    "lua_type": "NavigationOptions"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 166,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "OnStep",
            "desc": "What the agent does at a labelled step. The navigator holds the mover there, reports\n`Interacting`, runs the handler in its own thread, and walks on when it returns. A graph\nlink brings its `Instance` along; a navmesh `PathfindingLink` or modifier does not, so give\n`Tag` and the nearest tagged instance is looked up for it, and the handler is the same for\nboth.\n\n```lua\n:OnStep(\"Door\", function(agent, step)\n\tif step.Instance:GetAttribute(\"Locked\") then\n\t\treturn false, 15 -- go another way for a while\n\tend\n\tDoors.Open(step.Instance)\n\ttask.wait(0.4)\n\treturn true\nend, { Tag = \"VLUXYAI_DOOR\" })\n```\n\nOr let [Doors] do all of that over your door script:\n\n```lua\n:OnStep(\"Door\", VluxyAI.Doors.Step())\n```",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "label",
                    "desc": "The step `Label` this handles: `\"Door\"`, `\"Ladder\"`, `\"Vault\"`.",
                    "lua_type": "string"
                },
                {
                    "name": "handler",
                    "desc": "Runs when a step with that label is reached; may yield. Return `false` when the step could not be taken. A whole registration, such as [Doors.Step] returns, is taken as it is.",
                    "lua_type": "StepHandler | StepRegistration"
                },
                {
                    "name": "options",
                    "desc": "How to find the instance for a step that lacks one. Overrides the registration's own `Tag` and `Radius`.",
                    "lua_type": "OnStepOptions?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 213,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "SetStrictBlackboard",
            "desc": "Development aid: the agent warns once for a blackboard read that looks like a typo of a key\nsomething has written (`SeenTaget` for `SeenTarget`). Nothing is typed; the check is by\nspelling, so a legitimate `nil` read of a real key stays quiet.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "enabled",
                    "desc": "Default `true`.",
                    "lua_type": "boolean?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 246,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "SetName",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                },
                {
                    "name": "name",
                    "desc": "Used in warnings and errors. Default the entity's name.",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 256,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "GetDefinition",
            "desc": "For inspection, tests, or handing to `VluxyAI.NewAgent` later.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "returns": [
                {
                    "desc": "A shallow copy of what has been stacked so far.",
                    "lua_type": "AgentDefinition"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 267,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "Validate",
            "desc": "Validates without building. Useful to check a content module in a test.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "returns": [],
            "function_type": "static",
            "errors": [
                {
                    "lua_type": "string",
                    "desc": "The path and problem of the first bad field."
                }
            ],
            "source": {
                "line": 284,
                "path": "lib/Builder.luau"
            }
        },
        {
            "name": "Build",
            "desc": "Validates and builds the agent. The agent is not running; chain [Agent:Start].",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "Builder"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Agent"
                }
            ],
            "function_type": "static",
            "errors": [
                {
                    "lua_type": "string",
                    "desc": "The path and problem of the first bad field, or the builder was already used."
                }
            ],
            "source": {
                "line": 295,
                "path": "lib/Builder.luau"
            }
        }
    ],
    "properties": [],
    "types": [
        {
            "name": "OnStepOptions",
            "desc": "",
            "fields": [
                {
                    "name": "Tag",
                    "lua_type": "string?",
                    "desc": "Find the door for a step that has no `Instance`: the nearest instance with this `CollectionService` tag within `Radius` of the step. Default none."
                },
                {
                    "name": "Radius",
                    "lua_type": "number?",
                    "desc": "Studs. Default `8`."
                }
            ],
            "source": {
                "line": 178,
                "path": "lib/Builder.luau"
            }
        }
    ],
    "name": "Builder",
    "desc": "Stacks the parts of an AI and builds an [Agent] from them.\n\n```lua\nlocal agent = VluxyAI.new(model)\n\t:UseBrain(Stalker)\n\t:UsePathfinder(VluxyAI.Pathfinders.Navmesh.new({ AgentRadius = 2 }))\n\t:UseMover(VluxyAI.Movers.Humanoid.new(model))\n\t:AddSense(VluxyAI.Senses.Sight.new({ Range = 40 }))\n\t:Build()\n\t:Start()\n```\n\nEvery method returns the builder. [Builder:Build] validates the definition and errors with the\npath of the first bad field. A builder makes one agent; call `VluxyAI.new` again for the next.",
    "source": {
        "line": 44,
        "path": "lib/Builder.luau"
    }
}