Builtin Library
- ..
- .metadata278 B
- README.md9.0 KB
- init.luau47.2 KB
- inspector.luau471 B
README.md
Generator
A live procedural generator: it binds a .procGraph, plays the graph's
timeline and stands each of the graph's outputs in the scene as children of
the entity it is on. Change a param and the output is made again in place; in
edit and in play alike, nothing it makes is written to the world's source.
local graph = asset.create("procGraph", "crate") -- a box with a `size` input; edit its init.luau
local e = entity.spawn("crate")
e.component.add("Generator", { graph = graph })
e.component.get("Generator").params = { size = 2 }
Fields
| Field | What it does |
|---|---|
graph | The .procGraph it plays. |
params | Overrides for the graph's declared inputs, by name. |
output | One declared output to stand; empty, the default, stands every output. A graph of the call form stands what its io.output calls show (the ones the named output reaches, when one is named); an output it names that no io.output of the graph shows is shown by the Generator itself, under the output's name, the way an io.output of it would show it. A graph of the older node form stands each output it declares, one root each. |
playOn | What starts its clock in play mode: "auto" (default) plays a timeline with no end as soon as it binds and holds any other on its first frame; "load" plays on bind; "manual" waits for play(). In edit mode a Generator is not set to play, whatever playOn says: it shows the frame it is on until it is played. |
ending | "graph" (default) does what the timeline declares; "loop" plays the range round and round; "hold" plays it once and stays on its last frame. |
speed | How fast its clock runs: 1 (default) its own rate, 0 still, negative plays a timeline with an end backwards. |
diskCache | Whether the outputs the graph caches load from, and are written to, the world's disk cache. On by default. |
bakedSnapshot | The bundle an earlier engine stored with the scene for what the generator realized. In play it stands in place of cooking while the disk cache does not hold every output; the first commit that writes the disk cache for all of them clears it. Empty by default. |
cookBudgetMs | Milliseconds of cook work a frame before a cook yields to the next frame. 5 by default. |
Methods
play(), pause(), seek(seconds), seekFrame(frame), loop(), hold(),
setFps(fps), setRange(first, last) and setWallTime(on) drive its clock,
on every peer. getFrame(), getTime(), describeGraph() and playback()
read it; playback() also says what running the graph costs and how each
output is drawn: cost.cooks counts the cooks it presented and cost.cookMs
the CPU milliseconds they ran, the frames they waited out apart, for a graph of
the call form as for one of the node form. describeGraph() describes the graph
bound, of either form. cancelCook() stops a cook in flight and leaves the last
output standing. apply() swaps the generator for the asset it makes: the
frame being presented becomes a bundle, and an Asset component standing it
takes the Generator's place; for a graph of the call form, the bundle holds what
its io.output calls show, each under the name it was shown under. The
onFinished event fires when a range played once reaches its end.
A timeline that runs in real time (realTime = true) has an end when its graph
states frames beside it (g:timeline({ realTime = true, fps = 60, frames = 180 }))
or when setRange gives it one; with neither it runs on and never finishes.
When the playhead of one with an end reaches its last frame, ending applies as
it does to any timeline: "graph" loops where the graph declares loop and
otherwise holds on the last frame and fires onFinished once; "loop" plays it
again from the start, a fresh simulation each time, without firing it; "hold"
stays on the last frame. play() plays a held one again from its start.
playback().ends is whether the timeline has an end, and last is its last
frame. A real-time timeline begins again, by seek(0), a loop or play(), in
the runs its solvers hold on the device: a restart costs a rewrite like any
other present, and opens no cook.
What it cooks again
A Generator cooks again, in edit mode and in play alike, when its graph's source is
edited, when its graph, params, output or diskCache change, and when anything
its graph was built from changes: a node the graph reaches (edited, or no longer
loading), a module the graph or one of those nodes requires while it builds, or a file
their builds read (vfs.read in a node or graph source, proc.read in a module they
call). A Generator that does not reach the change cooks nothing for it. Every node of
one cook is built from one version of each module and file.
A graph that does not build (its source, or a node it calls, raises while it is built)
leaves what the Generator stands standing: playback().error says why, the cook
history holds a cook of target source closed failed with the error, and once what
it failed on is fixed the Generator cooks again on its own.
What playback() answers
One table, typed PlaybackState. The tables in it keyed by name are maps,
read with pairs, never ipairs:
for output, d in pairs(generator:playback().drawn) do
print(output, d.as, d.count) -- "instances" or "entities", and how many
end
| Field | What it holds |
|---|---|
playing, heldByPause, held, realTime, wallTime | The clock's state: running, held by a pause, held at the end of its range, a real-time timeline, wall time on. |
frame, time, first, last, frames, fps, loop, ends | Where the playhead stands and the range it plays; ends is whether the timeline has an end. |
cookedThrough | The last frame cooked ahead; reaching last means every frame is cooked. |
cooked, hits, steps, restarts, replacing | Node cooks, cache hits, solver steps, solver restarts, and outputs built again whose earlier state still stands. |
error, cookError | Why the graph's source does not load, and why its latest cook failed (led by the line of the call that failed, path:line: g.<call> failed: <why>), while they do. |
drawn | By output name: { as, count, because?, pieces? }, how the output's elements reach the screen. |
cost | { frames, frameMs, cooks, cookMs, devicePresents, deviceMs, memoPresents, framePresents, realizeMs, drainMs, rewriteMs }: frameMs + cookMs over frames is the script cost of a frame. |
nodes, ms | By node id: how many times each node cooked, and its milliseconds. |
placement, placementByGraph | By node id: where its cooks ran (runs "device", "cpu", "mixed" or "values"); and per node a graph used as a node stands as, the sums of its inner nodes. |
onDevice, offDevice, cpuNodes | Whether a new time is presented on the device, what holds it to cooking when it is not, and how many nodes run on the CPU every frame. |
heldFrames, notHeldFrames | Whether presents stand on the frames the engine holds, and why not. |
diskCache | By output name: { key, frames, static, complete, hits }, or { reason } where the cache is not used. |
cacheBytes, heaviestEntries | What the node cache holds, and its largest entries. |
call | For a graph in the call form, the report of its play. |
owner | The name the generator's device runs are held under. |
What stands while it cooks again
What a Generator stands stays standing while it cooks again, and a present replaces all of it at once: the shows a present makes stand together in the frame its cook finishes, and what they replace goes in that frame. So no frame stands nothing, and none stands part of one cook beside part of another. Each output stands once: a param set it cooked before shows that set's output again, and params set while a cook runs are cooked by the cook after it. A cook that fails, or is cancelled, leaves what stood standing.
Under an effect
An effect's play runs each graph of its entry on a Generator, a child of the
play's entity. effectRef:play(entry, opts) and the Effect component make
them and drive their clocks together, so a shot, an impact or a cast is a play
of an effect (guides { path = "systems/effects/documentation/visual-effects" }). The play's own
playback() adds its Generators' costs together.
Every play of one graph with the same params plays the frames the first one
cooked. A Generator of a graph with playOn = "manual" cooks every frame of the
timeline while it waits, and playback().cookedThrough reaching
playback().last says every frame is cooked.
Related
guides { path = "systems/procgen/documentation/procgen" }: graphs, ops, timelines, effects and the live generator in full.- The
procgentoolbox:spawn,adjust,apply,cancel,generators,cooks,framesandonPresentwork on generators by entity, andplayplays a graph on the preview stage.