1681-engine 0.5.10 → 0.6.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/CHANGELOG.md +50 -1
- package/README.md +12 -6
- package/dist/1681-engine.js +582 -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/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/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 +15 -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,137 @@
|
|
|
1
|
+
const A = ["&&", "||", "==", "!=", "<=", ">=", "<", ">", "!", "+", "-", "*", "/", "%", "(", ")", ","];
|
|
2
|
+
function N(r) {
|
|
3
|
+
const i = [];
|
|
4
|
+
let o = 0;
|
|
5
|
+
for (; o < r.length; ) {
|
|
6
|
+
const l = r[o];
|
|
7
|
+
if (/\s/.test(l)) {
|
|
8
|
+
o++;
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
if (/[0-9.]/.test(l)) {
|
|
12
|
+
const c = /^(?:\d+\.?\d*|\.\d+)/.exec(r.slice(o));
|
|
13
|
+
if (!c) throw new Error(`bad number at ${o}`);
|
|
14
|
+
i.push({ k: "num", v: Number(c[0]) }), o += c[0].length;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (l === '"' || l === "'") {
|
|
18
|
+
let c = o + 1, p = "";
|
|
19
|
+
for (; c < r.length && r[c] !== l; )
|
|
20
|
+
r[c] === "\\" && c + 1 < r.length && c++, p += r[c], c++;
|
|
21
|
+
if (c >= r.length) throw new Error(`unclosed string at ${o}`);
|
|
22
|
+
i.push({ k: "str", v: p }), o = c + 1;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (/[A-Za-z_$]/.test(l)) {
|
|
26
|
+
const c = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*/.exec(r.slice(o));
|
|
27
|
+
i.push({ k: "id", v: c[0] }), o += c[0].length;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const f = A.find((c) => r.startsWith(c, o));
|
|
31
|
+
if (!f) throw new Error(`unexpected '${l}' at ${o}`);
|
|
32
|
+
i.push({ k: "op", v: f }), o += f.length;
|
|
33
|
+
}
|
|
34
|
+
return i;
|
|
35
|
+
}
|
|
36
|
+
const m = (r) => !!r, k = (r, i) => r === i || r == null && i == null, s = (r) => typeof r == "number" ? r : typeof r == "boolean" ? Number(r) : r == null ? 0 : Number(r);
|
|
37
|
+
function Z(r) {
|
|
38
|
+
let i;
|
|
39
|
+
try {
|
|
40
|
+
i = N(r);
|
|
41
|
+
} catch (n) {
|
|
42
|
+
throw new Error(`expression '${r}': ${n.message}`);
|
|
43
|
+
}
|
|
44
|
+
let o = 0;
|
|
45
|
+
const l = () => i[o], f = (n) => l()?.k === "op" && l().v === n, c = (n) => {
|
|
46
|
+
const e = l();
|
|
47
|
+
return e?.k === "op" && n.includes(e.v);
|
|
48
|
+
}, p = (n) => {
|
|
49
|
+
throw new Error(`expression '${r}': ${n}`);
|
|
50
|
+
}, y = (n) => f(n) ? o++ : p(`expected '${n}'`), h = (n, e, u) => () => {
|
|
51
|
+
let t = n();
|
|
52
|
+
for (; c(e); ) {
|
|
53
|
+
const a = i[o++].v;
|
|
54
|
+
t = u(a, t, n());
|
|
55
|
+
}
|
|
56
|
+
return t;
|
|
57
|
+
}, x = () => {
|
|
58
|
+
const n = i[o++];
|
|
59
|
+
if (!n) return p("ended early");
|
|
60
|
+
if (n.k === "num" || n.k === "str") {
|
|
61
|
+
const e = n.v;
|
|
62
|
+
return () => e;
|
|
63
|
+
}
|
|
64
|
+
if (n.k === "id") {
|
|
65
|
+
const e = n.v;
|
|
66
|
+
if (e === "true") return () => !0;
|
|
67
|
+
if (e === "false") return () => !1;
|
|
68
|
+
if (e === "null") return () => null;
|
|
69
|
+
if (f("(")) {
|
|
70
|
+
o++;
|
|
71
|
+
const u = [];
|
|
72
|
+
for (; !f(")") && (u.push($()), !!f(",")); )
|
|
73
|
+
o++;
|
|
74
|
+
return y(")"), (t) => t.call(e, u.map((a) => a(t)));
|
|
75
|
+
}
|
|
76
|
+
return (u) => {
|
|
77
|
+
const t = u.get(e);
|
|
78
|
+
return typeof t == "number" || typeof t == "string" || typeof t == "boolean" || t == null ? t : String(t);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (n.v === "(") {
|
|
82
|
+
const e = $();
|
|
83
|
+
return y(")"), e;
|
|
84
|
+
}
|
|
85
|
+
return p(`unexpected '${n.v}'`);
|
|
86
|
+
}, w = () => {
|
|
87
|
+
if (f("!")) {
|
|
88
|
+
o++;
|
|
89
|
+
const n = w();
|
|
90
|
+
return (e) => !m(n(e));
|
|
91
|
+
}
|
|
92
|
+
if (f("-")) {
|
|
93
|
+
o++;
|
|
94
|
+
const n = w();
|
|
95
|
+
return (e) => -s(n(e));
|
|
96
|
+
}
|
|
97
|
+
return x();
|
|
98
|
+
}, v = h(
|
|
99
|
+
w,
|
|
100
|
+
["*", "/", "%"],
|
|
101
|
+
(n, e, u) => n === "*" ? (t) => s(e(t)) * s(u(t)) : n === "/" ? (t) => s(e(t)) / s(u(t)) : (t) => s(e(t)) % s(u(t))
|
|
102
|
+
), E = h(
|
|
103
|
+
v,
|
|
104
|
+
["+", "-"],
|
|
105
|
+
(n, e, u) => n === "+" ? (t) => {
|
|
106
|
+
const a = e(t), d = u(t);
|
|
107
|
+
return typeof a == "string" || typeof d == "string" ? `${a ?? ""}${d ?? ""}` : s(a) + s(d);
|
|
108
|
+
} : (t) => s(e(t)) - s(u(t))
|
|
109
|
+
), _ = h(E, ["<", ">", "<=", ">=", "==", "!="], (n, e, u) => {
|
|
110
|
+
switch (n) {
|
|
111
|
+
case "==":
|
|
112
|
+
return (t) => k(e(t), u(t));
|
|
113
|
+
case "!=":
|
|
114
|
+
return (t) => !k(e(t), u(t));
|
|
115
|
+
case "<":
|
|
116
|
+
return (t) => s(e(t)) < s(u(t));
|
|
117
|
+
case ">":
|
|
118
|
+
return (t) => s(e(t)) > s(u(t));
|
|
119
|
+
case "<=":
|
|
120
|
+
return (t) => s(e(t)) <= s(u(t));
|
|
121
|
+
default:
|
|
122
|
+
return (t) => s(e(t)) >= s(u(t));
|
|
123
|
+
}
|
|
124
|
+
}), z = h(_, ["&&"], (n, e, u) => (t) => m(e(t)) && m(u(t))), $ = h(z, ["||"], (n, e, u) => (t) => m(e(t)) || m(u(t)));
|
|
125
|
+
i.length === 0 && p("empty");
|
|
126
|
+
const b = $();
|
|
127
|
+
return o < i.length && p(`unexpected '${i[o].v}'`), b;
|
|
128
|
+
}
|
|
129
|
+
const g = /* @__PURE__ */ new Map();
|
|
130
|
+
function O(r) {
|
|
131
|
+
let i = g.get(r);
|
|
132
|
+
return i || (i = Z(r), g.size > 2e3 && g.clear(), g.set(r, i)), i;
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
Z as compileExpr,
|
|
136
|
+
O as expr
|
|
137
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { compileExpr as A } from "./expr.js";
|
|
2
|
+
function S(r, d = {}) {
|
|
3
|
+
const $ = [], s = (e, n) => $.push({ path: e, message: n, level: "error" }), g = Object.keys(r.nodes ?? {});
|
|
4
|
+
if (g.length === 0)
|
|
5
|
+
return s("nodes", "the script has no nodes"), $;
|
|
6
|
+
const m = r.start ?? g[0];
|
|
7
|
+
r.nodes[m] || s("start", `no node '${m}'`);
|
|
8
|
+
const p = d.functions ? /* @__PURE__ */ new Set(["visited", "chose", ...d.functions]) : null, a = (e, n) => {
|
|
9
|
+
if (typeof n != "string") return s(e, "must be an expression in a string");
|
|
10
|
+
try {
|
|
11
|
+
A(n);
|
|
12
|
+
} catch (o) {
|
|
13
|
+
return s(e, o.message);
|
|
14
|
+
}
|
|
15
|
+
if (p)
|
|
16
|
+
for (const o of n.matchAll(/([A-Za-z_$][\w$]*)\s*\(/g)) p.has(o[1]) || s(e, `no function '${o[1]}'`);
|
|
17
|
+
}, h = (e, n) => {
|
|
18
|
+
if (typeof n != "string") return s(e, "must be text");
|
|
19
|
+
for (const o of n.replace(/\{\{|\}\}/g, "").matchAll(/\{([^{}]*)\}/g)) a(e, o[1].trim());
|
|
20
|
+
}, u = (e, n) => {
|
|
21
|
+
(typeof n != "string" || !r.nodes[n]) && s(e, `no node '${String(n)}'`);
|
|
22
|
+
}, y = (e, n) => {
|
|
23
|
+
for (const [o, i] of Object.entries(n ?? {})) a(`${e}.${o}`, i);
|
|
24
|
+
}, v = (e, n) => {
|
|
25
|
+
(n ?? []).forEach((o, i) => {
|
|
26
|
+
const t = typeof o == "string" ? o : o?.name;
|
|
27
|
+
typeof t != "string" ? s(`${e}[${i}]`, "a command needs a name") : d.commands && !d.commands.includes(t) && s(`${e}[${i}]`, `no command '${t}'`);
|
|
28
|
+
});
|
|
29
|
+
}, w = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const e of g) {
|
|
31
|
+
const n = r.nodes[e], o = `nodes.${e}`, i = [];
|
|
32
|
+
y(`${o}.set`, n.set), v(`${o}.do`, n.do), (n.lines ?? []).forEach((t, f) => {
|
|
33
|
+
if (typeof t == "string") return h(`${o}.lines[${f}]`, t);
|
|
34
|
+
h(`${o}.lines[${f}].text`, t.text), t.if !== void 0 && a(`${o}.lines[${f}].if`, t.if);
|
|
35
|
+
}), (n.choices ?? []).forEach((t, f) => {
|
|
36
|
+
const c = `${o}.choices[${f}]`;
|
|
37
|
+
h(`${c}.text`, t.text), t.if !== void 0 && a(`${c}.if`, t.if), y(`${c}.set`, t.set), v(`${c}.do`, t.do), t.goto !== void 0 && (u(`${c}.goto`, t.goto), i.push(t.goto));
|
|
38
|
+
}), typeof n.next == "string" ? (u(`${o}.next`, n.next), i.push(n.next)) : Array.isArray(n.next) && n.next.forEach((t, f) => {
|
|
39
|
+
t.if !== void 0 && a(`${o}.next[${f}].if`, t.if), u(`${o}.next[${f}].goto`, t.goto), i.push(t.goto);
|
|
40
|
+
}), w.set(e, i);
|
|
41
|
+
}
|
|
42
|
+
const l = /* @__PURE__ */ new Set(), x = r.nodes[m] ? [m] : [];
|
|
43
|
+
for (; x.length; ) {
|
|
44
|
+
const e = x.pop();
|
|
45
|
+
l.has(e) || !r.nodes[e] || (l.add(e), x.push(...w.get(e) ?? []));
|
|
46
|
+
}
|
|
47
|
+
for (const e of g) l.has(e) || $.push({ path: `nodes.${e}`, message: "nothing leads here from the start", level: "warning" });
|
|
48
|
+
return $;
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
S as validateDialogue
|
|
52
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
function P(r, t) {
|
|
2
|
+
return [r, t];
|
|
3
|
+
}
|
|
4
|
+
function y(r, t, e = {}) {
|
|
5
|
+
const o = e.extends ?? null, n = new Map(o?.parts ?? []);
|
|
6
|
+
for (const [s, i] of t)
|
|
7
|
+
i === null ? n.delete(s) : n.set(s, l(n.get(s), i));
|
|
8
|
+
return { name: r, parts: n, base: o };
|
|
9
|
+
}
|
|
10
|
+
function w(r, t, e = {}) {
|
|
11
|
+
const o = e.with?.length ? y(t.name, e.with, { extends: t }).parts : t.parts, n = r.create(), s = { entity: n, args: e.args };
|
|
12
|
+
for (const [i, f] of o)
|
|
13
|
+
e.without?.includes(i) || r.add(n, i, g(f, s));
|
|
14
|
+
return n;
|
|
15
|
+
}
|
|
16
|
+
function x(r, t) {
|
|
17
|
+
for (let e = r; e; e = e.base) if (e === t) return !0;
|
|
18
|
+
return !1;
|
|
19
|
+
}
|
|
20
|
+
function g(r, t) {
|
|
21
|
+
return typeof r == "function" ? r(t) : r !== null && typeof r == "object" ? structuredClone(r) : r;
|
|
22
|
+
}
|
|
23
|
+
const h = (r) => r !== null && typeof r == "object" && !Array.isArray(r) && Object.getPrototypeOf(r) === Object.prototype;
|
|
24
|
+
function l(r, t) {
|
|
25
|
+
if (!h(r) || !h(t)) return t;
|
|
26
|
+
const e = { ...r };
|
|
27
|
+
for (const [o, n] of Object.entries(t)) e[o] = l(r[o], n);
|
|
28
|
+
return e;
|
|
29
|
+
}
|
|
30
|
+
class O {
|
|
31
|
+
types = /* @__PURE__ */ new Map();
|
|
32
|
+
factories = /* @__PURE__ */ new Map();
|
|
33
|
+
prefabs = /* @__PURE__ */ new Map();
|
|
34
|
+
/** Lets data name a component type. */
|
|
35
|
+
component(t, e) {
|
|
36
|
+
return this.types.set(t, e), this;
|
|
37
|
+
}
|
|
38
|
+
/** A value made in code for a prefab loaded from data (and its variants): the data cannot hold a function. */
|
|
39
|
+
factory(t, e, o) {
|
|
40
|
+
let n = this.factories.get(t);
|
|
41
|
+
return n || this.factories.set(t, n = /* @__PURE__ */ new Map()), n.set(e, o), this;
|
|
42
|
+
}
|
|
43
|
+
/** Adds a prefab made in code. */
|
|
44
|
+
add(t) {
|
|
45
|
+
return this.prefabs.set(t.name, t), this;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Builds the prefabs of `data`, bases before their variants (in any order in the data), and adds them. Throws,
|
|
49
|
+
* naming the prefab, on an unknown component or base, or a prefab that extends itself.
|
|
50
|
+
*/
|
|
51
|
+
load(t) {
|
|
52
|
+
const e = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set(), n = (s) => {
|
|
53
|
+
const i = e.get(s);
|
|
54
|
+
if (i) return i;
|
|
55
|
+
const f = t[s];
|
|
56
|
+
if (!f) return this.get(s);
|
|
57
|
+
if (o.has(s)) throw new Error(`PrefabLibrary: '${s}' extends itself`);
|
|
58
|
+
o.add(s);
|
|
59
|
+
const d = f.extends === void 0 ? void 0 : n(f.extends), u = Object.entries(f.components ?? {}).map(([c, a]) => {
|
|
60
|
+
const b = this.types.get(c);
|
|
61
|
+
if (!b) throw new Error(`PrefabLibrary: '${s}' names an unknown component '${c}'`);
|
|
62
|
+
return [b, a];
|
|
63
|
+
});
|
|
64
|
+
for (const [c, a] of this.factories.get(s) ?? []) u.push([c, a]);
|
|
65
|
+
const p = y(s, u, { extends: d });
|
|
66
|
+
return o.delete(s), e.set(s, p), p;
|
|
67
|
+
};
|
|
68
|
+
for (const s of Object.keys(t)) n(s);
|
|
69
|
+
for (const [s, i] of e) this.prefabs.set(s, i);
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
get(t) {
|
|
73
|
+
const e = this.prefabs.get(t);
|
|
74
|
+
if (!e) throw new Error(`PrefabLibrary: no prefab '${t}'`);
|
|
75
|
+
return e;
|
|
76
|
+
}
|
|
77
|
+
has(t) {
|
|
78
|
+
return this.prefabs.has(t);
|
|
79
|
+
}
|
|
80
|
+
names() {
|
|
81
|
+
return [...this.prefabs.keys()];
|
|
82
|
+
}
|
|
83
|
+
/** `spawnPrefab` by name. */
|
|
84
|
+
spawn(t, e, o = {}) {
|
|
85
|
+
return w(t, this.get(e), o);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
O as PrefabLibrary,
|
|
90
|
+
y as definePrefab,
|
|
91
|
+
x as isPrefabOf,
|
|
92
|
+
P as prefabPart,
|
|
93
|
+
w as spawnPrefab
|
|
94
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { existsSync as b } from "node:fs";
|
|
2
2
|
import { rm as d, mkdir as M, readFile as V, rename as T, readdir as x } from "node:fs/promises";
|
|
3
3
|
import { join as s } from "node:path";
|
|
4
|
-
import { isNewer as y, validManifest as $, fileUrl as
|
|
5
|
-
import { planWeb as
|
|
6
|
-
import { fetchWithTimeout as u, hashWeb as
|
|
4
|
+
import { isNewer as y, validManifest as $, fileUrl as P } from "../updates/manifest.js";
|
|
5
|
+
import { planWeb as U } from "../updates/webPlan.js";
|
|
6
|
+
import { fetchWithTimeout as u, hashWeb as D, putFile as g, sha256 as E } from "./webFiles.js";
|
|
7
7
|
import { WebPointers as W } from "./webPointers.js";
|
|
8
|
-
class
|
|
8
|
+
class z {
|
|
9
9
|
constructor(e) {
|
|
10
10
|
this.options = e, this.o = {
|
|
11
11
|
root: e.root,
|
|
@@ -30,6 +30,7 @@ class C {
|
|
|
30
30
|
loaded = null;
|
|
31
31
|
/** The tidy a start began: a build waits for it, or it could delete the `.part` folder being filled. */
|
|
32
32
|
tidying = Promise.resolve();
|
|
33
|
+
tidyChain = Promise.resolve();
|
|
33
34
|
/** This shell's identity. */
|
|
34
35
|
get shell() {
|
|
35
36
|
const e = this.options.shell;
|
|
@@ -95,7 +96,7 @@ class C {
|
|
|
95
96
|
if (b(s(l, this.o.entry)) && this.pointers.read("active")?.version !== o.version)
|
|
96
97
|
return this.pointers.write("pending", p), t(100), o.version;
|
|
97
98
|
await this.tidying;
|
|
98
|
-
const f = this.loaded?.dir ?? this.o.builtinDir, h =
|
|
99
|
+
const f = this.loaded?.dir ?? this.o.builtinDir, h = U(o, await D(f)), n = s(this.o.root, `${o.version}.part`);
|
|
99
100
|
await d(n, { recursive: !0, force: !0 }), await M(n, { recursive: !0 });
|
|
100
101
|
for (const r of h.copy) await g(n, r.path, await V(s(f, ...r.from.split("/"))));
|
|
101
102
|
let v = 0;
|
|
@@ -105,9 +106,9 @@ class C {
|
|
|
105
106
|
for (let r = m.shift(); r; r = m.shift()) {
|
|
106
107
|
let a = w.get(r.sha256);
|
|
107
108
|
if (!a) {
|
|
108
|
-
const c = await u(this.o.fetch,
|
|
109
|
+
const c = await u(this.o.fetch, P(this.o.channelUrl, r.sha256), this.o.fetchTimeoutMs);
|
|
109
110
|
if (!c.ok) throw new Error(`${r.path}: ${c.status}`);
|
|
110
|
-
if (a = new Uint8Array(await c.arrayBuffer()),
|
|
111
|
+
if (a = new Uint8Array(await c.arrayBuffer()), E(a) !== r.sha256) throw new Error(`${r.path}: checksum`);
|
|
111
112
|
w.set(r.sha256, a), v += r.size, t(Math.min(99, Math.round(v / Math.max(1, h.bytes) * 100)));
|
|
112
113
|
}
|
|
113
114
|
await g(n, r.path, a);
|
|
@@ -132,8 +133,13 @@ class C {
|
|
|
132
133
|
usable(e) {
|
|
133
134
|
return !!e && e.shell === this.shell && y(e.version, this.o.appVersion) && b(s(this.o.root, e.version, this.o.entry));
|
|
134
135
|
}
|
|
135
|
-
/** Removes every patched web but the active, pending and previous one, and any half-made folder.
|
|
136
|
-
|
|
136
|
+
/** Removes every patched web but the active, pending and previous one, and any half-made folder. A call made while
|
|
137
|
+
* one is running waits for it and then runs once more, so two never delete the same folder at once. */
|
|
138
|
+
tidy() {
|
|
139
|
+
const e = this.tidyChain.then(() => this.tidyOnce());
|
|
140
|
+
return this.tidyChain = e, e;
|
|
141
|
+
}
|
|
142
|
+
async tidyOnce() {
|
|
137
143
|
try {
|
|
138
144
|
const e = ["active", "pending", "previous"], t = new Set([...e.map((i) => this.pointers.read(i)?.version), this.loaded?.version].filter((i) => !!i));
|
|
139
145
|
for (const i of await x(this.o.root))
|
|
@@ -143,5 +149,5 @@ class C {
|
|
|
143
149
|
}
|
|
144
150
|
}
|
|
145
151
|
export {
|
|
146
|
-
|
|
152
|
+
z as WebPatcher
|
|
147
153
|
};
|
package/dist/input/Actions.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { parseChord as c, chordHeld as l } from "./keyChord.js";
|
|
2
2
|
import { rumblePad as f } from "./rumble.js";
|
|
3
3
|
const u = ["a", "b", "x", "y", "lb", "rb", "lt", "rt", "select", "start", "ls", "rs", "up", "down", "left", "right", "home"], w = ["lx", "ly", "rx", "ry"];
|
|
4
|
-
class
|
|
5
|
-
constructor(t,
|
|
6
|
-
this.keyboard = t, this.bindings = new Map(Object.entries(
|
|
4
|
+
class v {
|
|
5
|
+
constructor(t, s, e = {}) {
|
|
6
|
+
this.keyboard = t, this.bindings = new Map(Object.entries(s)), this.deadZone = e.deadZone ?? 0.25, this.gamepads = e.gamepads ?? (() => typeof navigator < "u" && typeof navigator.getGamepads == "function" ? navigator.getGamepads() : []);
|
|
7
7
|
}
|
|
8
8
|
keyboard;
|
|
9
9
|
bindings;
|
|
@@ -18,10 +18,14 @@ class g {
|
|
|
18
18
|
chords = /* @__PURE__ */ new Map();
|
|
19
19
|
/** Keys a chord holds this step: their bare bindings read 0 until the key comes up. */
|
|
20
20
|
claimed = /* @__PURE__ */ new Set();
|
|
21
|
+
/** Where `poll` takes its values from instead of the devices (a replay), until it returns null. */
|
|
22
|
+
source = null;
|
|
23
|
+
/** Handed every step's values after `poll` (a recorder). */
|
|
24
|
+
taps = /* @__PURE__ */ new Set();
|
|
21
25
|
keyDown = (t) => this.keyboard !== null && (this.keyboard.isDown(t) || this.keyboard.pressed(t));
|
|
22
26
|
/** Replaces one action's bindings (a player's rebinding). */
|
|
23
|
-
bind(t,
|
|
24
|
-
this.bindings.set(t, [...
|
|
27
|
+
bind(t, s) {
|
|
28
|
+
this.bindings.set(t, [...s]);
|
|
25
29
|
}
|
|
26
30
|
bindingsOf(t) {
|
|
27
31
|
return this.bindings.get(t) ?? [];
|
|
@@ -37,19 +41,46 @@ class g {
|
|
|
37
41
|
* Rumbles the gamepads the actions read: every connected one, or only `padIndex` among them. Resolves true when any
|
|
38
42
|
* played; a pad without rumble is skipped silently.
|
|
39
43
|
*/
|
|
40
|
-
async rumble(t,
|
|
41
|
-
const
|
|
44
|
+
async rumble(t, s) {
|
|
45
|
+
const e = this.gamepads(), i = s === void 0 ? e : [e[s] ?? null];
|
|
42
46
|
return (await Promise.all(i.map((r) => r ? f(r, t) : Promise.resolve(!1)))).includes(!0);
|
|
43
47
|
}
|
|
44
48
|
/** Reads every device once; call at the start of each simulation step. */
|
|
45
49
|
poll() {
|
|
46
|
-
[this.before, this.now] = [this.now, this.before], this.now.clear()
|
|
47
|
-
|
|
50
|
+
if ([this.before, this.now] = [this.now, this.before], this.now.clear(), this.source) {
|
|
51
|
+
const t = this.source();
|
|
52
|
+
if (t) {
|
|
53
|
+
for (const [s, e] of t) e > 0 && this.now.set(s, e);
|
|
54
|
+
for (const s of this.taps) s(this.now);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.source = null;
|
|
58
|
+
}
|
|
59
|
+
this.readDevices();
|
|
60
|
+
for (const t of this.taps) t(this.now);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Takes each step's values from `source` instead of the devices (an `InputPlayer`), until it returns null; then
|
|
64
|
+
* the devices answer again. Pass null to stop at once.
|
|
65
|
+
*/
|
|
66
|
+
replay(t) {
|
|
67
|
+
this.source = t;
|
|
68
|
+
}
|
|
69
|
+
/** Whether a replay is driving the actions now. */
|
|
70
|
+
get replaying() {
|
|
71
|
+
return this.source !== null;
|
|
72
|
+
}
|
|
73
|
+
/** Calls `tap` with every step's values right after `poll` (an `InputRecorder`); returns the stop. */
|
|
74
|
+
tap(t) {
|
|
75
|
+
return this.taps.add(t), () => this.taps.delete(t);
|
|
76
|
+
}
|
|
77
|
+
readDevices() {
|
|
78
|
+
const t = this.gamepads().filter((s) => s !== null);
|
|
48
79
|
this.claimChords();
|
|
49
|
-
for (const [
|
|
80
|
+
for (const [s, e] of this.bindings) {
|
|
50
81
|
let i = 0;
|
|
51
|
-
for (const o of
|
|
52
|
-
i > 0 && this.now.set(
|
|
82
|
+
for (const o of e) i = Math.max(i, this.read(o, t));
|
|
83
|
+
i > 0 && this.now.set(s, i);
|
|
53
84
|
}
|
|
54
85
|
}
|
|
55
86
|
/** Held this step. */
|
|
@@ -69,12 +100,12 @@ class g {
|
|
|
69
100
|
return !this.down(t) && (this.before.get(t) ?? 0) > 0;
|
|
70
101
|
}
|
|
71
102
|
/** `value(positive) - value(negative)`, in −1…1. */
|
|
72
|
-
axis(t,
|
|
73
|
-
return this.value(
|
|
103
|
+
axis(t, s) {
|
|
104
|
+
return this.value(s) - this.value(t);
|
|
74
105
|
}
|
|
75
106
|
/** A 2D direction from four actions, never longer than 1 (a diagonal is not faster). */
|
|
76
|
-
vector(t,
|
|
77
|
-
const o = this.axis(t,
|
|
107
|
+
vector(t, s, e, i) {
|
|
108
|
+
const o = this.axis(t, s), r = this.axis(e, i), n = Math.hypot(o, r);
|
|
78
109
|
return n > 1 ? [o / n, r / n] : [o, r];
|
|
79
110
|
}
|
|
80
111
|
/** Ends the step: the keyboard forgets its edges; virtual taps shorter than a step have now been seen. */
|
|
@@ -90,20 +121,20 @@ class g {
|
|
|
90
121
|
this.keyboard?.endStep(), this.virtualDown.clear(), this.poll(), this.before = new Map(this.now);
|
|
91
122
|
}
|
|
92
123
|
chordOf(t) {
|
|
93
|
-
let
|
|
94
|
-
return
|
|
124
|
+
let s = this.chords.get(t);
|
|
125
|
+
return s === void 0 && (s = t.startsWith("pad:") || t.startsWith("touch:") ? null : c(t), this.chords.set(t, s)), s;
|
|
95
126
|
}
|
|
96
127
|
/** Marks the keys held chords use, and frees those whose key has come up. */
|
|
97
128
|
claimChords() {
|
|
98
129
|
for (const t of this.claimed) this.keyDown(t) || this.claimed.delete(t);
|
|
99
130
|
if (this.keyboard)
|
|
100
131
|
for (const t of this.bindings.values())
|
|
101
|
-
for (const
|
|
102
|
-
const
|
|
103
|
-
|
|
132
|
+
for (const s of t) {
|
|
133
|
+
const e = this.chordOf(s);
|
|
134
|
+
e && l(e, this.keyDown) && this.claimed.add(e.code);
|
|
104
135
|
}
|
|
105
136
|
}
|
|
106
|
-
read(t,
|
|
137
|
+
read(t, s) {
|
|
107
138
|
if (t.startsWith("touch:")) {
|
|
108
139
|
const i = t.slice(6);
|
|
109
140
|
return this.virtual.has(i) || this.virtualDown.has(i) ? 1 : 0;
|
|
@@ -115,7 +146,7 @@ class g {
|
|
|
115
146
|
if (r !== 0) {
|
|
116
147
|
const h = w.indexOf(i.slice(0, -1));
|
|
117
148
|
if (h < 0) return 0;
|
|
118
|
-
for (const a of
|
|
149
|
+
for (const a of s) {
|
|
119
150
|
const d = (a.axes[h] ?? 0) * r;
|
|
120
151
|
d > this.deadZone && (o = Math.max(o, (d - this.deadZone) / (1 - this.deadZone)));
|
|
121
152
|
}
|
|
@@ -123,17 +154,17 @@ class g {
|
|
|
123
154
|
}
|
|
124
155
|
const n = u.indexOf(i);
|
|
125
156
|
if (n < 0) return 0;
|
|
126
|
-
for (const h of
|
|
157
|
+
for (const h of s) {
|
|
127
158
|
const a = h.buttons[n];
|
|
128
159
|
a?.pressed && (o = Math.max(o, a.value > 0 ? a.value : 1));
|
|
129
160
|
}
|
|
130
161
|
return Math.min(1, o);
|
|
131
162
|
}
|
|
132
|
-
const
|
|
133
|
-
return
|
|
163
|
+
const e = this.chordOf(t);
|
|
164
|
+
return e ? l(e, this.keyDown) ? 1 : 0 : this.claimed.has(t) ? 0 : this.keyDown(t) ? 1 : 0;
|
|
134
165
|
}
|
|
135
166
|
}
|
|
136
167
|
export {
|
|
137
|
-
|
|
168
|
+
v as Actions,
|
|
138
169
|
u as PAD_BUTTONS
|
|
139
170
|
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { PAD_BUTTONS as r } from "./Actions.js";
|
|
2
|
+
function c(s) {
|
|
3
|
+
return s.startsWith("pad:") ? "pad" : s.startsWith("touch:") ? "touch" : "keys";
|
|
4
|
+
}
|
|
5
|
+
const h = ["lx", "ly", "rx", "ry"], a = {
|
|
6
|
+
a: "A",
|
|
7
|
+
b: "B",
|
|
8
|
+
x: "X",
|
|
9
|
+
y: "Y",
|
|
10
|
+
lb: "LB",
|
|
11
|
+
rb: "RB",
|
|
12
|
+
lt: "LT",
|
|
13
|
+
rt: "RT",
|
|
14
|
+
select: "Select",
|
|
15
|
+
start: "Start",
|
|
16
|
+
ls: "Left stick press",
|
|
17
|
+
rs: "Right stick press",
|
|
18
|
+
up: "D-pad up",
|
|
19
|
+
down: "D-pad down",
|
|
20
|
+
left: "D-pad left",
|
|
21
|
+
right: "D-pad right",
|
|
22
|
+
home: "Home",
|
|
23
|
+
"lx-": "Left stick left",
|
|
24
|
+
"lx+": "Left stick right",
|
|
25
|
+
"ly-": "Left stick up",
|
|
26
|
+
"ly+": "Left stick down",
|
|
27
|
+
"rx-": "Right stick left",
|
|
28
|
+
"rx+": "Right stick right",
|
|
29
|
+
"ry-": "Right stick up",
|
|
30
|
+
"ry+": "Right stick down"
|
|
31
|
+
};
|
|
32
|
+
function p(s, t = {}) {
|
|
33
|
+
if (!s.startsWith("pad:")) return s;
|
|
34
|
+
const e = s.slice(4);
|
|
35
|
+
return t[e] ?? a[e] ?? e;
|
|
36
|
+
}
|
|
37
|
+
class l {
|
|
38
|
+
result;
|
|
39
|
+
settle;
|
|
40
|
+
done = !1;
|
|
41
|
+
held = /* @__PURE__ */ new Set();
|
|
42
|
+
options;
|
|
43
|
+
gamepads;
|
|
44
|
+
target;
|
|
45
|
+
onKey = (t) => this.key(t);
|
|
46
|
+
constructor(t = {}) {
|
|
47
|
+
this.options = {
|
|
48
|
+
devices: t.devices ?? ["keys", "pad"],
|
|
49
|
+
ignoreKeys: t.ignoreKeys ?? ["Escape"],
|
|
50
|
+
cancelKeys: t.cancelKeys ?? ["Escape"],
|
|
51
|
+
axisThreshold: t.axisThreshold ?? 0.6
|
|
52
|
+
}, this.gamepads = t.gamepads ?? (() => typeof navigator < "u" && typeof navigator.getGamepads == "function" ? navigator.getGamepads() : []), this.target = t.target ?? (typeof window < "u" ? window : null), this.result = new Promise((e) => this.settle = e);
|
|
53
|
+
for (const e of this.padInputs()) this.held.add(e);
|
|
54
|
+
this.options.devices.includes("keys") && this.target?.addEventListener("keydown", this.onKey, { capture: !0 });
|
|
55
|
+
}
|
|
56
|
+
/** Reads the gamepads once; call every frame while the capture is open. */
|
|
57
|
+
poll() {
|
|
58
|
+
if (this.done || !this.options.devices.includes("pad")) return;
|
|
59
|
+
const t = new Set(this.padInputs());
|
|
60
|
+
for (const e of t)
|
|
61
|
+
if (!this.held.has(e))
|
|
62
|
+
return this.finish(e);
|
|
63
|
+
for (const e of [...this.held]) t.has(e) || this.held.delete(e);
|
|
64
|
+
}
|
|
65
|
+
/** Stops waiting; the result is null. */
|
|
66
|
+
cancel() {
|
|
67
|
+
this.finish(null);
|
|
68
|
+
}
|
|
69
|
+
get open() {
|
|
70
|
+
return !this.done;
|
|
71
|
+
}
|
|
72
|
+
key(t) {
|
|
73
|
+
if (!(this.done || t.repeat)) {
|
|
74
|
+
if (t.preventDefault(), t.stopImmediatePropagation(), this.options.cancelKeys.includes(t.code)) return this.finish(null);
|
|
75
|
+
this.options.ignoreKeys.includes(t.code) || !t.code || this.finish(t.code);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
finish(t) {
|
|
79
|
+
this.done || (this.done = !0, this.target?.removeEventListener("keydown", this.onKey, { capture: !0 }), this.settle(t));
|
|
80
|
+
}
|
|
81
|
+
/** Every pad input down on any pad now, as bindings. */
|
|
82
|
+
padInputs() {
|
|
83
|
+
const t = [];
|
|
84
|
+
for (const e of this.gamepads())
|
|
85
|
+
e && (e.buttons.forEach((i, n) => {
|
|
86
|
+
(i.pressed || i.value > this.options.axisThreshold) && r[n] && t.push(`pad:${r[n]}`);
|
|
87
|
+
}), h.forEach((i, n) => {
|
|
88
|
+
const o = e.axes[n] ?? 0;
|
|
89
|
+
o > this.options.axisThreshold ? t.push(`pad:${i}+`) : o < -this.options.axisThreshold && t.push(`pad:${i}-`);
|
|
90
|
+
}));
|
|
91
|
+
return t;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
l as InputCapture,
|
|
96
|
+
c as deviceOf,
|
|
97
|
+
p as padLabel
|
|
98
|
+
};
|