Skip to content

Commit

Permalink
Merge pull request #223 from bhouston/registry-type-again
Browse files Browse the repository at this point in the history
Registry type again, adding scene profile to exec-graph & export-node-spec & graph-editor
  • Loading branch information
bhouston committed Jul 22, 2023
2 parents 27ec708 + 9282617 commit 674e129
Show file tree
Hide file tree
Showing 38 changed files with 349 additions and 368 deletions.
108 changes: 70 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ Another neat fact about behavior graphs is that they offer a sand boxed executio

## Documentation

* [Extending the Value System](/docs/Values.md)
* [Types Of Nodes](/docs/TypesOfNodes.md)
* [Abstractions and Drivers](/docs/Abstractions.md)
- [Extending the Value System](/docs/Values.md)
- [Types Of Nodes](/docs/TypesOfNodes.md)
- [Abstractions and Drivers](/docs/Abstractions.md)

## Community Resources

Expand All @@ -34,21 +34,21 @@ This library, while small, contains a nearly complete implementation of behavior

### Features

* **Customizable** While this library contains a lot of nodes, you do not have to expose all of them. For example, just because this supports for-loops and state, does not mean you have to register that node type as being available.
* **Type Safe** This library is implemented in TypeScript and fully makes use of its type safety features.
* **Small** This is a very small library with no external dependencies.
* **Simple** This library is implemented in a forward fashion without unnecessary complexity.
* **High Performance** Currently in performance testing, the library achieves over 2M node executions per second.
- **Customizable** While this library contains a lot of nodes, you do not have to expose all of them. For example, just because this supports for-loops and state, does not mean you have to register that node type as being available.
- **Type Safe** This library is implemented in TypeScript and fully makes use of its type safety features.
- **Small** This is a very small library with no external dependencies.
- **Simple** This library is implemented in a forward fashion without unnecessary complexity.
- **High Performance** Currently in performance testing, the library achieves over 2M node executions per second.

### Node Types

* **Events** You can implement arbitrary events that start execution: Start, Tick
* **Actions** You can implement actions that trigger animations, scene scene variations, or update internal state: Log
* **Logic** You can do arithmetic, trigonometry as well as vector operations and string manipulation: Add, Subtract, Multiply, Divide, Pow, Exp, Log, Log2, Log10, Min, Max, Round, Ceil, Floor, Sign, Abs, Trunc, Sqrt, Negate, And, Or, Not, ==, >, >=, <, <=, isNan, isInfinity, concat, includes.
* **Queries** You can query the state from the system.
* **Flow Control** Control execution flow using familiar structures: Branch, Delay, Debounce, Throttle, FlipFlop, Sequence, Gate, MultiGate, DoOnce, DoN, ForLoop
* **Variables** You can create, set and get variable values.
* **Custom Events** You can create, listen to and trigger custom events.
- **Events** You can implement arbitrary events that start execution: Start, Tick
- **Actions** You can implement actions that trigger animations, scene scene variations, or update internal state: Log
- **Logic** You can do arithmetic, trigonometry as well as vector operations and string manipulation: Add, Subtract, Multiply, Divide, Pow, Exp, Log, Log2, Log10, Min, Max, Round, Ceil, Floor, Sign, Abs, Trunc, Sqrt, Negate, And, Or, Not, ==, >, >=, <, <=, isNan, isInfinity, concat, includes.
- **Queries** You can query the state from the system.
- **Flow Control** Control execution flow using familiar structures: Branch, Delay, Debounce, Throttle, FlipFlop, Sequence, Gate, MultiGate, DoOnce, DoN, ForLoop
- **Variables** You can create, set and get variable values.
- **Custom Events** You can create, listen to and trigger custom events.

### Designed for Integration into Other Systems

Expand All @@ -75,7 +75,7 @@ The example behavior graphs are in the `/examples` folder. You can execute these
The main syntax is this one:

```zsh
npm run exec-graph ../../graphs/[examplename].json
npx exec-graph ./graphs/[examplename].json
```

Here are some example graphs in their native JSON form:
Expand All @@ -88,9 +88,13 @@ Print out the text "Hello World!" as soon as the graph starts up!

Console output:

