@driftengine/script 3.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +81 -0
- package/dist/bindings/ai.d.ts +66 -0
- package/dist/bindings/ai.js +173 -0
- package/dist/bindings/animation.d.ts +13 -0
- package/dist/bindings/animation.js +177 -0
- package/dist/bindings/audio.d.ts +56 -0
- package/dist/bindings/audio.js +126 -0
- package/dist/bindings/behavior.d.ts +36 -0
- package/dist/bindings/behavior.js +101 -0
- package/dist/bindings/chemistry.d.ts +72 -0
- package/dist/bindings/chemistry.js +253 -0
- package/dist/bindings/core.d.ts +172 -0
- package/dist/bindings/core.js +814 -0
- package/dist/bindings/editor.d.ts +53 -0
- package/dist/bindings/editor.js +248 -0
- package/dist/bindings/entities.d.ts +73 -0
- package/dist/bindings/entities.js +339 -0
- package/dist/bindings/interface.d.ts +55 -0
- package/dist/bindings/interface.js +200 -0
- package/dist/bindings/navigation.d.ts +36 -0
- package/dist/bindings/navigation.js +255 -0
- package/dist/bindings/network.d.ts +51 -0
- package/dist/bindings/network.js +96 -0
- package/dist/bindings/render.d.ts +71 -0
- package/dist/bindings/render.js +143 -0
- package/dist/bindings/rollback.d.ts +41 -0
- package/dist/bindings/rollback.js +74 -0
- package/dist/bindings/sprites.d.ts +53 -0
- package/dist/bindings/sprites.js +186 -0
- package/dist/bindings/terrain.d.ts +54 -0
- package/dist/bindings/terrain.js +138 -0
- package/dist/bindings/xr.d.ts +56 -0
- package/dist/bindings/xr.js +155 -0
- package/dist/entityHost.d.ts +80 -0
- package/dist/entityHost.js +159 -0
- package/dist/host.d.ts +153 -0
- package/dist/host.js +233 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +18 -0
- package/package.json +68 -0
- package/src/bindings/ai.ts +306 -0
- package/src/bindings/animation.ts +346 -0
- package/src/bindings/audio.ts +185 -0
- package/src/bindings/behavior.ts +181 -0
- package/src/bindings/chemistry.ts +548 -0
- package/src/bindings/core.ts +1604 -0
- package/src/bindings/editor.ts +393 -0
- package/src/bindings/entities.ts +550 -0
- package/src/bindings/interface.ts +300 -0
- package/src/bindings/navigation.ts +367 -0
- package/src/bindings/network.ts +178 -0
- package/src/bindings/render.ts +191 -0
- package/src/bindings/rollback.ts +110 -0
- package/src/bindings/sprites.ts +310 -0
- package/src/bindings/terrain.ts +180 -0
- package/src/bindings/xr.ts +272 -0
- package/src/entityHost.ts +219 -0
- package/src/host.ts +465 -0
- package/src/index.ts +41 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { BehaviorRunner } from '@driftengine/core';
|
|
2
|
+
import { type CapabilityDefinition, type OpaqueType, defineCapability } from 'driftscript';
|
|
3
|
+
|
|
4
|
+
export const BEHAVIOR_MODULE = 'drift/behavior';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `drift/behavior` — driving and watching a behaviour tree from a script.
|
|
8
|
+
*
|
|
9
|
+
* **A script drives a tree; it does not author one.** A tree is nested data with a name on every
|
|
10
|
+
* node, and the useful thing to have in a script is not a builder for it but the two verbs a
|
|
11
|
+
* hand-written routine cannot offer: advance it, and ask what it is doing. Authoring stays in
|
|
12
|
+
* TypeScript beside the actions the tree calls, which is where the consumer's own verbs already
|
|
13
|
+
* are.
|
|
14
|
+
*
|
|
15
|
+
* **`doing` is the capability worth pointing at.** It answers whether the agent is currently inside
|
|
16
|
+
* a node of a given name, which is what turns a tree from something that runs into something a
|
|
17
|
+
* script can react to — play a sound while an agent is sheltering, show an icon while it is walking
|
|
18
|
+
* home, refuse to talk to it mid-errand — without the tree and the script keeping a second copy of
|
|
19
|
+
* the same state in step.
|
|
20
|
+
*
|
|
21
|
+
* The same effect seam as `drift/navigation` and for the same reason: `behavior.read` is in the
|
|
22
|
+
* language's deterministic set and `behavior.write` is not, so a `@deterministic` system may watch
|
|
23
|
+
* a tree and not tick one. See `bindings/navigation.ts`, where the argument and its reversal
|
|
24
|
+
* condition are written out.
|
|
25
|
+
*/
|
|
26
|
+
export const BEHAVIOR_TYPES: readonly OpaqueType[] = [
|
|
27
|
+
{
|
|
28
|
+
module: BEHAVIOR_MODULE,
|
|
29
|
+
name: 'Behavior',
|
|
30
|
+
doc: 'One agent running one behaviour tree: where it is in its routine.',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const define = (
|
|
35
|
+
name: string,
|
|
36
|
+
params: readonly { name: string; type: string }[],
|
|
37
|
+
returns: string,
|
|
38
|
+
effects: readonly string[],
|
|
39
|
+
doc: string,
|
|
40
|
+
deterministic = true,
|
|
41
|
+
): CapabilityDefinition =>
|
|
42
|
+
defineCapability({
|
|
43
|
+
module: BEHAVIOR_MODULE,
|
|
44
|
+
name,
|
|
45
|
+
signature: `fn(${params.map((p) => `${p.name}: ${p.type}`).join(', ')}) -> ${returns}`,
|
|
46
|
+
params: [...params],
|
|
47
|
+
returns,
|
|
48
|
+
effects: effects as CapabilityDefinition['effects'],
|
|
49
|
+
deterministic,
|
|
50
|
+
doc,
|
|
51
|
+
implementation: `${BEHAVIOR_MODULE}.${name}`,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const BEHAVIOR_CAPABILITIES: readonly CapabilityDefinition[] = [
|
|
55
|
+
define(
|
|
56
|
+
'tick',
|
|
57
|
+
[{ name: 'behavior', type: 'Behavior' }],
|
|
58
|
+
'i32',
|
|
59
|
+
['behavior.write'],
|
|
60
|
+
'Advance the routine one tick. Answers 0 failed, 1 finished, 2 still going. Does nothing while paused.',
|
|
61
|
+
false,
|
|
62
|
+
),
|
|
63
|
+
define(
|
|
64
|
+
'step',
|
|
65
|
+
[{ name: 'behavior', type: 'Behavior' }],
|
|
66
|
+
'i32',
|
|
67
|
+
['behavior.write'],
|
|
68
|
+
'Advance one tick even while paused, which is what a step button is.',
|
|
69
|
+
false,
|
|
70
|
+
),
|
|
71
|
+
define(
|
|
72
|
+
'restart',
|
|
73
|
+
[{ name: 'behavior', type: 'Behavior' }],
|
|
74
|
+
'void',
|
|
75
|
+
['behavior.write'],
|
|
76
|
+
'Forget where the routine had got to, so the next tick starts it from the top.',
|
|
77
|
+
false,
|
|
78
|
+
),
|
|
79
|
+
define(
|
|
80
|
+
'setPaused',
|
|
81
|
+
[
|
|
82
|
+
{ name: 'behavior', type: 'Behavior' },
|
|
83
|
+
{ name: 'paused', type: 'bool' },
|
|
84
|
+
],
|
|
85
|
+
'void',
|
|
86
|
+
['behavior.write'],
|
|
87
|
+
'Hold this one agent while the world carries on.',
|
|
88
|
+
false,
|
|
89
|
+
),
|
|
90
|
+
define(
|
|
91
|
+
'paused',
|
|
92
|
+
[{ name: 'behavior', type: 'Behavior' }],
|
|
93
|
+
'bool',
|
|
94
|
+
['behavior.read'],
|
|
95
|
+
'Whether it is being held.',
|
|
96
|
+
),
|
|
97
|
+
define(
|
|
98
|
+
'status',
|
|
99
|
+
[{ name: 'behavior', type: 'Behavior' }],
|
|
100
|
+
'i32',
|
|
101
|
+
['behavior.read'],
|
|
102
|
+
'What the last tick answered, without ticking again.',
|
|
103
|
+
),
|
|
104
|
+
/*
|
|
105
|
+
* **The reason a tree beats a loop, from a script's side.** A hand-written routine keeps its
|
|
106
|
+
* state where nothing else can see it, so a script that wants to react to what an agent is doing
|
|
107
|
+
* keeps a second copy and the two drift. This reads the tree's own answer.
|
|
108
|
+
*/
|
|
109
|
+
define(
|
|
110
|
+
'doing',
|
|
111
|
+
[
|
|
112
|
+
{ name: 'behavior', type: 'Behavior' },
|
|
113
|
+
{ name: 'node', type: 'String' },
|
|
114
|
+
],
|
|
115
|
+
'bool',
|
|
116
|
+
['behavior.read'],
|
|
117
|
+
"Whether the agent is currently inside a node of this name — the routine's own answer, not a copy of it.",
|
|
118
|
+
),
|
|
119
|
+
define(
|
|
120
|
+
'depth',
|
|
121
|
+
[{ name: 'behavior', type: 'Behavior' }],
|
|
122
|
+
'i32',
|
|
123
|
+
['behavior.read'],
|
|
124
|
+
'How deep in the tree the last tick reached. For a debug readout.',
|
|
125
|
+
),
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
/** What a consumer hands the host so scripts can drive their agents' routines. */
|
|
129
|
+
export interface BehaviorServices {
|
|
130
|
+
/**
|
|
131
|
+
* What a character's tick is handed: a world, an entity, whatever the tree's own actions read.
|
|
132
|
+
*
|
|
133
|
+
* A function of the character rather than one context for all of them, because a routine is per
|
|
134
|
+
* agent and the thing its actions act on almost always is too.
|
|
135
|
+
*/
|
|
136
|
+
context(character: BehaviorRunner<unknown>): unknown;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function behaviorImplementation(services: BehaviorServices): Record<string, unknown> {
|
|
140
|
+
/* Reused across every `doing` call: the path is at most the tree's depth and this is read every
|
|
141
|
+
tick by anything watching an agent. */
|
|
142
|
+
let scratch: Uint32Array<ArrayBuffer> = new Uint32Array(32);
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
tick: (character: BehaviorRunner<unknown>) => character.tick(services.context(character)),
|
|
146
|
+
step: (character: BehaviorRunner<unknown>) => character.stepOnce(services.context(character)),
|
|
147
|
+
restart: (character: BehaviorRunner<unknown>) => character.reset(),
|
|
148
|
+
setPaused: (character: BehaviorRunner<unknown>, paused: boolean) => {
|
|
149
|
+
character.paused = paused;
|
|
150
|
+
},
|
|
151
|
+
paused: (character: BehaviorRunner<unknown>) => character.paused,
|
|
152
|
+
status: (character: BehaviorRunner<unknown>) => character.status,
|
|
153
|
+
depth(character: BehaviorRunner<unknown>): number {
|
|
154
|
+
scratch = fit(scratch, character);
|
|
155
|
+
return character.activePath(scratch);
|
|
156
|
+
},
|
|
157
|
+
doing(character: BehaviorRunner<unknown>, node: string): boolean {
|
|
158
|
+
scratch = fit(scratch, character);
|
|
159
|
+
const depth = character.activePath(scratch);
|
|
160
|
+
for (let i = 0; i < depth; i++) {
|
|
161
|
+
if (character.nameOf(scratch[i] ?? 0) === node) return true;
|
|
162
|
+
}
|
|
163
|
+
return false;
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Grow the scratch to hold this tree's deepest possible path.
|
|
170
|
+
*
|
|
171
|
+
* A path cannot be longer than the tree has nodes, so this settles after the first call per tree
|
|
172
|
+
* and never runs again — which is what keeps a per-tick read allocation-free in the steady state
|
|
173
|
+
* without asking a consumer to declare a depth they would have to keep correct.
|
|
174
|
+
*/
|
|
175
|
+
function fit(
|
|
176
|
+
scratch: Uint32Array<ArrayBuffer>,
|
|
177
|
+
character: BehaviorRunner<unknown>,
|
|
178
|
+
): Uint32Array<ArrayBuffer> {
|
|
179
|
+
const needed = character.tree.nodeCount;
|
|
180
|
+
return scratch.length >= needed ? scratch : new Uint32Array(needed);
|
|
181
|
+
}
|