Skip to content

Commit

Permalink
cleanup readme, simplify log output in exec-graph (add colors), and e…
Browse files Browse the repository at this point in the history
…nsure source maps work on cli apps.
  • Loading branch information
bhouston committed Jul 22, 2023
1 parent d020dc4 commit 2f325fd
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 49 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 profiling (-p):

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

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
15 changes: 12 additions & 3 deletions apps/exec-graph/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Engine,
ILifecycleEventEmitter,
Logger,
LogLevel,
ManualLifecycleEventEmitter,
parseSafeFloat,
readGraphFromJSON,
Expand All @@ -24,7 +25,7 @@ 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 @@ -49,6 +50,10 @@ async function execGraph({
})
);

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

const graphJsonPath = jsonPattern;
Logger.verbose(`reading behavior graph: ${graphJsonPath}`);
const textFile = await fs.readFile(graphJsonPath);
Expand Down Expand Up @@ -77,7 +82,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 @@ -99,6 +105,7 @@ async function execGraph({

Logger.verbose('executing all (async)');
await engine.executeAllAsync(5);
Logger.verbose(' completed');
}

if (lifecycleEventEmitter.tickEvent.listenerCount > 0) {
Expand All @@ -110,6 +117,7 @@ async function execGraph({
Logger.verbose('executing all (async)');
// eslint-disable-next-line no-await-in-loop
await engine.executeAllAsync(5);
Logger.verbose(' completed');
}
}

Expand All @@ -119,6 +127,7 @@ async function execGraph({

Logger.verbose('executing all (async)');
await engine.executeAllAsync(5);
Logger.verbose(' completed');
}

if (programOptions.profile) {
Expand All @@ -140,7 +149,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
39 changes: 34 additions & 5 deletions packages/core/src/Diagnostics/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,56 @@

import { EventEmitter } from '../Events/EventEmitter.js';

export enum LogLevel {
Verbose = 0,
Info = 1,
Warn = 2,
Error = 3
}

export enum PrefixStyle {
None = 0,
Time = 1
}

const Reset = '\x1b[0m';
const FgRed = '\x1b[31m';
const BgYellow = '\x1b[43m';
const Dim = '\x1b[2m';

export class Logger {
static logLevel = LogLevel.Info;
static prefixStyle = PrefixStyle.None;

public static readonly onVerbose = new EventEmitter<string>();
public static readonly onInfo = new EventEmitter<string>();
public static readonly onWarn = new EventEmitter<string>();
public static readonly onError = new EventEmitter<string>();

static {
const prefix = () => {
return new Date().toLocaleTimeString().padStart(11, '0');
switch (Logger.prefixStyle) {
case PrefixStyle.None:
return '';
case PrefixStyle.Time:
return new Date().toLocaleTimeString().padStart(11, '0') + ' ';
}
};

Logger.onVerbose.addListener((text: string) => {
console.log(prefix() + ` VERB: ${text}`);
if (Logger.logLevel > LogLevel.Verbose) return;
console.log(prefix() + `${Dim}${text}${Reset}`);
});
Logger.onInfo.addListener((text: string) => {
console.log(prefix() + ` INFO: ${text}`);
if (Logger.logLevel > LogLevel.Info) return;
console.log(prefix() + `${text}`);
});
Logger.onWarn.addListener((text: string) => {
console.warn(prefix() + ` WARN: ${text}`);
if (Logger.logLevel > LogLevel.Warn) return;
console.warn(prefix() + `${BgYellow}${text}${Reset}`);
});
Logger.onError.addListener((text: string) => {
console.error(prefix() + ` ERR: ${text}`);
console.error(prefix() + `${FgRed}${text}}${Reset}`);
});
}

Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"compilerOptions": {
"paths": {
"@behave-graph/core": ["./packages/core/"],
"@behave-graph/flow": ["./packages/flow/"]
"@behave-graph/flow": ["./packages/flow/"],
"@behave-graph/scene": ["./packages/scene/"]
},
"outDir": "dist",
"target": "ES2020",
Expand Down

0 comments on commit 2f325fd

Please sign in to comment.