```zsh
npm run exec-graph ../../graphs/core/HelloWorld.json
```sh
npx exec-graph ./graphs/core/HelloWorld.json
```

Console output:

```sh
Hello World!
```

Expand All @@ -102,9 +106,13 @@ In this example, we use set a variable and also listen to when it changes.

Console output:

```zsh
> npm run exec-graph ../../graphs/core/variables/Changed.json
```sh
npx exec-graph ./graphs/core/variables/Changed.json
```

Console output:

```sh
391
```

Expand All @@ -114,11 +122,15 @@ This example shows how to branching execution works. The "flow/branch" node has

[/graphs/core/flow/Branch.json](/graphs/core/flow/Branch.json)

Console output:
Command:

```zsh
> npm run exec-graph ../../graphs/core/flow/Branch.json
```sh
npx exec-graph ./graphs/core/flow/Branch.json
```

Console output:

```sh
Condition is false!
```

Expand All @@ -128,11 +140,15 @@ This shows how to create math formulas in logic nodes. In this case the equation

[/graphs/core/logic/Polynomial.json](/graphs/core/logic/Polynomial.json)

Console output:
Command:

```zsh
> npm run exec-graph ../../graphs/core/logic/Polynomial.json
```sh
npx exec-graph ./graphs/core/logic/Polynomial.json
```

Console output:

```sh
-9
```

Expand All @@ -142,11 +158,15 @@ Behave-Graph support asynchronous nodes. These are nodes which will continue exe

[/graphs/core/async/Delay.json](/graphs/core/async/Delay.json)

Console output:
Command:

```zsh
> npm run exec-graph ../../graphs/core/async/Delay.json
```sh
npx exec-graph ./graphs/core/async/Delay.json
```

Console output:

```sh
Waiting...
One Second Later!
```
Expand All @@ -157,11 +177,15 @@ Building upon waiting for downstream nodes to execute, you can also execute For

[/graphs/core/flow/ForLoop.json](/graphs/core/flow/ForLoop.json)

Console output:
Command:

```zsh
> npm run exec-graph ../../graphs/core/flow/ForLoop.json
```sh
npx exec-graph ./graphs/core/flow/ForLoop.json
```

Console output:

```sh
Starting For Loop...
Loop Body!
Loop Body!
Expand All @@ -184,9 +208,13 @@ You can register custom events, trigger then and listen on them.

Console output:

```zsh
> npm run exec-graph ../../graphs/core/events/CustomEvents.json
```sh
npx exec-graph ./graphs/core/events/CustomEvents.json
```

Console output:

```sh
myCustomEvent Fired!
myCustomEvent Fired!
myCustomEvent Fired!
Expand All @@ -200,11 +228,15 @@ Here is a test of 10,000,000 iteration for loop:

[/graphs/core/flow/PerformanceTest.json](/graphs/core/flow/PerformanceTest.json)

Here is the console output, when running with profiling (-p):
Here is the command running with verbose logging, e.g. "-l 0":

```zsh
> npm run exec-graph ../../graphs/core/flow/PerformanceTest.json -- -- -p
```sh
npx exec-graph ./graphs/core/flow/PerformanceTest.json -l 0
```

Console output:

```sh
Starting 10,000,000 iteration for-loop...
1,000,000 more iterations...
1,000,000 more iterations...
Expand All @@ -218,5 +250,5 @@ Starting 10,000,000 iteration for-loop...
1,000,000 more iterations...
Completed all iterations!

30000013 nodes executed in 2.98 seconds, at a rate of 10067118 steps/second
Profile Results: 30000014 nodes executed in 2.742 seconds, at a rate of 10940924 steps/second
```
2 changes: 1 addition & 1 deletion apps/exec-graph/bin/cli.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env node
#!/usr/bin/env node --enable-source-maps

import { main } from '../dist/index.js';

Expand Down
3 changes: 2 additions & 1 deletion apps/exec-graph/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"devDependencies": {},
"dependencies": {
"@behave-graph/core": "*"
"@behave-graph/core": "*",
"@behave-graph/scene": "*"
}
}
59 changes: 33 additions & 26 deletions apps/exec-graph/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import process from 'node:process';
import {
DefaultLogger,
Engine,
ILifecycleEventEmitter,
Logger,
LogLevel,
ManualLifecycleEventEmitter,
parseSafeFloat,
readGraphFromJSON,
registerCoreProfile,
validateGraph,
validateRegistry
} from '@behave-graph/core';
import { DummyScene, registerSceneProfile } from '@behave-graph/scene';
import { program } from 'commander';
import { createRequire } from 'module';

