Socket
Socket
Sign inDemoInstall

@croquet/worldcore-behavior

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@croquet/worldcore-behavior - npm Package Compare versions

Comparing version 1.2.0 to 1.3.0

11

CHANGELOG.md

@@ -7,2 +7,10 @@ # Changelog

## [1.3.0] - 2022-6-16
## Changed
- Behaviors are Actors
- BehaviorPawn provides a view-side interface to individual behaviors in the tree
- Behaviors have a code snippet to allow live editing
- PM_Behavioral can be added to pawns to access the object's behavior tree
## [1.0.0] - 2021-10-20

@@ -13,1 +21,4 @@ ### Added

## Pending

6

package.json
{
"name": "@croquet/worldcore-behavior",
"version": "1.2.0",
"version": "1.3.0",
"description": "Behavior Tree Component for Croquet Worldcore",

@@ -27,3 +27,3 @@ "keywords": [

"dependencies": {
"@croquet/worldcore-kernel": "^1.2.0"
"@croquet/worldcore-kernel": "^1.3.0"
},

@@ -33,3 +33,3 @@ "publishConfig": {

},
"gitHead": "7633b5da452e79cee2be15721d744e4cd9f9924c"
"gitHead": "d5e33664baaaa1a3a153e0aa3721ad3a17c25dc3"
}

@@ -1,5 +0,5 @@

import { RegisterMixin, WorldcoreModel, Shuffle } from "@croquet/worldcore-kernel";
// import { } from "@croquet/worldcore-kernel";
// import { Shuffle } from "./Utilities";
import { RegisterMixin, WorldcoreModel, Shuffle, Actor, Pawn, GetPawn } from "@croquet/worldcore-kernel";
import * as Worldcore from "@croquet/worldcore-kernel";
//------------------------------------------------------------------------------------------

@@ -9,6 +9,13 @@ //-- Behavioral ----------------------------------------------------------------------------

// StartBehavior sets the actor's current root behavior.
// Mixin to allow actors to use behavior trees.
export const AM_Behavioral = superclass => class extends superclass {
// StartBehavior sets the actor's current root behavior.
export const AM_Behavioral = superclass => class extends superclass {
init(...args) {
super.init(...args);
this.listen("setBehaviorCode", this.setBehaviorCode);
}
destroy() {

@@ -22,17 +29,58 @@ super.destroy();

options.actor = this;
this.behavior = behavior.create(options);
const target = behavior.create(options);
this.behavior = target;
}
setBehaviorCode(code) {
this.behavior.set({code: code});
}
}
RegisterMixin(AM_Behavioral);
//Mixin to allow view-side access of the behavior tree.
export const PM_Behavioral = superclass => class extends superclass {
get behavior() { if(this.actor.behavior) return GetPawn(this.actor.behavior.id) }
}
//------------------------------------------------------------------------------------------
//-- BehaviorHandler -----------------------------------------------------------------------
//------------------------------------------------------------------------------------------
//This is the default handler for the behavior proxies. It traps all method calls
// and uses the code snippet instead. If you want to call the base methods from the code snippet,
// you can with "super.onStart()" (for example)
class BehaviorHandler {
get(target, prop, receiver) {
if(this[prop]) return this[prop];
if(prop === "base") return target;
return Reflect.get(...arguments);
}
onStart() {
this.base.onStart(); // Fall thru to the behavior.
}
do(delta) {
this.base.do(delta); // Fall thru to the behavior.
}
}
//------------------------------------------------------------------------------------------
//-- Behavior ------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
export class Behavior extends WorldcoreModel {
export class Behavior extends Actor {
get pawn() { return BehaviorPawn; }
init(options) {
super.init();
this.set(options);
if (this.parent) this.parent.addChild(this);
super.init(options);
this.listen("_code", this.clearProxy); // Flush the proxy if the code changes.

@@ -43,18 +91,21 @@ if (this.tickRate) {

}
}
destroy() {
super.destroy();
if (this.parent) this.parent.removeChild(this);
this.doomed = true;
this.proxy.onStart();
}
set(options) {
for (const option in options) {
this["_" + option] = options[option];
clearProxy() { this.$proxy = null }
get proxy() {
if (!this.$proxy) {
const factoryCode = `return class extends superclass { ${this.code} }`;
const factory = new Function('superclass', 'WC', factoryCode);
this.$proxy = new Proxy(this, factory(BehaviorHandler, Worldcore).prototype);
}
return this.$proxy;
}
get code() { return this._code}
get actor() { return this._actor}
get parent() { return this._parent}
get tickRate() { return this._tickRate || 100}

@@ -64,10 +115,14 @@

if (this.doomed) return;
this.do(delta);
this.proxy.do(delta);
if (!this.doomed) this.future(this.tickRate).tick(this.tickRate);
}
do(delta) {}
startChild(behavior, options = {}) {
options.actor = this.actor;
options.parent = this;
behavior.create(options);
}
succeed(data) {
if (this.parent) this.parent.reportSuccess(this, data);
if (this.parent) this.parent.proxy.onSucceed(this, data);
this.destroy();

@@ -77,9 +132,24 @@ }

fail(data) {
if (this.parent) this.parent.reportFailure(this, data);
if (this.parent) this.parent.proxy.onFail(this, data);
this.destroy();
}
onStart() {}
do(delta) {}
onSucceed(child, data) { this.succeed(data) };
onFail(child, data) { this.fail(data) };
}
Behavior.register('Behavior');
// Behaviors don't have to have pawns. BehaviorPawn just provides a view-side interface for changing the code snippet.
// The BehaviorPawns replicate the structure of the behavior tree so you can use this to inspect the current state of the tree.
export class BehaviorPawn extends Pawn {
get code() { return this.actor.code }
set code(code) { this.set( {code: code}) }
}
//------------------------------------------------------------------------------------------

@@ -89,3 +159,3 @@ //-- CompositeBehavior ---------------------------------------------------------------------

// Behaviors with children. They don't tick themselves, but can respond to reported success or
// Behaviors with multiple child behaviors. They don't tick themselves, but respond to reported success or
// failure by their children who are ticking.

@@ -97,26 +167,24 @@

get behaviors() {return []}
get isParallel() { return this._parallel }
get isShuffle() { return this._shuffle }
destroy() {
super.destroy();
new Set(this.children).forEach(child => child.destroy());
onStart() {
this.n = 0;
this.pending = this.behaviors.length;
if (this.isShuffle) this.deck = Shuffle(this.behaviors.length);
this.isParallel ? this.startAll() : this.startNext();
}
startChild(behavior, options = {}) {
options.actor = this.actor;
options.parent = this;
behavior.create(options);
startAll() {
for (let i = 0; i < this.behaviors.length; i++ ) {
if (this.doomed) return;
this.isShuffle ? this.startChild(this.behaviors[this.deck[i]]) : this.startChild(this.behaviors[i]);
}
}
addChild(child) {
if (!this.children) this.children = new Set();
this.children.add(child);
startNext() {
if (this.isParallel) return;
this.isShuffle ? this.startChild(this.behaviors[this.deck[this.n++]]) : this.startChild(this.behaviors[this.n++]);
}
removeChild(child) {
if (this.children) this.children.delete(child);
}
reportSuccess(child, data) {};
reportFailure(child, data) { this.fail(data)};
}

@@ -130,23 +198,11 @@ CompositeBehavior.register('CompositeBehavior');

// Executes a sequence of behaviors in order. Fails if any of them fails. Nothing is
// excecuted after the first fail.
// executed after the first fail. Succeeds if all of them succeed.
// The equivalent of a logical AND
export class SequenceBehavior extends CompositeBehavior {
init(options) {
super.init(options);
this.n = 0;
this.next();
}
onSucceed() { --this.pending ? this.startNext() : this.succeed(); }
onFail() { this.fail(); }
next() {
if (this.n < this.behaviors.length) {
this.startChild(this.behaviors[this.n++]);
} else {
this.succeed();
}
}
reportSuccess() { this.next(); }
// reportFailure() { this.fail(); }
}

@@ -156,60 +212,2 @@ SequenceBehavior.register('SequenceBehavior');

//------------------------------------------------------------------------------------------
//-- RandomSequenceBehavior ----------------------------------------------------------------
//------------------------------------------------------------------------------------------
// Executes all children in random order. Fails if any of them fails. Nothing is excecuted after
// the first fail.
export class RandomSequenceBehavior extends CompositeBehavior {
init(options) {
super.init(options);
this.n = 0;
this.order = Shuffle(this.behaviors.length);
this.next();
}
next() {
if (this.n < this.behaviors.length) {
const pick = this.order[this.n++];
this.startChild(this.behaviors[pick]);
} else {
this.succeed();
}
}
reportSuccess() { this.next(); }
// reportFailure() { this.fail(); }
}
RandomSequenceBehavior.register('RandomSequenceBehavior');
//------------------------------------------------------------------------------------------
//-- ParallelSequenceBehavior --------------------------------------------------------------
//------------------------------------------------------------------------------------------
// Executes all childred simultaenously. Succeeds if all children succeed.
// Fails if one child fails. Aborts other children after first failure.
export class ParallelSequenceBehavior extends CompositeBehavior {
init(options) {
super.init(options);
this.behaviors.forEach (behavior => {
if (this.doomed) return;
this.startChild(behavior)
})
}
reportSuccess() {
if (this.children.size > 0) return;
this.succeed();
}
// reportFailure() { this.fail(); }
}
ParallelSequenceBehavior.register('ParallelSequenceBehavior');
//------------------------------------------------------------------------------------------
//-- SelectorBehavior ----------------------------------------------------------------------

@@ -219,23 +217,12 @@ //------------------------------------------------------------------------------------------

// Executes behaviors in order. Succeeds if any of them succeeds. Nothing is executed after
// the first success.
// the first success. Fails if all of them fail.
// The equivalent of a logical OR
export class SelectorBehavior extends CompositeBehavior {
init(options) {
super.init(options);
this.n = 0;
this.next();
}
onSucceed() { this.succeed(); }
onFail() { --this.pending ? this.startNext() : this.fail(); }
next() {
if (this.n < this.behaviors.length) {
this.startChild(this.behaviors[this.n++]);
} else {
this.fail();
}
}
reportSuccess() { this.succeed(); }
reportFailure() { this.next(); }
}

@@ -245,60 +232,2 @@ SelectorBehavior.register('SelectorBehavior');

//------------------------------------------------------------------------------------------
//-- RandomSelectorBehavior ----------------------------------------------------------------
//------------------------------------------------------------------------------------------
// Executes behaviors in random order. Succeeds if any of them succeeds. Nothing is executed after
// the first success.
export class RandomSelectorBehavior extends CompositeBehavior {
init(options) {
super.init(options);
this.order = Shuffle(this.behaviors.length);
this.n = 0;
this.next();
}
next() {
if (this.n < this.behaviors.length) {
const pick = this.order[this.n++];
this.startChild(this.behaviors[pick]);
} else {
this.fail();
}
}
reportSuccess() { this.succeed(); }
reportFailure() { this.next(); }
}
RandomSelectorBehavior.register('RandomSelectorBehavior');
//------------------------------------------------------------------------------------------
//-- ParallelSelectorBehavior --------------------------------------------------------------
//------------------------------------------------------------------------------------------
// Executes all childred simultaenously. Fails if all children fail.
// Succeeds if one child succeeds. Aborts other children after first success.
export class ParallelSelectorBehavior extends CompositeBehavior {
init(options) {
super.init(options);
this.behaviors.forEach (behavior => {
if (this.doomed) return;
this.startChild(behavior)
})
}
reportSuccess() { this.succeed(); }
reportFailure() {
if (this.children.size > 0) return;
this.fail();
}
}
ParallelSelectorBehavior.register('ParallelSelectorBehavior');
//------------------------------------------------------------------------------------------
//-- DecoratorBehavior ---------------------------------------------------------------------

@@ -312,31 +241,6 @@ //------------------------------------------------------------------------------------------

get tickRate() { return 0 }
get behavior() { return null}
get behavior() { return null }
init(options) {
super.init(options);
this.startChild();
}
onStart() { this.startChild(this.behavior); }
destroy() {
super.destroy();
if (this.child) this.child.destroy();
}
startChild(options = {}) {
options.actor = this.actor;
options.parent = this;
this.behavior.create(options);
}
addChild(child) {
this.child = child;
}
removeChild(child) {
if (this.child === child) this.child = null;
}
reportSuccess(child, data) {this.succeed(data)};
reportFailure(child, data) {this.fail(data)};
}

@@ -349,8 +253,8 @@ DecoratorBehavior.register('DecoratorBehavior');

// Holds a single child behavior. Inverts its completion status when it fnishes.
// Inverts completion status when child finishes.
export class InvertBehavior extends DecoratorBehavior {
reportSuccess(child, data) {this.fail(data)};
reportFailure(child, data) {this.succeed(data)};
onSucceed(child, data) {this.fail(data)};
onFail(child, data) {this.succeed(data)};

@@ -364,8 +268,8 @@ }

// Holds a single child behavior. Always returns success when it finishes.
// Always returns success when the child finishes.
export class SucceedBehavior extends DecoratorBehavior {
reportSuccess(child, data) {this.succeed(data)};
reportFailure(child, data) {this.succeed(data)};
onSucceed(child, data) { this.succeed(data) };
onFail(child, data) { this.succeed(data) };

@@ -379,8 +283,8 @@ }

// Holds a single child behavior. Always returns failure when it finishes.
// Always returns fail when the child finishes.
export class FailBehavior extends DecoratorBehavior {
reportSuccess(child, data) {this.fail(data)};
reportFailure(child, data) {this.fail(data)};
onSucceed(child, data) {this.fail(data)};
onFail(child, data) {this.fail(data)};

@@ -391,68 +295,39 @@ }

//------------------------------------------------------------------------------------------
//-- LoopBehavior --------------------------------------------------------------------------
//-- DelayBehavior -------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
// Holds a single child behavior. Will repeatedly execute it until count is reached, as long
// as it succeeds. If it fails, the loop returns failure.
//
// If the count is set to 0, it executes indefinitely.
//
// Note that if the child completes instantly and the count is high, you will probably overrun
// the call stack.
// Succeeds when delay time is reached.
export class LoopBehavior extends DecoratorBehavior {
export class DelayBehavior extends Behavior {
get count() {return this._count || 0}
get tickRate() { return 0 }
get delay() { return this._delay || 1000};
init(options) {
super.init(options);
if (this.count) this.n = 0;
}
onStart() { this.future(this.delay).succeed(); }
reportSuccess(child, data) {
if (this.count) {
this.n++;
if (this.n === this.count) {
this.succeed();
return;
}
}
this.startChild();
}
}
LoopBehavior.register('LoopBehavior');
DelayBehavior.register("DelayBehavior");
//------------------------------------------------------------------------------------------
//-- DestroyBehavior -----------------------------------------------------------------------
//-- LoopBehavior --------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
// Destroys the actor
// Repeatedly executes a child behavior until count is reached, as long
// as it succeeds. If it fails, the loop returns failure. If the count is set to 0, it executes indefinitely.
export class DestroyBehavior extends Behavior {
export class LoopBehavior extends DecoratorBehavior {
init(options) {
super.init(options);
this.actor.destroy();
get count() {return this._count || 0}
onStart() {
this.n = 0;
this.startChild(this.behavior);
}
}
DestroyBehavior.register("DestroyBehavior");
//------------------------------------------------------------------------------------------
//-- DelayBehavior -------------------------------------------------------------------------
//------------------------------------------------------------------------------------------
onSucceed() { ++this.n === this.count ? this.succeed() : this.startChild(this.behavior); }
onFail() { this.fail(); }
// Succeeds when delay time is reached.
}
LoopBehavior.register('LoopBehavior');
export class DelayBehavior extends Behavior {
get tickRate() { return 0 }
get delay() { return this._delay || 1000};
init(options) {
super.init(options);
this.future(this.delay).succeed();
}
}
DelayBehavior.register("DelayBehavior");
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc