feat: context types
This commit is contained in:
parent
983db36bab
commit
ea28c58cef
|
@ -8,10 +8,10 @@ const debug = D('@avocado:behavior:context');
|
||||||
export class Context {
|
export class Context {
|
||||||
|
|
||||||
constructor(defaults = {}) {
|
constructor(defaults = {}) {
|
||||||
|
this.typeMap = new Map();
|
||||||
|
this.variableMap = new Map();
|
||||||
this.initialize();
|
this.initialize();
|
||||||
for (const key in defaults) {
|
this.addObjectMap(defaults);
|
||||||
this.add(key, defaults[key]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static describe(description, fn) {
|
static describe(description, fn) {
|
||||||
|
@ -21,34 +21,41 @@ export class Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
static globals() {
|
static globals() {
|
||||||
if (!Context._globals) {
|
return invokeHookFlat('behaviorContextGlobals')
|
||||||
Context._globals = {};
|
.reduce((r, globals) => ({...r, ...globals}), {});
|
||||||
const globalss = invokeHookFlat('behaviorContextGlobals');
|
|
||||||
for (let i = 0; i < globalss.length; i++) {
|
|
||||||
const globals = globalss[i];
|
|
||||||
for (const key in globals) {
|
|
||||||
Context._globals[key] = globals[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Context._globals;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add(key, value) {
|
static typeDescription(type, variable) {
|
||||||
this.map.set(key, value);
|
const types = invokeHookFlat('behaviorContextTypes')
|
||||||
|
.reduce((r, globals) => ({...r, ...globals}), {});
|
||||||
|
if (!types[type]) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if ('function' === typeof types[type]) {
|
||||||
|
return types[type](variable);
|
||||||
|
}
|
||||||
|
return types[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
add(key, value, type) {
|
||||||
|
this.typeMap.set(key, type);
|
||||||
|
this.variableMap.set(key, value, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
addObjectMap(map) {
|
||||||
|
Object.entries(map).forEach(([key, [variable, type]]) => this.add(key, variable, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
all() {
|
all() {
|
||||||
return objectFromEntries(Array.from(this.map.entries()));
|
return Array.from(this.variableMap.keys())
|
||||||
|
.reduce((r, key) => ({...r, [key]: this.get(key)}), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
this.map = new Map();
|
this.typeMap.clear()
|
||||||
this.add('context', this);
|
this.variableMap.clear()
|
||||||
const globals = this.constructor.globals();
|
this.add('context', this, 'context');
|
||||||
for (const key in globals) {
|
this.addObjectMap(this.constructor.globals());
|
||||||
this.add(key, globals[key]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
|
@ -56,7 +63,12 @@ export class Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this.map.clear();
|
this.typeMap.clear()
|
||||||
|
this.variableMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key) {
|
||||||
|
return [this.variableMap.get(key), this.typeMap.get(key)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static renderSteps(steps) {
|
static renderSteps(steps) {
|
||||||
|
@ -126,7 +138,7 @@ export class Context {
|
||||||
previousNode = node;
|
previousNode = node;
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
}, this.map.get(first.key));
|
}, this.variableMap.get(first.key));
|
||||||
}
|
}
|
||||||
|
|
||||||
traverseOneStep(steps, previousNode, node, step) {
|
traverseOneStep(steps, previousNode, node, step) {
|
||||||
|
|
|
@ -8,10 +8,25 @@ class Flow {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static contextDescription() {
|
static parallel(actions, context) {
|
||||||
|
return actions.parallel(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static serial(actions, context) {
|
||||||
|
return actions.serial(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function behaviorContextGlobals() {
|
||||||
return {
|
return {
|
||||||
type: 'object',
|
Flow: [Flow, 'Flow'],
|
||||||
children: {
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function behaviorContextTypes() {
|
||||||
|
return {
|
||||||
|
Flow: {
|
||||||
conditional: {
|
conditional: {
|
||||||
type: 'ticking-promise',
|
type: 'ticking-promise',
|
||||||
label: 'If $1 then run $2.',
|
label: 'If $1 then run $2.',
|
||||||
|
@ -42,22 +57,7 @@ class Flow {
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static parallel(actions, context) {
|
|
||||||
return actions.parallel(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static serial(actions, context) {
|
|
||||||
return actions.serial(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export function behaviorContextGlobals() {
|
|
||||||
return {
|
|
||||||
Flow,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,23 +2,6 @@ import {TickingPromise} from '@avocado/core';
|
||||||
|
|
||||||
class Timing {
|
class Timing {
|
||||||
|
|
||||||
static contextDescription() {
|
|
||||||
return {
|
|
||||||
type: 'object',
|
|
||||||
children: {
|
|
||||||
wait: {
|
|
||||||
type: 'ticking-promise',
|
|
||||||
label: 'Wait for $1 seconds.',
|
|
||||||
args: [
|
|
||||||
['duration', {
|
|
||||||
type: 'number',
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static wait (duration) {
|
static wait (duration) {
|
||||||
return new TickingPromise(
|
return new TickingPromise(
|
||||||
() => {},
|
() => {},
|
||||||
|
@ -33,8 +16,24 @@ class Timing {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function behaviorContextGlobals() {
|
export function behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
Timing,
|
Timing: {
|
||||||
|
wait: {
|
||||||
|
type: 'ticking-promise',
|
||||||
|
label: 'Wait for $1 seconds.',
|
||||||
|
args: [
|
||||||
|
['duration', {
|
||||||
|
type: 'number',
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function behaviorContextGlobals() {
|
||||||
|
return {
|
||||||
|
Timing: [Timing, 'Timing'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,6 @@ class Utility {
|
||||||
|
|
||||||
export function behaviorContextGlobals() {
|
export function behaviorContextGlobals() {
|
||||||
return {
|
return {
|
||||||
Utility,
|
Utility: [Utility, 'Utility'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ export default class Behaved extends decorate(Trait) {
|
||||||
constructor(entity, params, state) {
|
constructor(entity, params, state) {
|
||||||
super(entity, params, state);
|
super(entity, params, state);
|
||||||
this._context = new Context({
|
this._context = new Context({
|
||||||
entity: this.entity,
|
entity: [this.entity, 'entity'],
|
||||||
});
|
});
|
||||||
this._currentRoutine = undefined;
|
this._currentRoutine = undefined;
|
||||||
this._routines = (new Routines()).fromJSON(this.params.routines);
|
this._routines = (new Routines()).fromJSON(this.params.routines);
|
||||||
|
|
|
@ -227,20 +227,6 @@ export default class Entity extends decorate(Resource) {
|
||||||
this._fastDirtyCheck = false;
|
this._fastDirtyCheck = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
contextDescription() {
|
|
||||||
return {
|
|
||||||
type: 'entity',
|
|
||||||
children: this._traitsFlat.reduce(
|
|
||||||
(r, trait) => ({
|
|
||||||
...r,
|
|
||||||
...trait.constructor.contextDescription(),
|
|
||||||
...trait.constructor.describeParams(),
|
|
||||||
...trait.constructor.describeState(),
|
|
||||||
}), {},
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fromJSON(json) {
|
fromJSON(json) {
|
||||||
super.fromJSON(json);
|
super.fromJSON(json);
|
||||||
if (json.instanceUuid) {
|
if (json.instanceUuid) {
|
||||||
|
|
15
packages/entity/index.hooks.js
Normal file
15
packages/entity/index.hooks.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
export function behaviorContextTypes() {
|
||||||
|
return {
|
||||||
|
entity: (entity) => (
|
||||||
|
Object.values(entity.allTraitInstances())
|
||||||
|
.reduce(
|
||||||
|
(r, {constructor: {behaviorContextTypes, describeParams, describeState}}) => ({
|
||||||
|
...r,
|
||||||
|
...behaviorContextTypes(),
|
||||||
|
...describeParams(),
|
||||||
|
...describeState(),
|
||||||
|
}), {},
|
||||||
|
)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ export class Trait extends decorate(class {}) {
|
||||||
this._fastDirtyCheck = false;
|
this._fastDirtyCheck = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ const decorate = compose(
|
||||||
|
|
||||||
export default class Alive extends decorate(Trait) {
|
export default class Alive extends decorate(Trait) {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
forceDeath: {
|
forceDeath: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
@ -112,7 +112,7 @@ export default class Alive extends decorate(Trait) {
|
||||||
constructor(entity, params, state) {
|
constructor(entity, params, state) {
|
||||||
super(entity, params, state);
|
super(entity, params, state);
|
||||||
this._context = new Context({
|
this._context = new Context({
|
||||||
entity: this.entity,
|
entity: [this.entity, 'entity'],
|
||||||
});
|
});
|
||||||
this._deathActions = behaviorItemFromJSON(this.params.deathActions);
|
this._deathActions = behaviorItemFromJSON(this.params.deathActions);
|
||||||
this._deathCondition = behaviorItemFromJSON(this.params.deathCondition);
|
this._deathCondition = behaviorItemFromJSON(this.params.deathCondition);
|
||||||
|
|
|
@ -10,7 +10,7 @@ const decorate = compose(
|
||||||
|
|
||||||
export default class Existent extends decorate(Trait) {
|
export default class Existent extends decorate(Trait) {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
transition: {
|
transition: {
|
||||||
type: 'ticking-promise',
|
type: 'ticking-promise',
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {Trait} from '../trait';
|
||||||
|
|
||||||
export default class Listed extends Trait {
|
export default class Listed extends Trait {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
detachFromList: {
|
detachFromList: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
|
|
@ -10,7 +10,7 @@ const decorate = compose(
|
||||||
|
|
||||||
export default class Mobile extends decorate(Trait) {
|
export default class Mobile extends decorate(Trait) {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
moveFor: {
|
moveFor: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
|
|
@ -17,7 +17,7 @@ const decorate = compose(
|
||||||
// < 16768 will pack into 1 short per axe and give +/- 0.25 precision.
|
// < 16768 will pack into 1 short per axe and give +/- 0.25 precision.
|
||||||
export default class Positioned extends decorate(Trait) {
|
export default class Positioned extends decorate(Trait) {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
setPosition: {
|
setPosition: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
|
|
@ -13,7 +13,7 @@ const decorate = compose(
|
||||||
|
|
||||||
export default class Spawner extends decorate(Trait) {
|
export default class Spawner extends decorate(Trait) {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
spawn: {
|
spawn: {
|
||||||
type: 'entity',
|
type: 'entity',
|
||||||
|
|
|
@ -30,7 +30,7 @@ const decorate = compose(
|
||||||
|
|
||||||
export default class Visible extends decorate(Trait) {
|
export default class Visible extends decorate(Trait) {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
updateVisibleBoundingBox: {
|
updateVisibleBoundingBox: {
|
||||||
advanced: true,
|
advanced: true,
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
import * as MathExt from '.';
|
import * as MathExt from '.';
|
||||||
|
|
||||||
MathExt.contextDescription = () => {
|
export function behaviorContextGlobals() {
|
||||||
return {
|
return {
|
||||||
type: 'module',
|
Math: [MathExt, 'Math'],
|
||||||
children: {
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function behaviorContextTypes() {
|
||||||
|
return {
|
||||||
|
Math: (Math) => ({
|
||||||
floor: {
|
floor: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
label: 'Floor $1.',
|
label: 'Floor $1.',
|
||||||
|
@ -28,12 +33,6 @@ MathExt.contextDescription = () => {
|
||||||
Vector: {
|
Vector: {
|
||||||
type: 'Vector',
|
type: 'Vector',
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function behaviorContextGlobals() {
|
|
||||||
return {
|
|
||||||
Math: MathExt,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
15
packages/math/vector/index.hooks.js
Normal file
15
packages/math/vector/index.hooks.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
export function behaviorContextTypes() {
|
||||||
|
return {
|
||||||
|
Vector: (Math) => ({
|
||||||
|
fromDirection: {
|
||||||
|
type: 'vector',
|
||||||
|
label: '$1 as a movement vector.',
|
||||||
|
args: [
|
||||||
|
['direction', {
|
||||||
|
type: 'number',
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
|
@ -409,7 +409,7 @@ export class Range extends MathRange {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function contextDescription() {
|
export function behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
type: 'Vector',
|
type: 'Vector',
|
||||||
children: {
|
children: {
|
||||||
|
|
|
@ -10,7 +10,7 @@ const decorate = compose(
|
||||||
|
|
||||||
export default class Collider extends decorate(Trait) {
|
export default class Collider extends decorate(Trait) {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
collidesWith: {
|
collidesWith: {
|
||||||
advanced: true,
|
advanced: true,
|
||||||
|
@ -182,7 +182,7 @@ export default class Collider extends decorate(Trait) {
|
||||||
|
|
||||||
pushCollisionTickingPromise(actions, other) {
|
pushCollisionTickingPromise(actions, other) {
|
||||||
const context = new Context({
|
const context = new Context({
|
||||||
entity: this.entity,
|
entity: [this.entity, 'entity'],
|
||||||
other,
|
other,
|
||||||
});
|
});
|
||||||
const tickingPromise = actions.tickingPromise(context);
|
const tickingPromise = actions.tickingPromise(context);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {Sound} from '..';
|
||||||
|
|
||||||
export default class Audible extends Trait {
|
export default class Audible extends Trait {
|
||||||
|
|
||||||
static contextDescription() {
|
static behaviorContextTypes() {
|
||||||
return {
|
return {
|
||||||
playSound: {
|
playSound: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user