Expand All @@ -22,9 +25,8 @@ const { name, version } = packageInfo as { name: string; version: string };

type ProgramOptions = {
upgrade?: boolean;
trace?: boolean;
logLevel?: number;
dryRun?: boolean;
profile?: boolean;
iterations: string;
};

Expand All @@ -35,24 +37,28 @@ async function execGraph({
jsonPattern: string;
programOptions: ProgramOptions;
}) {
const lifecycleEventEmitter = new ManualLifecycleEventEmitter();
const logger = new DefaultLogger();
const registry = registerCoreProfile({
values: {},
nodes: {},
dependencies: {}
});
const registry = registerSceneProfile(
registerCoreProfile({
values: {},
nodes: {},
dependencies: {
ILogger: new DefaultLogger(),
ILifecycleEventEmitter: new ManualLifecycleEventEmitter(),
IScene: new DummyScene()
}
})
);

if (programOptions.logLevel) {
Logger.logLevel = programOptions.logLevel as LogLevel;
}

const graphJsonPath = jsonPattern;
Logger.verbose(`reading behavior graph: ${graphJsonPath}`);
const textFile = await fs.readFile(graphJsonPath);
const graph = readGraphFromJSON({
graphJson: JSON.parse(textFile.toString('utf8')),
...registry,
dependencies: {
logger,
lifecycleEventEmitter
}
registry
});
graph.name = graphJsonPath;

Expand All @@ -75,7 +81,8 @@ async function execGraph({
Logger.verbose('creating behavior graph');
const engine = new Engine(graph.nodes);

if (programOptions.trace) {
// do not log at all to the verbose if not verbose is not enabled, makes a big performance difference.
if (programOptions.logLevel === LogLevel.Verbose) {
engine.onNodeExecutionStart.addListener((node) =>
Logger.verbose(`<< ${node.description.typeName} >> START`)
);
Expand All @@ -88,6 +95,8 @@ async function execGraph({
return;
}

const lifecycleEventEmitter = registry.dependencies
.ILifecycleEventEmitter! as ILifecycleEventEmitter;
const startTime = Date.now();
if (lifecycleEventEmitter.startEvent.listenerCount > 0) {
Logger.verbose('triggering start event');
Expand Down Expand Up @@ -117,16 +126,14 @@ async function execGraph({
await engine.executeAllAsync(5);
}

if (programOptions.profile) {
const deltaTime = Date.now() - startTime;
Logger.info(
`\n Profile Results: ${engine.executionSteps} nodes executed in ${
deltaTime / 1000
} seconds, at a rate of ${Math.round(
(engine.executionSteps * 1000) / deltaTime
)} steps/second`
);
}
const deltaTime = Date.now() - startTime;
Logger.verbose(
`profile results: ${engine.executionSteps} nodes executed in ${
deltaTime / 1000
} seconds, at a rate of ${Math.round(
(engine.executionSteps * 1000) / deltaTime
)} steps/second`
);

engine.dispose();
}
Expand All @@ -136,7 +143,7 @@ export const main = async () => {
.name(name)
.version(version)
.argument('<filename>', 'path to the behavior-graph json to execute')
.option('-t, --trace', `trace node execution`)
.option('-l, --logLevel <logLevel>', `trace node execution`, '1')
.option('-p, --profile', `profile execution time`)
.option('-d, --dryRun', `do not run graph`)
.option(
Expand Down
2 changes: 1 addition & 1 deletion apps/export-node-spec/bin/cli.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env node
#!/usr/bin/env node --enable-source-maps

import { main } from '../dist/index.js';

Expand Down
1 change: 1 addition & 0 deletions apps/export-node-spec/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"devDependencies": {},
"dependencies": {
"@behave-graph/core": "*",
"@behave-graph/scene": "*",
"csv-stringify": "^6.2.1"
}
}
Loading

0 comments on commit 674e129

Please sign in to comment.