# Function Library

`UCrowdToolkitLibrary` is the plugin's Blueprint function library. It provides one-node access
to the world's crowd actor, plus **bulk math nodes** that apply one operation over a whole
array of positions or transforms in a single C++ pass - replacing the Blueprint `ForEach`
loop (and its per-element node overhead) for the arrays the crowd getters return.

The canonical use is the render pipeline: `GetAgentPositions` → `PositionsToTransforms` →
`AddInstances`, with no loop in the graph.

!!!
The bulk nodes are **impure** (they have exec pins) on purpose. A pure node with an array
output re-runs once per connected pin, silently multiplying an O(n) pass. Always drive them
from the exec line. Inputs are never mutated - each node returns a **new** array.
!!!

## World access

==- GetCrowd
```cpp
static ACrowdToolkitActor* GetCrowd(const UObject* WorldContextObject);
```
The calling world's crowd actor. Resolves the world from the hidden **world-context pin**, so
there's no need to fetch the subsystem first - callable from any Blueprint. Returns null
outside game worlds. `BlueprintPure`.
===

## Position arrays

==- OffsetPositions
```cpp
static TArray<FVector> OffsetPositions(const TArray<FVector>& Positions, const FVector& Offset);
```
Each position + `Offset`.
===

==- TransformPositions
```cpp
static TArray<FVector> TransformPositions(const TArray<FVector>& Positions, const FTransform& Transform);
```
Each position run through `Transform` (scale, rotate, then translate) - e.g. local-to-world
through an actor's transform.
===

==- PositionsToTransforms
```cpp
static TArray<FTransform> PositionsToTransforms(
    const TArray<FVector>& Positions,
    const FVector& Offset,
    FRotator Rotation = FRotator(0,0,0),
    FVector  Scale    = FVector(1,1,1));
```
One transform per position: location = `position + Offset`, with the same `Rotation` and
`Scale` on every element. The one-call replacement for a "make a transform per point" loop
(instanced-mesh markers and the like).
===

==- GetPositionsCentroid
```cpp
static FVector GetPositionsCentroid(const TArray<FVector>& Positions);
```
Average of the positions (zero vector for an empty array) - e.g. a selection's centre point.
===

## Transform arrays

==- TransformsToPositions
```cpp
static TArray<FVector> TransformsToPositions(const TArray<FTransform>& Transforms);
```
Each transform's location, dropping rotation and scale.
===

==- OffsetTransforms
```cpp
static TArray<FTransform> OffsetTransforms(const TArray<FTransform>& Transforms, const FVector& Offset);
```
Each transform translated by `Offset` (rotation and scale untouched).
===

==- SetTransformsRotation
```cpp
static TArray<FTransform> SetTransformsRotation(const TArray<FTransform>& Transforms, const FRotator& Rotation);
```
Each transform with its rotation replaced by `Rotation`.
===

==- SetTransformsScale
```cpp
static TArray<FTransform> SetTransformsScale(const TArray<FTransform>& Transforms, FVector Scale = FVector(1,1,1));
```
Each transform with its scale replaced by `Scale`.
===

==- ComposeTransforms
```cpp
static TArray<FTransform> ComposeTransforms(const TArray<FTransform>& Transforms, const FTransform& Other);
```
Each transform composed with `Other` (`element * Other`) - every element re-expressed in
`Other`'s space. Pass an actor's world transform to move a whole local-space batch into the
world at once.
===

## Example: build instance transforms

The render pipeline with no Blueprint loop: read positions, turn them into transforms (lifted
to the mesh half-height), and add them as instances.

![Bulk render pipeline](../assets/api/fl-bulk.png)

==- C++
```cpp
// Lift every agent to its mesh half-height and render, no Blueprint loop.
TArray<FVector>    Positions  = Crowd->GetAgentPositions({});
TArray<FTransform> Transforms = UCrowdToolkitLibrary::PositionsToTransforms(
    Positions, FVector(0, 0, 88));
ISM->AddInstances(Transforms, /*bReturnIndices*/ false, /*bWorldSpace*/ true);
```
===
