@benev/tact 0.4.0-6 → 0.4.0-8
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/README.md +95 -26
- package/package.json +3 -2
- package/s/lib/input/controller.ts +4 -1
- package/s/lib/input/data/intent/decode.ts +2 -2
- package/s/lib/input/data/intent/encode.ts +2 -2
- package/s/lib/input/data/intent/minihash.ts +5 -0
- package/s/lib/input/decoder.ts +2 -2
- package/s/lib/input/evaluate/context.ts +5 -1
- package/s/lib/input/evaluate/evaluate.ts +27 -14
- package/s/lib/input/investigate/hash-bindings.ts +5 -3
- package/s/lib/input/investigate/investigate.ts +24 -9
- package/s/lib/input/test.ts +52 -30
- package/s/lib/input/testing/quickbind.ts +3 -3
- package/s/lib/ui/deck/auto-gamepads.ts +1 -0
- package/s/lib/ui/deck/collector.ts +3 -3
- package/s/lib/ui/deck/hub.ts +4 -3
- package/s/lib/ui/deck/setup/deck.ts +33 -20
- package/s/lib/ui/deck/setup/tact.ts +20 -11
- package/s/lib/ui/deck/setup/types.ts +1 -0
- package/s/lib/ui/deck/setup/utils/broadcast-channel.ts +17 -0
- package/s/lib/ui/deck/setup/utils/kv.ts +20 -0
- package/s/lib/ui/deck/types.ts +1 -1
- package/s/lib/ui/views/customize/view.ts +3 -3
- package/s/lib/utils/hash.ts +47 -0
- package/x/demo/main.bundle.min.js +104 -104
- package/x/demo/main.bundle.min.js.map +4 -4
- package/x/gamepad/index.html +1 -1
- package/x/index.html +2 -2
- package/x/lib/input/controller.js +1 -1
- package/x/lib/input/controller.js.map +1 -1
- package/x/lib/input/data/intent/decode.d.ts +1 -1
- package/x/lib/input/data/intent/decode.js +2 -2
- package/x/lib/input/data/intent/decode.js.map +1 -1
- package/x/lib/input/data/intent/encode.d.ts +1 -1
- package/x/lib/input/data/intent/encode.js +2 -2
- package/x/lib/input/data/intent/encode.js.map +1 -1
- package/x/lib/input/data/intent/minihash.d.ts +1 -0
- package/x/lib/input/data/intent/minihash.js +4 -0
- package/x/lib/input/data/intent/minihash.js.map +1 -0
- package/x/lib/input/decoder.d.ts +1 -1
- package/x/lib/input/decoder.js +2 -2
- package/x/lib/input/decoder.js.map +1 -1
- package/x/lib/input/evaluate/context.d.ts +3 -1
- package/x/lib/input/evaluate/context.js.map +1 -1
- package/x/lib/input/evaluate/evaluate.js +24 -11
- package/x/lib/input/evaluate/evaluate.js.map +1 -1
- package/x/lib/input/investigate/hash-bindings.d.ts +1 -1
- package/x/lib/input/investigate/hash-bindings.js +5 -3
- package/x/lib/input/investigate/hash-bindings.js.map +1 -1
- package/x/lib/input/investigate/investigate.d.ts +2 -1
- package/x/lib/input/investigate/investigate.js +14 -9
- package/x/lib/input/investigate/investigate.js.map +1 -1
- package/x/lib/input/test.d.ts +4 -2
- package/x/lib/input/test.js +49 -22
- package/x/lib/input/test.js.map +1 -1
- package/x/lib/input/testing/quickbind.d.ts +3 -2
- package/x/lib/input/testing/quickbind.js +3 -3
- package/x/lib/input/testing/quickbind.js.map +1 -1
- package/x/lib/ui/deck/auto-gamepads.js +1 -0
- package/x/lib/ui/deck/auto-gamepads.js.map +1 -1
- package/x/lib/ui/deck/collector.js +2 -2
- package/x/lib/ui/deck/collector.js.map +1 -1
- package/x/lib/ui/deck/hub.js +4 -3
- package/x/lib/ui/deck/hub.js.map +1 -1
- package/x/lib/ui/deck/setup/deck.js +23 -13
- package/x/lib/ui/deck/setup/deck.js.map +1 -1
- package/x/lib/ui/deck/setup/tact.d.ts +2 -2
- package/x/lib/ui/deck/setup/tact.js +15 -8
- package/x/lib/ui/deck/setup/tact.js.map +1 -1
- package/x/lib/ui/deck/setup/types.d.ts +1 -0
- package/x/lib/ui/deck/setup/utils/broadcast-channel.d.ts +4 -0
- package/x/lib/ui/deck/setup/utils/broadcast-channel.js +10 -0
- package/x/lib/ui/deck/setup/utils/broadcast-channel.js.map +1 -0
- package/x/lib/ui/deck/setup/utils/kv.d.ts +5 -0
- package/x/lib/ui/deck/setup/utils/kv.js +12 -0
- package/x/lib/ui/deck/setup/utils/kv.js.map +1 -0
- package/x/lib/ui/deck/types.d.ts +1 -0
- package/x/lib/ui/views/customize/view.js +3 -3
- package/x/lib/ui/views/customize/view.js.map +1 -1
- package/x/lib/utils/hash.d.ts +1 -0
- package/x/lib/utils/hash.js +47 -0
- package/x/lib/utils/hash.js.map +1 -0
|
@@ -1,31 +1,44 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {disposer, ev} from "@e280/stz"
|
|
4
3
|
import {Hub} from "../hub.js"
|
|
5
4
|
import {asDeck} from "../types.js"
|
|
5
|
+
import {setupKv} from "./utils/kv.js"
|
|
6
6
|
import {SetupParams} from "./types.js"
|
|
7
7
|
import {Controls} from "../controls/controls.js"
|
|
8
8
|
import {Bindings} from "../../../input/types.js"
|
|
9
9
|
import {firstPreset} from "../utils/first-preset.js"
|
|
10
|
+
import {setupBroadcastChannel} from "./utils/broadcast-channel.js"
|
|
10
11
|
|
|
11
12
|
export async function setupDeck<B extends Bindings>(params: SetupParams<B>) {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
13
|
+
const {dispose, schedule, disposable} = disposer()
|
|
14
|
+
|
|
15
|
+
const namespace = params.namespace
|
|
16
|
+
? `tact_${params.namespace}`
|
|
17
|
+
: "tact"
|
|
18
|
+
|
|
19
|
+
const {kv} = disposable(
|
|
20
|
+
await setupKv(namespace, params.kv)
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const {broadcastChannel} = disposable(
|
|
24
|
+
await setupBroadcastChannel(namespace, params.broadcastChannel)
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const {maxPlayers} = params
|
|
29
|
+
const {bindings} = firstPreset(params.presets).profile
|
|
30
|
+
const hub = new Hub(bindings)
|
|
31
|
+
const controls = new Controls({...params, kv})
|
|
32
|
+
|
|
33
|
+
schedule(ev(broadcastChannel, {message: () => controls.load()}))
|
|
34
|
+
schedule(controls.on(() => broadcastChannel.postMessage({})))
|
|
35
|
+
|
|
36
|
+
await controls.load()
|
|
37
|
+
return asDeck({hub, controls, maxPlayers, dispose})
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
dispose()
|
|
41
|
+
throw error
|
|
42
|
+
}
|
|
30
43
|
}
|
|
31
44
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
+
import {disposer} from "@e280/stz"
|
|
2
3
|
import {register} from "@e280/sly"
|
|
3
4
|
|
|
4
5
|
import {setupDeck} from "./deck.js"
|
|
5
6
|
import {SetupParams} from "./types.js"
|
|
6
|
-
import {Collector} from "../collector.js"
|
|
7
7
|
import {Bindings} from "../../../input/types.js"
|
|
8
8
|
import {autoGamepads} from "../auto-gamepads.js"
|
|
9
9
|
import {ellipsis} from "../../../utils/ellipsis.js"
|
|
@@ -23,9 +23,10 @@ import devicesSvg from "../../icons/akar/devices.svg.js"
|
|
|
23
23
|
import gameControllerSvg from "../../icons/akar/game-controller.svg.js"
|
|
24
24
|
|
|
25
25
|
export async function setupTact<B extends Bindings>(params: SetupParams<B>) {
|
|
26
|
-
const
|
|
26
|
+
const {dispose, schedule, disposable} = disposer()
|
|
27
|
+
|
|
28
|
+
const deck = disposable(await setupDeck(params))
|
|
27
29
|
const first = firstPreset(deck.controls.presets)
|
|
28
|
-
const collector = new Collector(first.profile.bindings)
|
|
29
30
|
const visualizer = new Visualizer()
|
|
30
31
|
|
|
31
32
|
const elements = {
|
|
@@ -36,7 +37,7 @@ export async function setupTact<B extends Bindings>(params: SetupParams<B>) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
function gamepads(defaultProfileKey?: string) {
|
|
39
|
-
|
|
40
|
+
const stop = autoGamepads(deck.hub, (controller, source) => {
|
|
40
41
|
const handle = `${source.pad.gamepad.id} ${source.pad.gamepad.index + 1}`
|
|
41
42
|
deck.controls.attach(controller, {
|
|
42
43
|
icon: gameControllerSvg,
|
|
@@ -47,18 +48,20 @@ export async function setupTact<B extends Bindings>(params: SetupParams<B>) {
|
|
|
47
48
|
})
|
|
48
49
|
return () => deck.controls.detach(controller)
|
|
49
50
|
})
|
|
51
|
+
schedule(stop)
|
|
52
|
+
return stop
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
function mouseKeyboard() {
|
|
53
56
|
const {key, profile} = first
|
|
54
57
|
|
|
55
|
-
const controller = new Controller({
|
|
58
|
+
const controller = disposable(new Controller({
|
|
56
59
|
bindings: profile.bindings,
|
|
57
|
-
source: new Sources(
|
|
58
|
-
new KeyboardSource(),
|
|
59
|
-
new PointerSource(),
|
|
60
|
-
),
|
|
61
|
-
})
|
|
60
|
+
source: disposable(new Sources(
|
|
61
|
+
disposable(new KeyboardSource()),
|
|
62
|
+
disposable(new PointerSource()),
|
|
63
|
+
)),
|
|
64
|
+
}))
|
|
62
65
|
|
|
63
66
|
deck.hub.plug(controller)
|
|
64
67
|
|
|
@@ -70,6 +73,11 @@ export async function setupTact<B extends Bindings>(params: SetupParams<B>) {
|
|
|
70
73
|
defaultProfileKey: key,
|
|
71
74
|
})
|
|
72
75
|
|
|
76
|
+
schedule(() => {
|
|
77
|
+
deck.hub.remove(controller)
|
|
78
|
+
deck.controls.detach(controller)
|
|
79
|
+
})
|
|
80
|
+
|
|
73
81
|
return controller
|
|
74
82
|
}
|
|
75
83
|
|
|
@@ -79,12 +87,13 @@ export async function setupTact<B extends Bindings>(params: SetupParams<B>) {
|
|
|
79
87
|
|
|
80
88
|
return {
|
|
81
89
|
deck,
|
|
82
|
-
collector,
|
|
83
90
|
gamepads,
|
|
84
91
|
mouseKeyboard,
|
|
85
92
|
visualizer,
|
|
86
93
|
elements,
|
|
87
94
|
registerElements,
|
|
95
|
+
encodeAll: deck.hub.encodeAll.bind(deck.hub),
|
|
96
|
+
dispose,
|
|
88
97
|
}
|
|
89
98
|
}
|
|
90
99
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
export async function setupBroadcastChannel(
|
|
3
|
+
namespace: string,
|
|
4
|
+
broadcastChannel: BroadcastChannel | undefined,
|
|
5
|
+
) {
|
|
6
|
+
|
|
7
|
+
let dispose = () => {}
|
|
8
|
+
|
|
9
|
+
if (!broadcastChannel) {
|
|
10
|
+
const bc = new BroadcastChannel(namespace)
|
|
11
|
+
broadcastChannel = bc
|
|
12
|
+
dispose = () => bc.close()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return {broadcastChannel, dispose}
|
|
16
|
+
}
|
|
17
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
import {IdbMagazine, idbOpen, Kv} from "@e280/kv"
|
|
3
|
+
|
|
4
|
+
export async function setupKv(
|
|
5
|
+
namespace: string,
|
|
6
|
+
kv: Kv | undefined,
|
|
7
|
+
) {
|
|
8
|
+
|
|
9
|
+
let dispose = () => {}
|
|
10
|
+
|
|
11
|
+
if (!kv) {
|
|
12
|
+
const idb = await idbOpen(namespace, "kv")
|
|
13
|
+
const magazine = new IdbMagazine(idb)
|
|
14
|
+
kv = new Kv(magazine)
|
|
15
|
+
dispose = () => idb.db.close()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {kv, dispose}
|
|
19
|
+
}
|
|
20
|
+
|
package/s/lib/ui/deck/types.ts
CHANGED
|
@@ -4,7 +4,6 @@ import {Bindings} from "../../input/types.js"
|
|
|
4
4
|
import {Controls} from "./controls/controls.js"
|
|
5
5
|
|
|
6
6
|
export type PlayerId = number
|
|
7
|
-
|
|
8
7
|
export type ProfileKey = string
|
|
9
8
|
|
|
10
9
|
export type Profile<B extends Bindings = any> = {
|
|
@@ -19,6 +18,7 @@ export type Deck<B extends Bindings = any> = {
|
|
|
19
18
|
hub: Hub<B>
|
|
20
19
|
maxPlayers: number
|
|
21
20
|
controls: Controls<B>
|
|
21
|
+
dispose: () => void
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export const asDeck = <B extends Bindings>(deck: Deck<B>) => deck
|
|
@@ -27,17 +27,17 @@ export const [CustomizeView, makeCustomizeElement] = shadowDuplex((options: {con
|
|
|
27
27
|
? profiles.get(profile.basedOn)
|
|
28
28
|
: profile
|
|
29
29
|
|
|
30
|
-
const updateBindings = (bindings: Bindings) => {
|
|
30
|
+
const updateBindings = async(bindings: Bindings) => {
|
|
31
31
|
let key = $profileKey()
|
|
32
32
|
|
|
33
33
|
if (profiles.isPreset(key)) {
|
|
34
34
|
const basedOn = key
|
|
35
35
|
const freshKey = makeId()
|
|
36
36
|
key = freshKey
|
|
37
|
-
profiles.clone(freshKey, basedOn)
|
|
37
|
+
await profiles.clone(freshKey, basedOn)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
profiles.update(key, {bindings})
|
|
40
|
+
await profiles.update(key, {bindings})
|
|
41
41
|
$profileKey(key)
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
import {blake3} from "@awasm/noble/js.js"
|
|
3
|
+
import {dataViewFrom, txt} from "@e280/stz"
|
|
4
|
+
|
|
5
|
+
const endian = false
|
|
6
|
+
enum EntropyType {String, Number, Bytes}
|
|
7
|
+
|
|
8
|
+
export function hash(...entropy: (string | number | Uint8Array)[]) {
|
|
9
|
+
if (entropy.length === 0)
|
|
10
|
+
throw new RangeError("hash requires entropy")
|
|
11
|
+
|
|
12
|
+
const hasher = blake3.create()
|
|
13
|
+
const typeTag = new Uint8Array(1)
|
|
14
|
+
const lengthTag = new Uint8Array(4)
|
|
15
|
+
const lengthDataview = dataViewFrom(lengthTag)
|
|
16
|
+
|
|
17
|
+
for (const part of entropy) {
|
|
18
|
+
if (typeof part === "string") {
|
|
19
|
+
const bytes = txt.toBytes(part)
|
|
20
|
+
typeTag[0] = EntropyType.String
|
|
21
|
+
lengthDataview.setUint32(0, bytes.byteLength, endian)
|
|
22
|
+
hasher.update(typeTag)
|
|
23
|
+
hasher.update(lengthTag)
|
|
24
|
+
hasher.update(bytes)
|
|
25
|
+
}
|
|
26
|
+
else if (typeof part === "number") {
|
|
27
|
+
const bytes = new Uint8Array(8)
|
|
28
|
+
dataViewFrom(bytes).setFloat64(0, part, endian)
|
|
29
|
+
typeTag[0] = EntropyType.Number
|
|
30
|
+
lengthDataview.setUint32(0, bytes.byteLength, endian)
|
|
31
|
+
hasher.update(typeTag)
|
|
32
|
+
hasher.update(lengthTag)
|
|
33
|
+
hasher.update(bytes)
|
|
34
|
+
}
|
|
35
|
+
else if (part instanceof Uint8Array) {
|
|
36
|
+
typeTag[0] = EntropyType.Bytes
|
|
37
|
+
lengthDataview.setUint32(0, part.byteLength, endian)
|
|
38
|
+
hasher.update(typeTag)
|
|
39
|
+
hasher.update(lengthTag)
|
|
40
|
+
hasher.update(part)
|
|
41
|
+
}
|
|
42
|
+
else throw new Error("unknown part type")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return hasher.digest() as Uint8Array
|
|
46
|
+
}
|
|
47
|
+
|