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 {
|
||||
|
||||
constructor(defaults = {}) {
|
||||
this.typeMap = new Map();
|
||||
this.variableMap = new Map();
|
||||
this.initialize();
|
||||
for (const key in defaults) {
|
||||
this.add(key, defaults[key]);
|
||||
}
|
||||
this.addObjectMap(defaults);
|
||||
}
|
||||
|
||||
static describe(description, fn) {
|
||||
|
@ -21,34 +21,41 @@ export class Context {
|
|||
}
|
||||
|
||||
static globals() {
|
||||
if (!Context._globals) {
|
||||
Context._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;
|
||||
return invokeHookFlat('behaviorContextGlobals')
|
||||
.reduce((r, globals) => ({...r, ...globals}), {});
|
||||
}
|
||||
|
||||
add(key, value) {
|
||||
this.map.set(key, value);
|
||||
static typeDescription(type, variable) {
|
||||
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() {
|
||||
return objectFromEntries(Array.from(this.map.entries()));
|
||||
return Array.from(this.variableMap.keys())
|
||||
.reduce((r, key) => ({...r, [key]: this.get(key)}), {});
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.map = new Map();
|
||||
this.add('context', this);
|
||||
const globals = this.constructor.globals();
|
||||
for (const key in globals) {
|
||||
this.add(key, globals[key]);
|
||||
}
|
||||
this.typeMap.clear()
|
||||
this.variableMap.clear()
|
||||
this.add('context', this, 'context');
|
||||
this.addObjectMap(this.constructor.globals());
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
@ -56,7 +63,12 @@ export class Context {
|
|||
}
|
||||
|
||||
destroy() {
|
||||
this.map.clear();
|
||||
this.typeMap.clear()
|
||||
this.variableMap.clear();
|
||||
}
|
||||
|
||||
get(key) {
|
||||
return [this.variableMap.get(key), this.typeMap.get(key)];
|
||||
}
|
||||
|
||||
static renderSteps(steps) {
|
||||
|
@ -126,7 +138,7 @@ export class Context {
|
|||
previousNode = node;
|
||||
return result;
|
||||
});
|
||||
}, this.map.get(first.key));
|
||||
}, this.variableMap.get(first.key));
|
||||
}
|
||||
|
||||
traverseOneStep(steps, previousNode, node, step) {
|
||||
|
|
|
@ -8,44 +8,6 @@ class Flow {
|
|||
}
|
||||
};
|
||||
|
||||
static contextDescription() {
|
||||
return {
|
||||
type: 'object',
|
||||
children: {
|
||||
conditional: {
|
||||
type: 'ticking-promise',
|
||||
label: 'If $1 then run $2.',
|
||||
args: [
|
||||
['condition', {
|
||||
type: 'condition',
|
||||
}],
|
||||
['actions', {
|
||||
type: 'actions',
|
||||
}],
|
||||
],
|
||||
},
|
||||
parallel: {
|
||||
type: 'ticking-promise',
|
||||
label: 'Run $1 in parallel.',
|
||||
args: [
|
||||
['actions', {
|
||||
type: 'actions',
|
||||
}],
|
||||
],
|
||||
},
|
||||
serial: {
|
||||
type: 'ticking-promise',
|
||||
label: 'Run $1 serially.',
|
||||
args: [
|
||||
['actions', {
|
||||
type: 'actions',
|
||||
}],
|
||||
],
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static parallel(actions, context) {
|
||||
return actions.parallel(context);
|
||||
}
|
||||
|
@ -58,6 +20,44 @@ class Flow {
|
|||
|
||||
export function behaviorContextGlobals() {
|
||||
return {
|
||||
Flow,
|
||||
Flow: [Flow, 'Flow'],
|
||||
};
|
||||
}
|
||||
|
||||
export function behaviorContextTypes() {
|
||||
return {
|
||||
Flow: {
|
||||
conditional: {
|
||||
type: 'ticking-promise',
|
||||
label: 'If $1 then run $2.',
|
||||
args: [
|
||||
['condition', {
|
||||
type: 'condition',
|
||||
}],
|
||||
['actions', {
|
||||
type: 'actions',
|
||||
}],
|
||||
],
|
||||
},
|
||||
parallel: {
|
||||
type: 'ticking-promise',
|
||||
label: 'Run $1 in parallel.',
|
||||
args: [
|
||||
['actions', {
|
||||
type: 'actions',
|
||||
}],
|
||||
],
|
||||
},
|
||||
serial: {
|
||||
type: 'ticking-promise',
|
||||
label: 'Run $1 serially.',
|
||||
args: [
|
||||
['actions', {
|
||||
type: 'actions',
|
||||
}],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,23 +2,6 @@ import {TickingPromise} from '@avocado/core';
|
|||
|
||||
class Timing {
|
||||
|
||||
static contextDescription() {
|
||||
return {
|
||||
type: 'object',
|
||||
children: {
|
||||
wait: {
|
||||
type: 'ticking-promise',
|
||||
label: 'Wait for $1 seconds.',
|
||||
args: [
|
||||
['duration', {
|
||||
type: 'number',
|
||||
}],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static wait (duration) {
|
||||
return new TickingPromise(
|
||||
() => {},
|
||||
|
@ -33,8 +16,24 @@ class Timing {
|
|||
|
||||
}
|
||||
|
||||
export function behaviorContextGlobals() {
|
||||
export function behaviorContextTypes() {
|
||||
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() {
|
||||
return {
|
||||
Utility,
|
||||
Utility: [Utility, 'Utility'],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ export default class Behaved extends decorate(Trait) {
|
|||
constructor(entity, params, state) {
|
||||
super(entity, params, state);
|
||||
this._context = new Context({
|
||||
entity: this.entity,
|
||||
entity: [this.entity, 'entity'],
|
||||
});
|
||||
this._currentRoutine = undefined;
|
||||
this._routines = (new Routines()).fromJSON(this.params.routines);
|
||||
|
|
|
@ -227,20 +227,6 @@ export default class Entity extends decorate(Resource) {
|
|||
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) {
|
||||
super.fromJSON(json);
|
||||
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;
|
||||
}
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ const decorate = compose(
|
|||
|
||||
export default class Alive extends decorate(Trait) {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
forceDeath: {
|
||||
type: 'void',
|
||||
|
@ -112,7 +112,7 @@ export default class Alive extends decorate(Trait) {
|
|||
constructor(entity, params, state) {
|
||||
super(entity, params, state);
|
||||
this._context = new Context({
|
||||
entity: this.entity,
|
||||
entity: [this.entity, 'entity'],
|
||||
});
|
||||
this._deathActions = behaviorItemFromJSON(this.params.deathActions);
|
||||
this._deathCondition = behaviorItemFromJSON(this.params.deathCondition);
|
||||
|
|
|
@ -10,7 +10,7 @@ const decorate = compose(
|
|||
|
||||
export default class Existent extends decorate(Trait) {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
transition: {
|
||||
type: 'ticking-promise',
|
||||
|
|
|
@ -4,7 +4,7 @@ import {Trait} from '../trait';
|
|||
|
||||
export default class Listed extends Trait {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
detachFromList: {
|
||||
type: 'void',
|
||||
|
|
|
@ -10,7 +10,7 @@ const decorate = compose(
|
|||
|
||||
export default class Mobile extends decorate(Trait) {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
moveFor: {
|
||||
type: 'void',
|
||||
|
|
|
@ -17,7 +17,7 @@ const decorate = compose(
|
|||
// < 16768 will pack into 1 short per axe and give +/- 0.25 precision.
|
||||
export default class Positioned extends decorate(Trait) {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
setPosition: {
|
||||
type: 'void',
|
||||
|
|
|
@ -13,7 +13,7 @@ const decorate = compose(
|
|||
|
||||
export default class Spawner extends decorate(Trait) {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
spawn: {
|
||||
type: 'entity',
|
||||
|
|
|
@ -30,7 +30,7 @@ const decorate = compose(
|
|||
|
||||
export default class Visible extends decorate(Trait) {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
updateVisibleBoundingBox: {
|
||||
advanced: true,
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import * as MathExt from '.';
|
||||
|
||||
MathExt.contextDescription = () => {
|
||||
export function behaviorContextGlobals() {
|
||||
return {
|
||||
type: 'module',
|
||||
children: {
|
||||
Math: [MathExt, 'Math'],
|
||||
};
|
||||
}
|
||||
|
||||
export function behaviorContextTypes() {
|
||||
return {
|
||||
Math: (Math) => ({
|
||||
floor: {
|
||||
type: 'number',
|
||||
label: 'Floor $1.',
|
||||
|
@ -28,12 +33,6 @@ MathExt.contextDescription = () => {
|
|||
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 {
|
||||
type: 'Vector',
|
||||
children: {
|
||||
|
|
|
@ -10,7 +10,7 @@ const decorate = compose(
|
|||
|
||||
export default class Collider extends decorate(Trait) {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
collidesWith: {
|
||||
advanced: true,
|
||||
|
@ -182,7 +182,7 @@ export default class Collider extends decorate(Trait) {
|
|||
|
||||
pushCollisionTickingPromise(actions, other) {
|
||||
const context = new Context({
|
||||
entity: this.entity,
|
||||
entity: [this.entity, 'entity'],
|
||||
other,
|
||||
});
|
||||
const tickingPromise = actions.tickingPromise(context);
|
||||
|
|
|
@ -4,7 +4,7 @@ import {Sound} from '..';
|
|||
|
||||
export default class Audible extends Trait {
|
||||
|
||||
static contextDescription() {
|
||||
static behaviorContextTypes() {
|
||||
return {
|
||||
playSound: {
|
||||
type: 'void',
|
||||
|
|
Loading…
Reference in New Issue
Block a user