1681-engine 0.5.10 → 0.6.1
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/CHANGELOG.md +61 -1
- package/README.md +12 -6
- package/dist/1681-engine.js +588 -522
- package/dist/ai/behaviorTree.js +198 -0
- package/dist/ai/buildTree.js +54 -0
- package/dist/audio/spatial.js +118 -0
- package/dist/cjs/electron/webPatcher.d.ts +4 -1
- package/dist/cjs/electron/webPatcher.js +9 -2
- package/dist/core/Camera.js +10 -0
- package/dist/core/ObjectFactory.js +23 -21
- package/dist/core/PixelGrid.js +47 -0
- package/dist/core/SharpText.js +72 -0
- package/dist/core/Stage.js +48 -31
- package/dist/core/gridPlacement.js +14 -0
- package/dist/dialogue/DialogueRunner.js +173 -0
- package/dist/dialogue/expr.js +137 -0
- package/dist/dialogue/validateDialogue.js +52 -0
- package/dist/ecs/prefab.js +94 -0
- package/dist/electron/webPatcher.js +16 -10
- package/dist/input/Actions.js +58 -27
- package/dist/input/InputCapture.js +98 -0
- package/dist/input/Keymap.js +32 -26
- package/dist/input/inputTape.js +68 -0
- package/dist/mobile/backButton.js +40 -0
- package/dist/mobile/capacitor.js +48 -0
- package/dist/mobile/screen.js +31 -0
- package/dist/mobile.js +12 -0
- package/dist/nav/flowField.js +58 -0
- package/dist/nav/steering.js +77 -0
- package/dist/net/InterpolationBuffer.js +30 -23
- package/dist/net/LagCompensator.js +100 -0
- package/dist/net/Room.js +122 -43
- package/dist/net/RoomHost.js +13 -4
- package/dist/net/SpatialHash.js +66 -0
- package/dist/types/ai/behaviorTree.d.ts +133 -0
- package/dist/types/ai/behaviorTree.d.ts.map +1 -0
- package/dist/types/ai/buildTree.d.ts +55 -0
- package/dist/types/ai/buildTree.d.ts.map +1 -0
- package/dist/types/audio/spatial.d.ts +107 -0
- package/dist/types/audio/spatial.d.ts.map +1 -0
- package/dist/types/core/Camera.d.ts +8 -0
- package/dist/types/core/Camera.d.ts.map +1 -1
- package/dist/types/core/ObjectFactory.d.ts.map +1 -1
- package/dist/types/core/PixelGrid.d.ts +30 -0
- package/dist/types/core/PixelGrid.d.ts.map +1 -0
- package/dist/types/core/SharpText.d.ts +32 -0
- package/dist/types/core/SharpText.d.ts.map +1 -0
- package/dist/types/core/Stage.d.ts +14 -0
- package/dist/types/core/Stage.d.ts.map +1 -1
- package/dist/types/core/gridPlacement.d.ts +20 -0
- package/dist/types/core/gridPlacement.d.ts.map +1 -0
- package/dist/types/dialogue/DialogueRunner.d.ts +78 -0
- package/dist/types/dialogue/DialogueRunner.d.ts.map +1 -0
- package/dist/types/dialogue/expr.d.ts +12 -0
- package/dist/types/dialogue/expr.d.ts.map +1 -0
- package/dist/types/dialogue/script.d.ts +78 -0
- package/dist/types/dialogue/script.d.ts.map +1 -0
- package/dist/types/dialogue/validateDialogue.d.ts +21 -0
- package/dist/types/dialogue/validateDialogue.d.ts.map +1 -0
- package/dist/types/ecs/prefab.d.ts +84 -0
- package/dist/types/ecs/prefab.d.ts.map +1 -0
- package/dist/types/electron/webPatcher.d.ts +4 -1
- package/dist/types/electron/webPatcher.d.ts.map +1 -1
- package/dist/types/index.d.ts +18 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/input/Actions.d.ts +14 -0
- package/dist/types/input/Actions.d.ts.map +1 -1
- package/dist/types/input/InputCapture.d.ts +53 -0
- package/dist/types/input/InputCapture.d.ts.map +1 -0
- package/dist/types/input/Keymap.d.ts +12 -6
- package/dist/types/input/Keymap.d.ts.map +1 -1
- package/dist/types/input/inputTape.d.ts +66 -0
- package/dist/types/input/inputTape.d.ts.map +1 -0
- package/dist/types/mobile/backButton.d.ts +30 -0
- package/dist/types/mobile/backButton.d.ts.map +1 -0
- package/dist/types/mobile/capacitor.d.ts +62 -0
- package/dist/types/mobile/capacitor.d.ts.map +1 -0
- package/dist/types/mobile/index.d.ts +4 -0
- package/dist/types/mobile/index.d.ts.map +1 -0
- package/dist/types/mobile/screen.d.ts +27 -0
- package/dist/types/mobile/screen.d.ts.map +1 -0
- package/dist/types/nav/flowField.d.ts +31 -0
- package/dist/types/nav/flowField.d.ts.map +1 -0
- package/dist/types/nav/steering.d.ts +47 -0
- package/dist/types/nav/steering.d.ts.map +1 -0
- package/dist/types/net/InterpolationBuffer.d.ts +5 -0
- package/dist/types/net/InterpolationBuffer.d.ts.map +1 -1
- package/dist/types/net/LagCompensator.d.ts +70 -0
- package/dist/types/net/LagCompensator.d.ts.map +1 -0
- package/dist/types/net/Room.d.ts +72 -3
- package/dist/types/net/Room.d.ts.map +1 -1
- package/dist/types/net/RoomHost.d.ts +8 -3
- package/dist/types/net/RoomHost.d.ts.map +1 -1
- package/dist/types/net/SpatialHash.d.ts +25 -0
- package/dist/types/net/SpatialHash.d.ts.map +1 -0
- package/dist/types/ui/ScrollView.d.ts.map +1 -1
- package/dist/ui/ScrollView.js +10 -8
- package/package.json +5 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
class k {
|
|
2
|
+
constructor(t) {
|
|
3
|
+
this.root = t;
|
|
4
|
+
}
|
|
5
|
+
root;
|
|
6
|
+
/** A new agent on this tree, with memory of its own. */
|
|
7
|
+
agent() {
|
|
8
|
+
return new p(this.root);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
class p {
|
|
12
|
+
constructor(t) {
|
|
13
|
+
this.root = t;
|
|
14
|
+
}
|
|
15
|
+
root;
|
|
16
|
+
now = 0;
|
|
17
|
+
memory = /* @__PURE__ */ new Map();
|
|
18
|
+
kept = /* @__PURE__ */ new Map();
|
|
19
|
+
/** Nodes that answered 'running' last time they ticked: the ones a halt must reach. */
|
|
20
|
+
open = /* @__PURE__ */ new Set();
|
|
21
|
+
last = /* @__PURE__ */ new Map();
|
|
22
|
+
seen = /* @__PURE__ */ new Map();
|
|
23
|
+
/** Ticks the tree once at time `now` (ms) and returns the root's answer. */
|
|
24
|
+
update(t, e) {
|
|
25
|
+
this.now = e, this.seen = /* @__PURE__ */ new Map();
|
|
26
|
+
const n = this.tick(this.root, t);
|
|
27
|
+
return this.last = this.seen, n;
|
|
28
|
+
}
|
|
29
|
+
/** Halts whatever is running and forgets all memory: the agent starts the tree afresh (it died, it was stunned). */
|
|
30
|
+
reset(t) {
|
|
31
|
+
this.halt(this.root, t), this.memory.clear(), this.kept.clear(), this.open.clear(), this.last.clear();
|
|
32
|
+
}
|
|
33
|
+
/** Whether a node is running for this agent now. */
|
|
34
|
+
isRunning(t) {
|
|
35
|
+
return this.open.has(t);
|
|
36
|
+
}
|
|
37
|
+
state(t, e) {
|
|
38
|
+
return this.memory.has(t) || this.memory.set(t, e()), this.memory.get(t);
|
|
39
|
+
}
|
|
40
|
+
lasting(t, e) {
|
|
41
|
+
return this.kept.has(t) || this.kept.set(t, e()), this.kept.get(t);
|
|
42
|
+
}
|
|
43
|
+
tick(t, e) {
|
|
44
|
+
const n = t.tick(e, this);
|
|
45
|
+
return this.seen.set(t, n), n === "running" ? this.open.add(t) : (this.open.delete(t), this.memory.delete(t)), n;
|
|
46
|
+
}
|
|
47
|
+
halt(t, e) {
|
|
48
|
+
if (this.open.has(t)) {
|
|
49
|
+
for (const n of t.children) this.halt(n, e);
|
|
50
|
+
t.halt?.(e, this), this.open.delete(t), this.memory.delete(t);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** The tree as it ran on the last tick, depth first: for a debug overlay. */
|
|
54
|
+
trace() {
|
|
55
|
+
const t = [], e = (n, r) => {
|
|
56
|
+
t.push({ depth: r, kind: n.kind, name: n.name, status: this.last.get(n) ?? null });
|
|
57
|
+
for (const o of n.children) e(o, r + 1);
|
|
58
|
+
};
|
|
59
|
+
return e(this.root, 0), t;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function m(s) {
|
|
63
|
+
return s.map((t) => `${" ".repeat(t.depth)}${t.name ?? t.kind} ${t.status ?? "·"}`).join(`
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
const u = (s, t, e, n = {}) => ({
|
|
67
|
+
kind: s,
|
|
68
|
+
children: t,
|
|
69
|
+
tick: e,
|
|
70
|
+
...n
|
|
71
|
+
});
|
|
72
|
+
function w(...s) {
|
|
73
|
+
const t = u("sequence", s, (e, n) => {
|
|
74
|
+
const r = n.state(t, () => ({ i: 0 }));
|
|
75
|
+
for (; r.i < s.length; r.i++) {
|
|
76
|
+
const o = n.tick(s[r.i], e);
|
|
77
|
+
if (o !== "success") return o;
|
|
78
|
+
}
|
|
79
|
+
return "success";
|
|
80
|
+
});
|
|
81
|
+
return t;
|
|
82
|
+
}
|
|
83
|
+
function y(...s) {
|
|
84
|
+
const t = u("selector", s, (e, n) => {
|
|
85
|
+
const r = n.state(t, () => ({ i: 0 }));
|
|
86
|
+
for (; r.i < s.length; r.i++) {
|
|
87
|
+
const o = n.tick(s[r.i], e);
|
|
88
|
+
if (o !== "failure") return o;
|
|
89
|
+
}
|
|
90
|
+
return "failure";
|
|
91
|
+
});
|
|
92
|
+
return t;
|
|
93
|
+
}
|
|
94
|
+
function v(...s) {
|
|
95
|
+
return g("reactive-sequence", s, "success");
|
|
96
|
+
}
|
|
97
|
+
function M(...s) {
|
|
98
|
+
return g("reactive-selector", s, "failure");
|
|
99
|
+
}
|
|
100
|
+
function g(s, t, e) {
|
|
101
|
+
return u(s, t, (n, r) => {
|
|
102
|
+
for (let o = 0; o < t.length; o++) {
|
|
103
|
+
const i = r.tick(t[o], n);
|
|
104
|
+
if (i !== e) {
|
|
105
|
+
for (let c = o + 1; c < t.length; c++) r.halt(t[c], n);
|
|
106
|
+
return i;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return e;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function b(s, ...t) {
|
|
113
|
+
const e = Math.min(t.length, s.succeed ?? t.length), n = Math.min(t.length, s.fail ?? 1), r = u("parallel", t, (o, i) => {
|
|
114
|
+
const c = i.state(r, () => /* @__PURE__ */ new Map());
|
|
115
|
+
for (let a = 0; a < t.length; a++) {
|
|
116
|
+
if (c.has(a)) continue;
|
|
117
|
+
const h = i.tick(t[a], o);
|
|
118
|
+
h !== "running" && c.set(a, h);
|
|
119
|
+
}
|
|
120
|
+
let f = 0, l = 0;
|
|
121
|
+
for (const a of c.values()) a === "success" ? f++ : l++;
|
|
122
|
+
if (f < e && l < n) return "running";
|
|
123
|
+
for (const a of t) i.halt(a, o);
|
|
124
|
+
return f >= e ? "success" : "failure";
|
|
125
|
+
});
|
|
126
|
+
return r;
|
|
127
|
+
}
|
|
128
|
+
function q(s) {
|
|
129
|
+
return u("invert", [s], (t, e) => {
|
|
130
|
+
const n = e.tick(s, t);
|
|
131
|
+
return n === "success" ? "failure" : n === "failure" ? "success" : "running";
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function A(s) {
|
|
135
|
+
return u("succeed", [s], (t, e) => e.tick(s, t) === "running" ? "running" : "success");
|
|
136
|
+
}
|
|
137
|
+
function S(s, t) {
|
|
138
|
+
const e = u("repeat", [t], (n, r) => {
|
|
139
|
+
const o = r.state(e, () => ({ n: 0 })), i = r.tick(t, n);
|
|
140
|
+
return i !== "success" ? i : (o.n++, o.n >= s ? "success" : "running");
|
|
141
|
+
});
|
|
142
|
+
return e;
|
|
143
|
+
}
|
|
144
|
+
function $(s, t) {
|
|
145
|
+
const e = u("retry", [t], (n, r) => {
|
|
146
|
+
const o = r.state(e, () => ({ n: 0 })), i = r.tick(t, n);
|
|
147
|
+
return i !== "failure" ? i : (o.n++, o.n >= s ? "failure" : "running");
|
|
148
|
+
});
|
|
149
|
+
return e;
|
|
150
|
+
}
|
|
151
|
+
function j(s, t) {
|
|
152
|
+
const e = u("cooldown", [t], (n, r) => {
|
|
153
|
+
const o = r.lasting(e, () => ({ readyAt: -1 / 0 }));
|
|
154
|
+
if (r.now < o.readyAt) return "failure";
|
|
155
|
+
const i = r.tick(t, n);
|
|
156
|
+
return i !== "running" && (o.readyAt = r.now + s), i;
|
|
157
|
+
});
|
|
158
|
+
return e;
|
|
159
|
+
}
|
|
160
|
+
function B(s, t) {
|
|
161
|
+
const e = u("timeout", [t], (n, r) => {
|
|
162
|
+
const o = r.state(e, () => ({ began: r.now }));
|
|
163
|
+
return r.now - o.began >= s ? (r.halt(t, n), "failure") : r.tick(t, n);
|
|
164
|
+
});
|
|
165
|
+
return e;
|
|
166
|
+
}
|
|
167
|
+
function H(s) {
|
|
168
|
+
const t = u("wait", [], (e, n) => {
|
|
169
|
+
const r = n.state(t, () => ({ began: n.now }));
|
|
170
|
+
return n.now - r.began >= s ? "success" : "running";
|
|
171
|
+
});
|
|
172
|
+
return t;
|
|
173
|
+
}
|
|
174
|
+
function T(s, t) {
|
|
175
|
+
return u("condition", [], (e) => t(e) ? "success" : "failure", { name: s });
|
|
176
|
+
}
|
|
177
|
+
function F(s, t, e = {}) {
|
|
178
|
+
return u("action", [], (n, r) => t(n, r.now), { name: s, halt: e.onHalt ? (n) => e.onHalt(n) : void 0 });
|
|
179
|
+
}
|
|
180
|
+
export {
|
|
181
|
+
k as BehaviorTree,
|
|
182
|
+
p as BtAgent,
|
|
183
|
+
F as action,
|
|
184
|
+
T as condition,
|
|
185
|
+
j as cooldown,
|
|
186
|
+
m as formatTrace,
|
|
187
|
+
q as invert,
|
|
188
|
+
b as parallel,
|
|
189
|
+
M as reactiveSelector,
|
|
190
|
+
v as reactiveSequence,
|
|
191
|
+
S as repeat,
|
|
192
|
+
$ as retry,
|
|
193
|
+
y as selector,
|
|
194
|
+
w as sequence,
|
|
195
|
+
A as succeed,
|
|
196
|
+
B as timeout,
|
|
197
|
+
H as wait
|
|
198
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { action as m, condition as s, wait as h, timeout as $, cooldown as y, retry as b, repeat as w, succeed as q, invert as v, parallel as S, reactiveSelector as k, reactiveSequence as A, selector as H, sequence as T } from "./behaviorTree.js";
|
|
2
|
+
function x(e, t) {
|
|
3
|
+
return l(e, t, "$", []);
|
|
4
|
+
}
|
|
5
|
+
function l(e, t, u, c) {
|
|
6
|
+
const r = (n) => {
|
|
7
|
+
throw new Error(`buildTree: ${u}: ${n}`);
|
|
8
|
+
};
|
|
9
|
+
if (!e || typeof e != "object") return r("not a node");
|
|
10
|
+
const a = (n) => !Array.isArray(n) || n.length === 0 ? r("needs children") : n.map((d, f) => l(d, t, `${u}.children[${f}]`, c)), i = (n) => l(n, t, `${u}.child`, c), o = (n, d) => typeof n == "number" && n >= 0 ? n : r(`${d} must be a number of at least 0`);
|
|
11
|
+
switch (e.type) {
|
|
12
|
+
case "sequence":
|
|
13
|
+
return T(...a(e.children));
|
|
14
|
+
case "selector":
|
|
15
|
+
return H(...a(e.children));
|
|
16
|
+
case "reactiveSequence":
|
|
17
|
+
return A(...a(e.children));
|
|
18
|
+
case "reactiveSelector":
|
|
19
|
+
return k(...a(e.children));
|
|
20
|
+
case "parallel":
|
|
21
|
+
return S({ succeed: e.succeed, fail: e.fail }, ...a(e.children));
|
|
22
|
+
case "invert":
|
|
23
|
+
return v(i(e.child));
|
|
24
|
+
case "succeed":
|
|
25
|
+
return q(i(e.child));
|
|
26
|
+
case "repeat":
|
|
27
|
+
return w(o(e.times, "times"), i(e.child));
|
|
28
|
+
case "retry":
|
|
29
|
+
return b(o(e.times, "times"), i(e.child));
|
|
30
|
+
case "cooldown":
|
|
31
|
+
return y(o(e.ms, "ms"), i(e.child));
|
|
32
|
+
case "timeout":
|
|
33
|
+
return $(o(e.ms, "ms"), i(e.child));
|
|
34
|
+
case "wait":
|
|
35
|
+
return h(o(e.ms, "ms"));
|
|
36
|
+
case "condition": {
|
|
37
|
+
const n = t.conditions?.[e.name];
|
|
38
|
+
return n ? s(e.name, n) : r(`no condition '${e.name}'`);
|
|
39
|
+
}
|
|
40
|
+
case "action": {
|
|
41
|
+
const n = t.actions?.[e.name];
|
|
42
|
+
return n ? typeof n == "function" ? m(e.name, n) : m(e.name, n.run, { onHalt: n.onHalt }) : r(`no action '${e.name}'`);
|
|
43
|
+
}
|
|
44
|
+
case "tree": {
|
|
45
|
+
const n = t.trees?.[e.name];
|
|
46
|
+
return n ? c.includes(e.name) ? r(`tree '${e.name}' contains itself`) : l(n, t, `${u}<${e.name}>`, [...c, e.name]) : r(`no tree '${e.name}'`);
|
|
47
|
+
}
|
|
48
|
+
default:
|
|
49
|
+
return r(`unknown type '${e.type}'`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
x as buildTree
|
|
54
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const l = [18e3, 1800];
|
|
2
|
+
function f(c, t, e = {}) {
|
|
3
|
+
const i = e.range ?? 480, s = t.x - c.x, n = Math.hypot(s, t.y - c.y), r = e.maxPan ?? 0.8, h = Math.max(-r, Math.min(r, s / (e.panWidth ?? i / 2))), o = e.muffle === void 0 ? l : e.muffle, a = Math.min(1, n / i), u = o ? o[0] * Math.pow(o[1] / o[0], a) : 2e4;
|
|
4
|
+
return n >= i ? { audible: !1, gain: 0, pan: h, cutoffHz: u } : { audible: !0, gain: Math.pow(1 - a, e.rolloff ?? 1.5), pan: h, cutoffHz: u };
|
|
5
|
+
}
|
|
6
|
+
const m = 0.05;
|
|
7
|
+
class d {
|
|
8
|
+
constructor(t, e = t.destination) {
|
|
9
|
+
this.context = t, this.output = t.createGain(), this.output.connect(e);
|
|
10
|
+
}
|
|
11
|
+
context;
|
|
12
|
+
/** Every emitter's gain goes through this: the game's volume setting. */
|
|
13
|
+
output;
|
|
14
|
+
emitters = /* @__PURE__ */ new Set();
|
|
15
|
+
here = { x: 0, y: 0 };
|
|
16
|
+
/** The listener's place as of the last `update`. */
|
|
17
|
+
get listener() {
|
|
18
|
+
return this.here;
|
|
19
|
+
}
|
|
20
|
+
/** How many emitters are alive (playing or waiting out of range). */
|
|
21
|
+
get size() {
|
|
22
|
+
return this.emitters.size;
|
|
23
|
+
}
|
|
24
|
+
/** A sound at (x, y), looping by default. Starts at once when in range of the listener. */
|
|
25
|
+
emitter(t, e, i, s = {}) {
|
|
26
|
+
const n = new p(this, t, e, i, s);
|
|
27
|
+
return this.emitters.add(n), n.refresh(this.here, !1), n;
|
|
28
|
+
}
|
|
29
|
+
/** A one-shot at (x, y), dropped when it ends; skipped (and done at once) when out of range. */
|
|
30
|
+
play(t, e, i, s = {}) {
|
|
31
|
+
return this.emitter(t, e, i, { ...s, loop: !1 });
|
|
32
|
+
}
|
|
33
|
+
/** Moves the listener and re-mixes every emitter. Call once a frame. */
|
|
34
|
+
update(t = this.here) {
|
|
35
|
+
this.here = { x: t.x, y: t.y };
|
|
36
|
+
for (const e of this.emitters) e.refresh(this.here, !0);
|
|
37
|
+
}
|
|
38
|
+
/** Stops every emitter. */
|
|
39
|
+
stopAll(t = 0) {
|
|
40
|
+
for (const e of [...this.emitters]) e.stop(t);
|
|
41
|
+
}
|
|
42
|
+
destroy() {
|
|
43
|
+
this.stopAll(), this.output.disconnect();
|
|
44
|
+
}
|
|
45
|
+
/** @internal */
|
|
46
|
+
forget(t) {
|
|
47
|
+
this.emitters.delete(t);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
class p {
|
|
51
|
+
constructor(t, e, i, s, n) {
|
|
52
|
+
this.owner = t, this.buffer = e, this.x = i, this.y = s, this.options = n;
|
|
53
|
+
const r = t.context;
|
|
54
|
+
this.volume = n.volume ?? 1, this.rate = n.playbackRate ?? 1, this.origin = r.currentTime, this.filter = r.createBiquadFilter(), this.filter.type = "lowpass", this.gain = r.createGain(), this.panner = r.createStereoPanner(), this.filter.connect(this.gain).connect(this.panner).connect(t.output);
|
|
55
|
+
}
|
|
56
|
+
owner;
|
|
57
|
+
buffer;
|
|
58
|
+
x;
|
|
59
|
+
y;
|
|
60
|
+
options;
|
|
61
|
+
volume;
|
|
62
|
+
done = !1;
|
|
63
|
+
source = null;
|
|
64
|
+
gain;
|
|
65
|
+
panner;
|
|
66
|
+
filter;
|
|
67
|
+
/** When the loop would have begun, had it never stopped: where a restart picks it up. */
|
|
68
|
+
origin;
|
|
69
|
+
rate;
|
|
70
|
+
get playing() {
|
|
71
|
+
return this.source !== null;
|
|
72
|
+
}
|
|
73
|
+
refresh(t, e) {
|
|
74
|
+
if (this.done) return;
|
|
75
|
+
const i = f(t, this, this.options), s = this.options.loop ?? !0;
|
|
76
|
+
if (!i.audible) {
|
|
77
|
+
if (!s) return this.stop();
|
|
78
|
+
this.halt();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const n = this.owner.context, r = n.currentTime, h = (o, a) => e && this.source ? o.setTargetAtTime(a, r, m) : o.setValueAtTime(a, r);
|
|
82
|
+
h(this.gain.gain, i.gain * Math.max(0, Math.min(1, this.volume))), h(this.panner.pan, i.pan), h(this.filter.frequency, Math.min(i.cutoffHz, n.sampleRate / 2)), this.source || this.begin(s);
|
|
83
|
+
}
|
|
84
|
+
stop(t = 0) {
|
|
85
|
+
if (this.done) return;
|
|
86
|
+
this.done = !0, this.owner.forget(this);
|
|
87
|
+
const e = this.source, i = this.owner.context;
|
|
88
|
+
if (e && t > 0) {
|
|
89
|
+
const s = i.currentTime + t / 1e3;
|
|
90
|
+
this.gain.gain.setValueAtTime(this.gain.gain.value, i.currentTime), this.gain.gain.linearRampToValueAtTime(0, s), e.stop(s), e.onended = () => this.release();
|
|
91
|
+
} else
|
|
92
|
+
this.halt(), this.release();
|
|
93
|
+
}
|
|
94
|
+
begin(t) {
|
|
95
|
+
const e = this.owner.context, i = e.createBufferSource();
|
|
96
|
+
i.buffer = this.buffer, i.loop = t, i.playbackRate.value = this.rate, i.connect(this.filter);
|
|
97
|
+
const s = t ? (e.currentTime - this.origin) * this.rate % this.buffer.duration : 0;
|
|
98
|
+
i.start(e.currentTime, s), t || (i.onended = () => this.stop()), this.source = i;
|
|
99
|
+
}
|
|
100
|
+
halt() {
|
|
101
|
+
const t = this.source;
|
|
102
|
+
if (t) {
|
|
103
|
+
this.source = null, t.onended = null;
|
|
104
|
+
try {
|
|
105
|
+
t.stop();
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
108
|
+
t.disconnect();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
release() {
|
|
112
|
+
this.filter.disconnect(), this.gain.disconnect(), this.panner.disconnect();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
d as SpatialAudio,
|
|
117
|
+
f as spatialMix
|
|
118
|
+
};
|
|
@@ -47,6 +47,7 @@ export declare class WebPatcher {
|
|
|
47
47
|
private loaded;
|
|
48
48
|
/** The tidy a start began: a build waits for it, or it could delete the `.part` folder being filled. */
|
|
49
49
|
private tidying;
|
|
50
|
+
private tidyChain;
|
|
50
51
|
constructor(options: WebPatcherOptions);
|
|
51
52
|
/** This shell's identity. */
|
|
52
53
|
get shell(): string;
|
|
@@ -75,6 +76,8 @@ export declare class WebPatcher {
|
|
|
75
76
|
private promote;
|
|
76
77
|
/** A pointer this shell may load: its own shell, newer than the installed build, its folder whole. */
|
|
77
78
|
private usable;
|
|
78
|
-
/** Removes every patched web but the active, pending and previous one, and any half-made folder.
|
|
79
|
+
/** Removes every patched web but the active, pending and previous one, and any half-made folder. A call made while
|
|
80
|
+
* one is running waits for it and then runs once more, so two never delete the same folder at once. */
|
|
79
81
|
tidy(): Promise<void>;
|
|
82
|
+
private tidyOnce;
|
|
80
83
|
}
|
|
@@ -27,6 +27,7 @@ class WebPatcher {
|
|
|
27
27
|
loaded = null;
|
|
28
28
|
/** The tidy a start began: a build waits for it, or it could delete the `.part` folder being filled. */
|
|
29
29
|
tidying = Promise.resolve();
|
|
30
|
+
tidyChain = Promise.resolve();
|
|
30
31
|
constructor(options) {
|
|
31
32
|
this.options = options;
|
|
32
33
|
this.o = {
|
|
@@ -197,8 +198,14 @@ class WebPatcher {
|
|
|
197
198
|
usable(p) {
|
|
198
199
|
return !!p && p.shell === this.shell && (0, manifest_1.isNewer)(p.version, this.o.appVersion) && (0, node_fs_1.existsSync)((0, node_path_1.join)(this.o.root, p.version, this.o.entry));
|
|
199
200
|
}
|
|
200
|
-
/** Removes every patched web but the active, pending and previous one, and any half-made folder.
|
|
201
|
-
|
|
201
|
+
/** Removes every patched web but the active, pending and previous one, and any half-made folder. A call made while
|
|
202
|
+
* one is running waits for it and then runs once more, so two never delete the same folder at once. */
|
|
203
|
+
tidy() {
|
|
204
|
+
const next = this.tidyChain.then(() => this.tidyOnce());
|
|
205
|
+
this.tidyChain = next;
|
|
206
|
+
return next;
|
|
207
|
+
}
|
|
208
|
+
async tidyOnce() {
|
|
202
209
|
try {
|
|
203
210
|
const names = ['active', 'pending', 'previous'];
|
|
204
211
|
const keep = new Set([...names.map((n) => this.pointers.read(n)?.version), this.loaded?.version].filter((v) => !!v));
|
package/dist/core/Camera.js
CHANGED
|
@@ -12,6 +12,8 @@ class g {
|
|
|
12
12
|
resolution = 1;
|
|
13
13
|
/** Lands the view on whole backing pixels (pixel art); off, the world moves smoothly between them. */
|
|
14
14
|
roundPixels = !1;
|
|
15
|
+
/** The world is drawn on its own pixel grid (`Stage.pixelPerfect`): `snapRoot` lands on whole world pixels. Set by the stage. */
|
|
16
|
+
pixelGrid = !1;
|
|
15
17
|
scrollX = 0;
|
|
16
18
|
scrollY = 0;
|
|
17
19
|
width = 0;
|
|
@@ -42,6 +44,14 @@ class g {
|
|
|
42
44
|
const s = this.zoom * this.resolution;
|
|
43
45
|
return Math.round(t * s) / s;
|
|
44
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Where an object's root lands (a body, and whatever is laid over one): a whole world pixel while the world is drawn
|
|
49
|
+
* on its own grid (`Stage.pixelPerfect`), else `snap`. One rule for every root, so a body, what it holds and what
|
|
50
|
+
* points at it fall on the same pixel; children keep whole-pixel offsets from it.
|
|
51
|
+
*/
|
|
52
|
+
snapRoot(t) {
|
|
53
|
+
return this.pixelGrid ? Math.round(t) : this.snap(t);
|
|
54
|
+
}
|
|
45
55
|
setBounds(t, s, h, e) {
|
|
46
56
|
return this.bounds = { x: t, y: s, width: h, height: e }, this;
|
|
47
57
|
}
|
|
@@ -1,45 +1,47 @@
|
|
|
1
|
-
import { BitmapLabel as
|
|
2
|
-
import { Graphics as
|
|
3
|
-
import { Group as
|
|
4
|
-
import { Image as
|
|
5
|
-
import { Rectangle as
|
|
6
|
-
import { Text as
|
|
1
|
+
import { BitmapLabel as g } from "./BitmapLabel.js";
|
|
2
|
+
import { Graphics as p } from "./Graphics.js";
|
|
3
|
+
import { Group as u } from "./Group.js";
|
|
4
|
+
import { Image as l } from "./Image.js";
|
|
5
|
+
import { Rectangle as x } from "./Rectangle.js";
|
|
6
|
+
import { Text as f } from "./Text.js";
|
|
7
7
|
class L {
|
|
8
8
|
constructor(t) {
|
|
9
9
|
this.stage = t;
|
|
10
10
|
}
|
|
11
11
|
stage;
|
|
12
|
-
image(t, e, r,
|
|
13
|
-
return this.attach(new
|
|
12
|
+
image(t, e, r, s) {
|
|
13
|
+
return this.attach(new l(this.stage.textures, t, e, r, s));
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* A copy of `src` as it is drawn right now (afterimages, clones). A live texture, repainted every frame, is
|
|
17
17
|
* snapshotted first, and the snapshot is freed with the copy.
|
|
18
18
|
*/
|
|
19
19
|
still(t, e, r) {
|
|
20
|
-
const
|
|
21
|
-
if (!
|
|
22
|
-
const
|
|
23
|
-
return i.once("destroyed", () =>
|
|
20
|
+
const s = this.stage.textures;
|
|
21
|
+
if (!s.isLive(r.textureKey)) return this.image(t, e, r.textureKey, r.frameName);
|
|
22
|
+
const a = s.snapshot(r.textureKey, r.frameName), i = this.image(t, e, a, "0");
|
|
23
|
+
return i.once("destroyed", () => s.remove(a)), i;
|
|
24
24
|
}
|
|
25
25
|
graphics(t) {
|
|
26
|
-
const e = this.attach(new
|
|
26
|
+
const e = this.attach(new p());
|
|
27
27
|
return e.position.set(t?.x ?? 0, t?.y ?? 0), e;
|
|
28
28
|
}
|
|
29
29
|
container(t = 0, e = 0, r = []) {
|
|
30
|
-
const
|
|
31
|
-
return
|
|
30
|
+
const s = this.attach(new u());
|
|
31
|
+
return s.position.set(t, e), s.add(r), s;
|
|
32
32
|
}
|
|
33
|
-
rectangle(t, e, r,
|
|
34
|
-
const n = this.attach(new
|
|
33
|
+
rectangle(t, e, r, s, a, i = 1) {
|
|
34
|
+
const n = this.attach(new x(r, s, a, i));
|
|
35
35
|
return n.position.set(t, e), n;
|
|
36
36
|
}
|
|
37
|
-
text(t, e, r,
|
|
38
|
-
|
|
37
|
+
text(t, e, r, s) {
|
|
38
|
+
const a = this.attach(new f(t, e, r, s));
|
|
39
|
+
return this.stage.keepSharp(a), a;
|
|
39
40
|
}
|
|
40
41
|
/** A bitmap-font label (`BitmapLabel`): cheap to change, for text rewritten many times a second. */
|
|
41
|
-
label(t, e, r,
|
|
42
|
-
|
|
42
|
+
label(t, e, r, s, a, i, n, h, c, m = "") {
|
|
43
|
+
const o = this.attach(new g(t, e, r, s, a, i, n, h, c, m));
|
|
44
|
+
return this.stage.keepSharp(o), o;
|
|
43
45
|
}
|
|
44
46
|
/** Puts an object made elsewhere on the world layer, as the factory's own are (a `PixelLayer`, a custom class). */
|
|
45
47
|
existing(t) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Matrix as n, Sprite as l, RenderTexture as a } from "pixi.js";
|
|
2
|
+
import { gridPlacement as d } from "./gridPlacement.js";
|
|
3
|
+
import { SharpText as x } from "./SharpText.js";
|
|
4
|
+
class m {
|
|
5
|
+
constructor(e, t) {
|
|
6
|
+
this.app = e, this.world = t, this.text = new x(t);
|
|
7
|
+
}
|
|
8
|
+
app;
|
|
9
|
+
world;
|
|
10
|
+
texture = null;
|
|
11
|
+
sprite = null;
|
|
12
|
+
text;
|
|
13
|
+
transform = new n();
|
|
14
|
+
on = !1;
|
|
15
|
+
get enabled() {
|
|
16
|
+
return this.on;
|
|
17
|
+
}
|
|
18
|
+
/** Once a frame, after the camera wrote the world's transform and before Pixi draws the screen. */
|
|
19
|
+
render(e, t) {
|
|
20
|
+
if (t !== this.on && (t ? this.enable(e) : this.disable(e)), !t) return;
|
|
21
|
+
const i = e.zoom || 1, s = this.world.position, r = d(s.x, s.y, i, this.app.renderer.resolution, e.width, e.height), o = this.fit(r.width, r.height);
|
|
22
|
+
this.transform.set(1, 0, 0, 1, -r.tx, -r.ty), this.app.renderer.render({ container: this.world, target: o, clear: !0, clearColor: [0, 0, 0, 0], transform: this.transform });
|
|
23
|
+
const h = this.sprite;
|
|
24
|
+
h.scale.set(i), h.position.set(r.x, r.y), this.text.sync(s, i);
|
|
25
|
+
}
|
|
26
|
+
destroy(e) {
|
|
27
|
+
this.disable(e), this.text.destroy();
|
|
28
|
+
}
|
|
29
|
+
enable(e) {
|
|
30
|
+
this.on = !0, e.pixelGrid = !0;
|
|
31
|
+
const t = this.app.stage, i = Math.max(0, t.children.indexOf(this.world));
|
|
32
|
+
t.removeChild(this.world), this.sprite = new l(), t.addChildAt(this.sprite, i), t.addChildAt(this.text.layer, i + 1);
|
|
33
|
+
}
|
|
34
|
+
disable(e) {
|
|
35
|
+
if (!this.on) return;
|
|
36
|
+
this.on = !1, e.pixelGrid = !1, this.text.release();
|
|
37
|
+
const t = this.app.stage, i = Math.max(0, this.sprite ? t.children.indexOf(this.sprite) : 0);
|
|
38
|
+
t.removeChild(this.text.layer), this.sprite?.destroy(), this.sprite = null, this.texture?.destroy(!0), this.texture = null, this.world.destroyed || t.addChildAt(this.world, i);
|
|
39
|
+
}
|
|
40
|
+
/** The texture at exactly this size, made again only when the screen or the zoom changed. */
|
|
41
|
+
fit(e, t) {
|
|
42
|
+
return this.texture && this.texture.width === e && this.texture.height === t ? this.texture : (this.texture?.destroy(!0), this.texture = a.create({ width: e, height: t, resolution: 1, scaleMode: "nearest", antialias: !1 }), this.sprite.texture = this.texture, this.texture);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
m as PixelGrid
|
|
47
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Container as n, Matrix as d } from "pixi.js";
|
|
2
|
+
class c {
|
|
3
|
+
constructor(e) {
|
|
4
|
+
this.world = e;
|
|
5
|
+
}
|
|
6
|
+
world;
|
|
7
|
+
layer = new n({ sortableChildren: !0 });
|
|
8
|
+
labels = /* @__PURE__ */ new Set();
|
|
9
|
+
m = new d();
|
|
10
|
+
/** Labels tracked since the last sweep for destroyed ones: off, nothing else sweeps them. */
|
|
11
|
+
sinceSweep = 0;
|
|
12
|
+
track(e) {
|
|
13
|
+
this.labels.add({ obj: e, home: null, wrap: null }), ++this.sinceSweep >= 256 && this.prune();
|
|
14
|
+
}
|
|
15
|
+
/** Lays the layer over the world (`origin`: where the world's origin lands on screen) and every label on its home. */
|
|
16
|
+
sync(e, r) {
|
|
17
|
+
this.layer.position.set(e.x, e.y), this.layer.scale.set(r);
|
|
18
|
+
for (const t of this.labels) {
|
|
19
|
+
const s = t.obj;
|
|
20
|
+
if (s.destroyed) {
|
|
21
|
+
this.drop(t);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
s.parent && s.parent !== t.wrap && (t.home = s.parent, t.wrap ??= this.layer.addChild(new n()), t.wrap.addChild(s));
|
|
25
|
+
const o = t.home, i = t.wrap;
|
|
26
|
+
if (!(!o || !i)) {
|
|
27
|
+
if (o.destroyed) {
|
|
28
|
+
s.destroy(), this.drop(t);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
this.place(o, i, s);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Every label back in its home (the grid switched off), the stand-ins gone. */
|
|
36
|
+
release() {
|
|
37
|
+
for (const e of this.labels) {
|
|
38
|
+
const { obj: r, home: t, wrap: s } = e;
|
|
39
|
+
if (r.destroyed) {
|
|
40
|
+
this.drop(e);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
t && s && r.parent === s && (t.destroyed ? r.destroy() : t.addChild(r)), s?.destroy(), e.wrap = null, e.home = null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Forgets labels the game destroyed while nothing synced (the grid off). */
|
|
47
|
+
prune() {
|
|
48
|
+
this.sinceSweep = 0;
|
|
49
|
+
for (const e of this.labels) e.obj.destroyed && this.drop(e);
|
|
50
|
+
}
|
|
51
|
+
destroy() {
|
|
52
|
+
this.release(), this.labels.clear(), this.layer.destroy({ children: !0 });
|
|
53
|
+
}
|
|
54
|
+
place(e, r, t) {
|
|
55
|
+
const s = this.m.identity();
|
|
56
|
+
let o = !0, i = 1, a = e;
|
|
57
|
+
for (let l = e; l !== this.world; l = l.parent) {
|
|
58
|
+
if (!l) {
|
|
59
|
+
o = !1;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
(!l.visible || !l.renderable) && (o = !1), i *= l.alpha, l.updateLocalTransform(), s.prepend(l.localTransform), a = l;
|
|
63
|
+
}
|
|
64
|
+
r.visible = o, o && (r.setFromMatrix(s), r.alpha = i, r.zIndex = e === this.world ? t.zIndex : a.zIndex);
|
|
65
|
+
}
|
|
66
|
+
drop(e) {
|
|
67
|
+
e.wrap?.destroy(), this.labels.delete(e);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
c as SharpText
|
|
72
|
+
};
|