@simpludify/core 0.1.5 → 0.1.6
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 +3 -3
- package/dist/foundation/version.d.ts +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +549 -31
- package/dist/index.js.map +1 -1
- package/dist/interaction/action-bindings.d.ts +18 -2
- package/dist/interaction/actions.d.ts +42 -8
- package/dist/interaction/gamepad-bindings.d.ts +100 -0
- package/dist/interaction/input-capture.d.ts +38 -0
- package/dist/interaction/input.d.ts +20 -0
- package/dist/interaction/physical-input.d.ts +32 -0
- package/dist/interaction/pointer-routing.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1583,7 +1583,7 @@ var RandomManager = class {
|
|
|
1583
1583
|
};
|
|
1584
1584
|
// packages/core/src/foundation/version.ts
|
|
1585
1585
|
/** Source workspace version; checked against package.json by the build validator. */
|
|
1586
|
-
var ENGINE_VERSION = "0.1.
|
|
1586
|
+
var ENGINE_VERSION = "0.1.6";
|
|
1587
1587
|
// packages/core/src/scene/actor.ts
|
|
1588
1588
|
var inputPhase$1 = ComponentPhase.Input;
|
|
1589
1589
|
var updatePhase$1 = ComponentPhase.Update;
|
|
@@ -2814,7 +2814,7 @@ function boxCircle(box, circle, out, tolerance) {
|
|
|
2814
2814
|
out.normalY = nx * box.sin + ny * box.cos;
|
|
2815
2815
|
return true;
|
|
2816
2816
|
}
|
|
2817
|
-
function axis(a, b, x, y, out, tolerance) {
|
|
2817
|
+
function axis$1(a, b, x, y, out, tolerance) {
|
|
2818
2818
|
const distance = (b.x - a.x) * x + (b.y - a.y) * y;
|
|
2819
2819
|
const depth = a.hx * Math.abs(a.cos * x + a.sin * y) + a.hy * Math.abs(-a.sin * x + a.cos * y) + (b.hx * Math.abs(b.cos * x + b.sin * y) + b.hy * Math.abs(-b.sin * x + b.cos * y)) - Math.abs(distance);
|
|
2820
2820
|
if (depth < -tolerance) return false;
|
|
@@ -2845,7 +2845,7 @@ function contactManifold(a, b, out, tolerance = 0) {
|
|
|
2845
2845
|
}
|
|
2846
2846
|
if (b.collider.shape === CollisionShape.Circle) return boxCircle(ag, bg, out, tolerance);
|
|
2847
2847
|
out.depth = Infinity;
|
|
2848
|
-
return axis(ag, bg, ag.cos, ag.sin, out, tolerance) && axis(ag, bg, -ag.sin, ag.cos, out, tolerance) && axis(ag, bg, bg.cos, bg.sin, out, tolerance) && axis(ag, bg, -bg.sin, bg.cos, out, tolerance);
|
|
2848
|
+
return axis$1(ag, bg, ag.cos, ag.sin, out, tolerance) && axis$1(ag, bg, -ag.sin, ag.cos, out, tolerance) && axis$1(ag, bg, bg.cos, bg.sin, out, tolerance) && axis$1(ag, bg, -bg.sin, bg.cos, out, tolerance);
|
|
2849
2849
|
}
|
|
2850
2850
|
// packages/core/src/game/collision-response.ts
|
|
2851
2851
|
/** Translate along the minimum separation axis, preserving tangential movement intent. */
|
|
@@ -4080,6 +4080,135 @@ var TileGeometry = class TileGeometry {
|
|
|
4080
4080
|
for (let dy = -radius; dy <= radius; dy++) for (let dx = Math.max(-radius, -dy - radius); dx <= Math.min(radius, -dy + radius); dx++) yield tile(x + dx, y + dy);
|
|
4081
4081
|
}
|
|
4082
4082
|
};
|
|
4083
|
+
// packages/core/src/interaction/gamepad-bindings.ts
|
|
4084
|
+
/** Standard mapping physical positions, not product-specific printed labels. */
|
|
4085
|
+
var GamepadButton = Object.freeze({
|
|
4086
|
+
South: 0,
|
|
4087
|
+
East: 1,
|
|
4088
|
+
West: 2,
|
|
4089
|
+
North: 3,
|
|
4090
|
+
LeftShoulder: 4,
|
|
4091
|
+
RightShoulder: 5,
|
|
4092
|
+
LeftTrigger: 6,
|
|
4093
|
+
RightTrigger: 7,
|
|
4094
|
+
Select: 8,
|
|
4095
|
+
Start: 9,
|
|
4096
|
+
LeftStick: 10,
|
|
4097
|
+
RightStick: 11,
|
|
4098
|
+
DPadUp: 12,
|
|
4099
|
+
DPadDown: 13,
|
|
4100
|
+
DPadLeft: 14,
|
|
4101
|
+
DPadRight: 15,
|
|
4102
|
+
Home: 16
|
|
4103
|
+
});
|
|
4104
|
+
var GamepadAxis = Object.freeze({
|
|
4105
|
+
LeftX: 0,
|
|
4106
|
+
LeftY: 1,
|
|
4107
|
+
RightX: 2,
|
|
4108
|
+
RightY: 3
|
|
4109
|
+
});
|
|
4110
|
+
var axis = (index) => Object.freeze({ axis: index });
|
|
4111
|
+
/** Ready-to-use data; game Actions retain application-defined names. */
|
|
4112
|
+
var GamepadBindings = Object.freeze({
|
|
4113
|
+
LeftStick: Object.freeze({
|
|
4114
|
+
x: axis(0),
|
|
4115
|
+
y: axis(1)
|
|
4116
|
+
}),
|
|
4117
|
+
RightStick: Object.freeze({
|
|
4118
|
+
x: axis(2),
|
|
4119
|
+
y: axis(3)
|
|
4120
|
+
}),
|
|
4121
|
+
DPad: Object.freeze({
|
|
4122
|
+
x: Object.freeze({
|
|
4123
|
+
negative: Object.freeze([14]),
|
|
4124
|
+
positive: Object.freeze([15])
|
|
4125
|
+
}),
|
|
4126
|
+
y: Object.freeze({
|
|
4127
|
+
negative: Object.freeze([12]),
|
|
4128
|
+
positive: Object.freeze([13])
|
|
4129
|
+
})
|
|
4130
|
+
}),
|
|
4131
|
+
Move: Object.freeze({
|
|
4132
|
+
x: Object.freeze({
|
|
4133
|
+
axis: 0,
|
|
4134
|
+
negative: Object.freeze([14]),
|
|
4135
|
+
positive: Object.freeze([15])
|
|
4136
|
+
}),
|
|
4137
|
+
y: Object.freeze({
|
|
4138
|
+
axis: 1,
|
|
4139
|
+
negative: Object.freeze([12]),
|
|
4140
|
+
positive: Object.freeze([13])
|
|
4141
|
+
})
|
|
4142
|
+
})
|
|
4143
|
+
});
|
|
4144
|
+
var fail = () => {
|
|
4145
|
+
throw new EngineError("INVALID_GAMEPAD_BINDING", "Invalid gamepad binding");
|
|
4146
|
+
};
|
|
4147
|
+
function gamepadIndex(value) {
|
|
4148
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) return fail();
|
|
4149
|
+
return value;
|
|
4150
|
+
}
|
|
4151
|
+
function gamepadDeadZone(value) {
|
|
4152
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value >= 1) return fail();
|
|
4153
|
+
return value;
|
|
4154
|
+
}
|
|
4155
|
+
function record(value, keys) {
|
|
4156
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((k) => !keys.includes(k))) return fail();
|
|
4157
|
+
return Object.fromEntries(Object.entries(value));
|
|
4158
|
+
}
|
|
4159
|
+
function axisBinding(value) {
|
|
4160
|
+
const v = record(value, [
|
|
4161
|
+
"axis",
|
|
4162
|
+
"invert",
|
|
4163
|
+
"negative",
|
|
4164
|
+
"positive",
|
|
4165
|
+
"deadZone"
|
|
4166
|
+
]);
|
|
4167
|
+
const indices = (value) => {
|
|
4168
|
+
if (value === void 0) return Object.freeze([]);
|
|
4169
|
+
if (!Array.isArray(value)) return fail();
|
|
4170
|
+
return Object.freeze([...new Set(value.map(gamepadIndex))]);
|
|
4171
|
+
};
|
|
4172
|
+
if (v.invert !== void 0 && typeof v.invert !== "boolean") return fail();
|
|
4173
|
+
return Object.freeze({
|
|
4174
|
+
...v.axis === void 0 ? {} : { axis: gamepadIndex(v.axis) },
|
|
4175
|
+
...v.invert === void 0 ? {} : { invert: v.invert },
|
|
4176
|
+
negative: indices(v.negative),
|
|
4177
|
+
positive: indices(v.positive),
|
|
4178
|
+
...v.deadZone === void 0 ? {} : { deadZone: gamepadDeadZone(v.deadZone) }
|
|
4179
|
+
});
|
|
4180
|
+
}
|
|
4181
|
+
function checkedGamepadBindings(actions, value) {
|
|
4182
|
+
const v = record(value, Object.keys(actions));
|
|
4183
|
+
return Object.freeze(Object.entries(v).map(([name, binding]) => {
|
|
4184
|
+
if (!Object.hasOwn(actions, name)) return fail();
|
|
4185
|
+
const action = actions[name];
|
|
4186
|
+
if (!action) return fail();
|
|
4187
|
+
let result;
|
|
4188
|
+
if (action.kind === "button") {
|
|
4189
|
+
const b = record(binding, ["buttons"]);
|
|
4190
|
+
if (b.buttons !== void 0 && !Array.isArray(b.buttons)) return fail();
|
|
4191
|
+
result = Object.freeze({ buttons: Object.freeze((b.buttons ?? []).map((item) => {
|
|
4192
|
+
if (typeof item === "number") return gamepadIndex(item);
|
|
4193
|
+
const b = record(item, ["button", "threshold"]), threshold = b.threshold ?? .5;
|
|
4194
|
+
if (typeof threshold !== "number" || !Number.isFinite(threshold) || threshold <= 0 || threshold > 1) return fail();
|
|
4195
|
+
return Object.freeze({
|
|
4196
|
+
button: gamepadIndex(b.button),
|
|
4197
|
+
threshold
|
|
4198
|
+
});
|
|
4199
|
+
})) });
|
|
4200
|
+
} else if (action.kind === "axis1d") result = axisBinding(binding);
|
|
4201
|
+
else {
|
|
4202
|
+
const keys = action.kind === "axis2d" ? ["x", "y"] : [
|
|
4203
|
+
"x",
|
|
4204
|
+
"y",
|
|
4205
|
+
"z"
|
|
4206
|
+
], b = record(binding, keys);
|
|
4207
|
+
result = Object.freeze(Object.fromEntries(keys.map((k) => [k, axisBinding(b[k] ?? {})])));
|
|
4208
|
+
}
|
|
4209
|
+
return Object.freeze([action, result]);
|
|
4210
|
+
}));
|
|
4211
|
+
}
|
|
4083
4212
|
// packages/core/src/interaction/key-code.ts
|
|
4084
4213
|
/** Physical UI Events code values plus F13–F24; Unidentified is not bindable. */
|
|
4085
4214
|
var KeyCode = {
|
|
@@ -4275,6 +4404,27 @@ function parseKeyCode(value) {
|
|
|
4275
4404
|
if (!isKeyCode(value)) throw new EngineError("INVALID_KEY_CODE", "Unknown physical keyboard code", { value });
|
|
4276
4405
|
return value;
|
|
4277
4406
|
}
|
|
4407
|
+
// packages/core/src/interaction/physical-input.ts
|
|
4408
|
+
var InputDevice = Object.freeze({
|
|
4409
|
+
Keyboard: "keyboard",
|
|
4410
|
+
Mouse: "mouse",
|
|
4411
|
+
Gamepad: "gamepad"
|
|
4412
|
+
});
|
|
4413
|
+
/** Standard PointerEvent.button indices; these are not the buttons bit mask. */
|
|
4414
|
+
var MouseButton = Object.freeze({
|
|
4415
|
+
Left: 0,
|
|
4416
|
+
Middle: 1,
|
|
4417
|
+
Right: 2,
|
|
4418
|
+
Back: 3,
|
|
4419
|
+
Forward: 4
|
|
4420
|
+
});
|
|
4421
|
+
function isMouseButton(value) {
|
|
4422
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 4;
|
|
4423
|
+
}
|
|
4424
|
+
function parseMouseButton(value) {
|
|
4425
|
+
if (!isMouseButton(value)) throw new EngineError("INVALID_MOUSE_BUTTON", "Expected a standard mouse button index (0–4)");
|
|
4426
|
+
return value;
|
|
4427
|
+
}
|
|
4278
4428
|
// packages/core/src/interaction/action-bindings.ts
|
|
4279
4429
|
function checkedBinding(action, value) {
|
|
4280
4430
|
const record = (v, allowed) => {
|
|
@@ -4288,43 +4438,123 @@ function checkedBinding(action, value) {
|
|
|
4288
4438
|
if (!Array.isArray(v)) throw new EngineError("INVALID_BINDING", "Key list must be an array");
|
|
4289
4439
|
return Object.freeze([...new Set(v.map(parseKeyCode))]);
|
|
4290
4440
|
};
|
|
4291
|
-
const
|
|
4292
|
-
|
|
4441
|
+
const mice = (v) => {
|
|
4442
|
+
if (!Array.isArray(v)) throw new EngineError("INVALID_BINDING", "Mouse button list must be an array");
|
|
4443
|
+
return Object.freeze([...new Set(v.map(parseMouseButton))]);
|
|
4444
|
+
};
|
|
4445
|
+
const axis = (v, root = false) => {
|
|
4446
|
+
const r = record(v ?? {}, [
|
|
4447
|
+
"negative",
|
|
4448
|
+
"positive",
|
|
4449
|
+
"mouseNegative",
|
|
4450
|
+
"mousePositive",
|
|
4451
|
+
...root ? ["gamepad"] : []
|
|
4452
|
+
]);
|
|
4293
4453
|
return Object.freeze({
|
|
4294
4454
|
negative: codes(r.negative),
|
|
4295
|
-
positive: codes(r.positive)
|
|
4455
|
+
positive: codes(r.positive),
|
|
4456
|
+
...r.mouseNegative === void 0 ? {} : { mouseNegative: mice(r.mouseNegative) },
|
|
4457
|
+
...r.mousePositive === void 0 ? {} : { mousePositive: mice(r.mousePositive) }
|
|
4296
4458
|
});
|
|
4297
4459
|
};
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4460
|
+
const r = record(value, action.kind === "button" ? [
|
|
4461
|
+
"keys",
|
|
4462
|
+
"mouse",
|
|
4463
|
+
"gamepad"
|
|
4464
|
+
] : action.kind === "axis1d" ? [
|
|
4465
|
+
"negative",
|
|
4466
|
+
"positive",
|
|
4467
|
+
"mouseNegative",
|
|
4468
|
+
"mousePositive",
|
|
4469
|
+
"gamepad"
|
|
4470
|
+
] : action.kind === "axis2d" ? [
|
|
4301
4471
|
"x",
|
|
4302
4472
|
"y",
|
|
4303
|
-
"
|
|
4473
|
+
"gamepad"
|
|
4474
|
+
] : [
|
|
4475
|
+
"x",
|
|
4476
|
+
"y",
|
|
4477
|
+
"z",
|
|
4478
|
+
"gamepad"
|
|
4304
4479
|
]);
|
|
4305
|
-
|
|
4480
|
+
let gamepad;
|
|
4481
|
+
if (r.gamepad !== void 0) {
|
|
4482
|
+
const checked = checkedGamepadBindings({ [action.name]: action }, { [action.name]: r.gamepad })[0];
|
|
4483
|
+
if (!checked) throw new EngineError("INVALID_BINDING", "Missing gamepad binding");
|
|
4484
|
+
gamepad = checked[1];
|
|
4485
|
+
}
|
|
4486
|
+
const base = action.kind === "button" ? {
|
|
4487
|
+
keys: codes(r.keys),
|
|
4488
|
+
...r.mouse === void 0 ? {} : { mouse: mice(r.mouse) }
|
|
4489
|
+
} : action.kind === "axis1d" ? axis(value, true) : action.kind === "axis2d" ? {
|
|
4306
4490
|
x: axis(r.x),
|
|
4307
4491
|
y: axis(r.y)
|
|
4308
4492
|
} : {
|
|
4309
4493
|
x: axis(r.x),
|
|
4310
4494
|
y: axis(r.y),
|
|
4311
4495
|
z: axis(r.z)
|
|
4496
|
+
};
|
|
4497
|
+
return Object.freeze({
|
|
4498
|
+
...base,
|
|
4499
|
+
...gamepad === void 0 ? {} : { gamepad }
|
|
4312
4500
|
});
|
|
4313
4501
|
}
|
|
4314
4502
|
function keyLists(binding, path = "") {
|
|
4315
4503
|
const lists = [];
|
|
4316
|
-
for (const [key, value] of Object.entries(binding)) if (
|
|
4504
|
+
for (const [key, value] of Object.entries(binding)) if (key === "keys" || key === "negative" || key === "positive") lists.push({
|
|
4317
4505
|
path: path + key,
|
|
4318
4506
|
keys: value
|
|
4319
4507
|
});
|
|
4320
|
-
else lists.push(...keyLists(value, `${path}${key}.`));
|
|
4508
|
+
else if (key === "x" || key === "y" || key === "z") lists.push(...keyLists(value, `${path}${key}.`));
|
|
4509
|
+
return lists;
|
|
4510
|
+
}
|
|
4511
|
+
function mouseLists(binding, path = "") {
|
|
4512
|
+
const lists = [];
|
|
4513
|
+
for (const [key, value] of Object.entries(binding)) if (key === "mouse" || key === "mouseNegative" || key === "mousePositive") lists.push({
|
|
4514
|
+
path: path + key,
|
|
4515
|
+
buttons: value
|
|
4516
|
+
});
|
|
4517
|
+
else if (key === "x" || key === "y" || key === "z") lists.push(...mouseLists(value, `${path}${key}.`));
|
|
4321
4518
|
return lists;
|
|
4322
4519
|
}
|
|
4520
|
+
function gamepadControls(binding, path = "gamepad") {
|
|
4521
|
+
const result = [];
|
|
4522
|
+
for (const [name, value] of Object.entries(binding)) if (name === "axis" && typeof value === "number") result.push({
|
|
4523
|
+
kind: "axis",
|
|
4524
|
+
index: value,
|
|
4525
|
+
path: `${path}.axis`
|
|
4526
|
+
});
|
|
4527
|
+
else if (name === "buttons" || name === "negative" || name === "positive") for (const item of value) result.push({
|
|
4528
|
+
kind: "button",
|
|
4529
|
+
index: typeof item === "number" ? item : item.button,
|
|
4530
|
+
path: `${path}.${name}`
|
|
4531
|
+
});
|
|
4532
|
+
else if (name === "x" || name === "y" || name === "z") result.push(...gamepadControls(value, `${path}.${name}`));
|
|
4533
|
+
return result;
|
|
4534
|
+
}
|
|
4535
|
+
function editGamepad(current, patch, remove) {
|
|
4536
|
+
if (Array.isArray(patch)) {
|
|
4537
|
+
const old = Array.isArray(current) ? current : [];
|
|
4538
|
+
const control = (v) => v && typeof v === "object" && "button" in v ? v.button : v;
|
|
4539
|
+
return remove ? old.filter((v) => !patch.some((p) => control(p) === control(v))) : [...new Map([...old, ...patch].map((v) => [JSON.stringify(v), v])).values()];
|
|
4540
|
+
}
|
|
4541
|
+
if (patch && typeof patch === "object") {
|
|
4542
|
+
const result = current && typeof current === "object" ? { ...current } : {};
|
|
4543
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
4544
|
+
const edited = editGamepad(result[key], value, remove);
|
|
4545
|
+
if (edited === void 0) delete result[key];
|
|
4546
|
+
else result[key] = edited;
|
|
4547
|
+
}
|
|
4548
|
+
return result;
|
|
4549
|
+
}
|
|
4550
|
+
return remove ? current === patch ? void 0 : current : patch;
|
|
4551
|
+
}
|
|
4323
4552
|
function editBinding(current, patch, remove) {
|
|
4324
4553
|
const result = { ...current };
|
|
4325
4554
|
for (const [name, value] of Object.entries(patch)) {
|
|
4326
4555
|
const old = current[name];
|
|
4327
|
-
if (
|
|
4556
|
+
if (name === "gamepad") result[name] = editGamepad(old, value, remove);
|
|
4557
|
+
else if (Array.isArray(value)) result[name] = remove ? (old ?? []).filter((k) => !value.includes(k)) : [.../* @__PURE__ */ new Set([...old ?? [], ...value])];
|
|
4328
4558
|
else result[name] = editBinding(old, value, remove);
|
|
4329
4559
|
}
|
|
4330
4560
|
return result;
|
|
@@ -4522,6 +4752,9 @@ var ActionController = class {
|
|
|
4522
4752
|
bus = new EventBus();
|
|
4523
4753
|
keyboardAllowed = true;
|
|
4524
4754
|
blockedKeys = /* @__PURE__ */ new Set();
|
|
4755
|
+
mouseAllowed = true;
|
|
4756
|
+
blockedMouse = /* @__PURE__ */ new Set();
|
|
4757
|
+
bindingGeneration = 0;
|
|
4525
4758
|
pending = [];
|
|
4526
4759
|
transitions = [];
|
|
4527
4760
|
constructor(actions, options) {
|
|
@@ -4529,6 +4762,8 @@ var ActionController = class {
|
|
|
4529
4762
|
this.options = options;
|
|
4530
4763
|
if (options.keyboard !== void 0 && typeof options.keyboard !== "boolean") throw new EngineError("INVALID_VALUE", "Keyboard enabled must be boolean");
|
|
4531
4764
|
this.keyboardAllowed = options.keyboard ?? true;
|
|
4765
|
+
if (options.mouse !== void 0 && typeof options.mouse !== "boolean") throw new EngineError("INVALID_VALUE", "Mouse enabled must be boolean");
|
|
4766
|
+
this.mouseAllowed = options.mouse ?? true;
|
|
4532
4767
|
for (const action of Object.values(actions)) {
|
|
4533
4768
|
const binding = checkedBinding(action, options.bindings && Object.hasOwn(options.bindings, action.name) ? options.bindings[action.name] ?? {} : {});
|
|
4534
4769
|
const value = neutral(action);
|
|
@@ -4575,6 +4810,24 @@ var ActionController = class {
|
|
|
4575
4810
|
get sourceCount() {
|
|
4576
4811
|
return this.sources.size;
|
|
4577
4812
|
}
|
|
4813
|
+
get mouseEnabled() {
|
|
4814
|
+
return this.mouseAllowed;
|
|
4815
|
+
}
|
|
4816
|
+
set mouseEnabled(value) {
|
|
4817
|
+
if (this.disposed) throw new EngineError("OWNER_DISPOSED", "Action controller has been disposed");
|
|
4818
|
+
if (typeof value !== "boolean") throw new EngineError("INVALID_VALUE", "Mouse enabled must be boolean");
|
|
4819
|
+
if (value === this.mouseAllowed) return;
|
|
4820
|
+
this.mouseAllowed = value;
|
|
4821
|
+
this.blockedMouse.clear();
|
|
4822
|
+
if (value) {
|
|
4823
|
+
for (const entry of this.entries.values()) for (const list of mouseLists(entry.binding)) for (const button of list.buttons) if (this.options.input.mouseDown(button)) this.blockedMouse.add(button);
|
|
4824
|
+
}
|
|
4825
|
+
for (const action of this.entries.keys()) this.recompute(action);
|
|
4826
|
+
}
|
|
4827
|
+
/** @internal Used by existing host adapters to follow common binding settings. */
|
|
4828
|
+
get bindingRevision() {
|
|
4829
|
+
return this.bindingGeneration;
|
|
4830
|
+
}
|
|
4578
4831
|
onDispose(callback) {
|
|
4579
4832
|
return this.lifetime.onDispose(callback);
|
|
4580
4833
|
}
|
|
@@ -4653,13 +4906,13 @@ var ActionController = class {
|
|
|
4653
4906
|
}
|
|
4654
4907
|
return source;
|
|
4655
4908
|
}
|
|
4656
|
-
/** @internal */ write(source, action, value) {
|
|
4909
|
+
/** @internal */ write(source, action, value, edges = true) {
|
|
4657
4910
|
this.options.input.assertWrite(isNeutral(value));
|
|
4658
4911
|
this.entry(action);
|
|
4659
4912
|
const values = this.sources.get(source);
|
|
4660
4913
|
if (!values) throw new EngineError("OWNER_DISPOSED", "Action source has been disposed");
|
|
4661
4914
|
values.set(action, value);
|
|
4662
|
-
this.recompute(action);
|
|
4915
|
+
this.recompute(action, edges);
|
|
4663
4916
|
}
|
|
4664
4917
|
/** @internal */ clearSource(source, remove) {
|
|
4665
4918
|
const values = this.sources.get(source);
|
|
@@ -4670,11 +4923,11 @@ var ActionController = class {
|
|
|
4670
4923
|
if (!this.disposed) for (const action of actions) this.recompute(action);
|
|
4671
4924
|
}
|
|
4672
4925
|
keyboard(action) {
|
|
4673
|
-
if (!this.keyboardAllowed) return neutral(action);
|
|
4674
4926
|
const binding = this.entry(action).binding;
|
|
4675
|
-
const held = (keys) => keys?.some((k) => !this.blockedKeys.has(k) && this.options.input.keyDown(k)) ?? false;
|
|
4676
|
-
const
|
|
4677
|
-
|
|
4927
|
+
const held = (keys) => this.keyboardAllowed && (keys?.some((k) => !this.blockedKeys.has(k) && this.options.input.keyDown(k)) ?? false);
|
|
4928
|
+
const mouse = (buttons) => this.mouseAllowed && (buttons?.some((b) => !this.blockedMouse.has(b) && this.options.input.mouseDown(b)) ?? false);
|
|
4929
|
+
const axis = (b) => Number(held(b?.positive) || mouse(b?.mousePositive)) - Number(held(b?.negative) || mouse(b?.mouseNegative));
|
|
4930
|
+
if (action.kind === "button") return held(binding.keys) || mouse(binding.mouse);
|
|
4678
4931
|
if (action.kind === "axis1d") return axis(binding);
|
|
4679
4932
|
const b = binding;
|
|
4680
4933
|
return action.kind === "axis2d" ? {
|
|
@@ -4727,11 +4980,15 @@ var ActionController = class {
|
|
|
4727
4980
|
}
|
|
4728
4981
|
/** @internal */ keyChanged() {
|
|
4729
4982
|
for (const key of this.blockedKeys) if (!this.options.input.keyDown(key)) this.blockedKeys.delete(key);
|
|
4983
|
+
for (const button of this.blockedMouse) if (!this.options.input.mouseDown(button)) this.blockedMouse.delete(button);
|
|
4730
4984
|
if (this.active || !this.disposed && this.options.scene.inputOwner === this.options.input && (this.options.scene.state === SceneState.Preparing || this.options.scene.state === SceneState.Ready)) for (const action of this.entries.keys()) this.recompute(action);
|
|
4731
4985
|
}
|
|
4732
4986
|
/** @internal */ accepts(code) {
|
|
4733
4987
|
return this.active && this.keyboardAllowed && [...this.entries.values()].some((e) => keyLists(e.binding).some((list) => list.keys.includes(code)));
|
|
4734
4988
|
}
|
|
4989
|
+
/** @internal */ acceptsMouse(button) {
|
|
4990
|
+
return this.active && this.mouseAllowed && [...this.entries.values()].some((e) => mouseLists(e.binding).some((list) => list.buttons.includes(button)));
|
|
4991
|
+
}
|
|
4735
4992
|
/** @internal */ capture(override) {
|
|
4736
4993
|
if (!this.active) return;
|
|
4737
4994
|
const tokens = override ? new Map([...this.entries.keys()].map((a) => [a.name, a])) : void 0;
|
|
@@ -4773,16 +5030,25 @@ var ActionController = class {
|
|
|
4773
5030
|
/** Clears held contributions and unconsumed edges; no synthetic button release. */
|
|
4774
5031
|
reset() {
|
|
4775
5032
|
this.blockedKeys.clear();
|
|
5033
|
+
this.blockedMouse.clear();
|
|
4776
5034
|
for (const values of this.sources.values()) values.clear();
|
|
4777
5035
|
this.pending = [];
|
|
4778
5036
|
for (const [action, entry] of this.entries) entry.value = neutral(action);
|
|
4779
5037
|
}
|
|
5038
|
+
/** @internal Flush device transitions without destroying explicit program values. */
|
|
5039
|
+
resetPhysical() {
|
|
5040
|
+
this.blockedKeys.clear();
|
|
5041
|
+
this.blockedMouse.clear();
|
|
5042
|
+
this.pending = [];
|
|
5043
|
+
for (const action of this.entries.keys()) this.recompute(action, false);
|
|
5044
|
+
}
|
|
4780
5045
|
getBinding(action) {
|
|
4781
5046
|
return this.entry(action).binding;
|
|
4782
5047
|
}
|
|
4783
5048
|
rebind(action, binding) {
|
|
4784
5049
|
const checked = checkedBinding(action, binding), entry = this.entry(action);
|
|
4785
5050
|
entry.binding = checked;
|
|
5051
|
+
this.bindingGeneration++;
|
|
4786
5052
|
this.pending = this.pending.filter((event) => event.action !== action);
|
|
4787
5053
|
this.recompute(action, false);
|
|
4788
5054
|
}
|
|
@@ -4795,7 +5061,13 @@ var ActionController = class {
|
|
|
4795
5061
|
resetBindings(action) {
|
|
4796
5062
|
for (const token of action ? [action] : this.entries.keys()) this.rebind(token, this.entry(token).defaults);
|
|
4797
5063
|
}
|
|
4798
|
-
conflicts() {
|
|
5064
|
+
conflicts(device = "keyboard") {
|
|
5065
|
+
if (![
|
|
5066
|
+
"keyboard",
|
|
5067
|
+
"mouse",
|
|
5068
|
+
"gamepad",
|
|
5069
|
+
"all"
|
|
5070
|
+
].includes(device)) throw new EngineError("INVALID_BINDING", "Unknown conflict device");
|
|
4799
5071
|
const keys = /* @__PURE__ */ new Map();
|
|
4800
5072
|
for (const [action, entry] of this.entries) for (const list of keyLists(entry.binding)) for (const key of list.keys) {
|
|
4801
5073
|
const group = keys.get(key) ?? [];
|
|
@@ -4805,10 +5077,54 @@ var ActionController = class {
|
|
|
4805
5077
|
});
|
|
4806
5078
|
keys.set(key, group);
|
|
4807
5079
|
}
|
|
4808
|
-
|
|
5080
|
+
const keyboard = [...keys].filter(([, bindings]) => bindings.length > 1).map(([key, bindings]) => ({
|
|
4809
5081
|
key,
|
|
4810
5082
|
bindings
|
|
4811
5083
|
}));
|
|
5084
|
+
if (device === "keyboard") return keyboard;
|
|
5085
|
+
const mice = /* @__PURE__ */ new Map();
|
|
5086
|
+
const pads = /* @__PURE__ */ new Map();
|
|
5087
|
+
for (const [action, entry] of this.entries) {
|
|
5088
|
+
for (const list of mouseLists(entry.binding)) for (const button of list.buttons) {
|
|
5089
|
+
const uses = mice.get(button) ?? [];
|
|
5090
|
+
uses.push({
|
|
5091
|
+
action,
|
|
5092
|
+
path: list.path
|
|
5093
|
+
});
|
|
5094
|
+
mice.set(button, uses);
|
|
5095
|
+
}
|
|
5096
|
+
const pad = entry.binding.gamepad;
|
|
5097
|
+
if (pad) for (const input of gamepadControls(pad)) {
|
|
5098
|
+
const key = `${input.kind}:${input.index}`;
|
|
5099
|
+
const group = pads.get(key) ?? {
|
|
5100
|
+
kind: input.kind,
|
|
5101
|
+
index: input.index,
|
|
5102
|
+
bindings: []
|
|
5103
|
+
};
|
|
5104
|
+
group.bindings.push({
|
|
5105
|
+
action,
|
|
5106
|
+
path: input.path
|
|
5107
|
+
});
|
|
5108
|
+
pads.set(key, group);
|
|
5109
|
+
}
|
|
5110
|
+
}
|
|
5111
|
+
const mouse = [...mice].filter(([, uses]) => uses.length > 1).map(([button, bindings]) => ({
|
|
5112
|
+
device: "mouse",
|
|
5113
|
+
button,
|
|
5114
|
+
bindings
|
|
5115
|
+
}));
|
|
5116
|
+
const gamepad = [...pads.values()].filter((group) => group.bindings.length > 1).map((group) => ({
|
|
5117
|
+
device: "gamepad",
|
|
5118
|
+
...group
|
|
5119
|
+
}));
|
|
5120
|
+
return device === "mouse" ? mouse : device === "gamepad" ? gamepad : [
|
|
5121
|
+
...keyboard.map((group) => ({
|
|
5122
|
+
device: "keyboard",
|
|
5123
|
+
...group
|
|
5124
|
+
})),
|
|
5125
|
+
...mouse,
|
|
5126
|
+
...gamepad
|
|
5127
|
+
];
|
|
4812
5128
|
}
|
|
4813
5129
|
exportBindings() {
|
|
4814
5130
|
return {
|
|
@@ -4847,6 +5163,10 @@ var ActionSource = class extends OwnedInputSource {
|
|
|
4847
5163
|
const checked = checkedActionValue(action, value);
|
|
4848
5164
|
if (this.writable(isNeutral(checked))) this.controller.write(this, action, checked);
|
|
4849
5165
|
}
|
|
5166
|
+
/** @internal Reset one device binding without synthesizing logical edges. */
|
|
5167
|
+
resetBinding(action) {
|
|
5168
|
+
if (this.writable(true)) this.controller.write(this, action, neutral(action), false);
|
|
5169
|
+
}
|
|
4850
5170
|
release(remove) {
|
|
4851
5171
|
this.controller.clearSource(this, remove);
|
|
4852
5172
|
}
|
|
@@ -4869,20 +5189,38 @@ var KeyboardSource = class extends OwnedInputSource {
|
|
|
4869
5189
|
this.input.releaseKeyboard(this, remove);
|
|
4870
5190
|
}
|
|
4871
5191
|
};
|
|
5192
|
+
/** Physical mouse contribution; game state is read through ActionController. */
|
|
5193
|
+
var MouseSource = class extends OwnedInputSource {
|
|
5194
|
+
input;
|
|
5195
|
+
/** @internal */ constructor(input) {
|
|
5196
|
+
super();
|
|
5197
|
+
this.input = input;
|
|
5198
|
+
}
|
|
5199
|
+
set(button, pressed) {
|
|
5200
|
+
parseMouseButton(button);
|
|
5201
|
+
if (typeof pressed !== "boolean") throw new EngineError("INVALID_VALUE", "Mouse state must be boolean");
|
|
5202
|
+
if (this.writable(!pressed)) this.input.writeMouse(this, button, pressed);
|
|
5203
|
+
}
|
|
5204
|
+
release(remove) {
|
|
5205
|
+
this.input.releaseMouse(this, remove);
|
|
5206
|
+
}
|
|
5207
|
+
};
|
|
4872
5208
|
/** Engine-owned routing and update boundary. No raw game-state/alternate movement API. */
|
|
4873
5209
|
var InputSystem = class {
|
|
4874
5210
|
actions = /* @__PURE__ */ new Set();
|
|
4875
5211
|
adapters = /* @__PURE__ */ new Set();
|
|
4876
5212
|
keyboards = /* @__PURE__ */ new Map();
|
|
5213
|
+
mice = /* @__PURE__ */ new Map();
|
|
5214
|
+
captureCancel;
|
|
4877
5215
|
dead = false;
|
|
4878
5216
|
playback = false;
|
|
4879
5217
|
frames;
|
|
4880
5218
|
/** @internal Device hosts may reject live gestures during Replay playback. */
|
|
4881
5219
|
get liveInput() {
|
|
4882
|
-
return !this.dead && !this.playback;
|
|
5220
|
+
return !this.dead && !this.playback && !this.captureCancel;
|
|
4883
5221
|
}
|
|
4884
5222
|
get sourceCount() {
|
|
4885
|
-
let count = this.keyboards.size;
|
|
5223
|
+
let count = this.keyboards.size + this.mice.size;
|
|
4886
5224
|
for (const actions of this.actions) count += actions.sourceCount;
|
|
4887
5225
|
return count;
|
|
4888
5226
|
}
|
|
@@ -4902,10 +5240,19 @@ var InputSystem = class {
|
|
|
4902
5240
|
};
|
|
4903
5241
|
}
|
|
4904
5242
|
acceptsKey(code) {
|
|
4905
|
-
if (this.
|
|
5243
|
+
if (!this.liveInput) return false;
|
|
4906
5244
|
for (const actions of this.actions) if (actions.accepts(code)) return true;
|
|
4907
5245
|
return false;
|
|
4908
5246
|
}
|
|
5247
|
+
acceptsMouse(button) {
|
|
5248
|
+
if (!this.liveInput) return false;
|
|
5249
|
+
for (const actions of this.actions) if (actions.acceptsMouse(button)) return true;
|
|
5250
|
+
return false;
|
|
5251
|
+
}
|
|
5252
|
+
/** @internal */ mouseDown(button) {
|
|
5253
|
+
for (const buttons of this.mice.values()) if (buttons.has(button)) return true;
|
|
5254
|
+
return false;
|
|
5255
|
+
}
|
|
4909
5256
|
notify() {
|
|
4910
5257
|
for (const actions of this.actions) actions.keyChanged();
|
|
4911
5258
|
}
|
|
@@ -4949,10 +5296,42 @@ var InputSystem = class {
|
|
|
4949
5296
|
}
|
|
4950
5297
|
return source;
|
|
4951
5298
|
}
|
|
5299
|
+
createMouseSource(owner) {
|
|
5300
|
+
if (this.dead || owner?.disposed) throw new EngineError("OWNER_DISPOSED", "Input owner has been disposed");
|
|
5301
|
+
const source = new MouseSource(this);
|
|
5302
|
+
this.mice.set(source, /* @__PURE__ */ new Set());
|
|
5303
|
+
try {
|
|
5304
|
+
if (owner) source.own(owner);
|
|
5305
|
+
} catch (error) {
|
|
5306
|
+
source.dispose();
|
|
5307
|
+
throw error;
|
|
5308
|
+
}
|
|
5309
|
+
return source;
|
|
5310
|
+
}
|
|
5311
|
+
/** @internal */ writeMouse(source, button, pressed) {
|
|
5312
|
+
this.assertWrite(!pressed);
|
|
5313
|
+
const buttons = this.mice.get(source);
|
|
5314
|
+
if (!buttons || this.dead) throw new EngineError("OWNER_DISPOSED", "Input has been disposed");
|
|
5315
|
+
if (this.captureCancel && pressed) return;
|
|
5316
|
+
if (buttons.has(button) === pressed) return;
|
|
5317
|
+
const before = this.mouseDown(button);
|
|
5318
|
+
if (pressed) buttons.add(button);
|
|
5319
|
+
else buttons.delete(button);
|
|
5320
|
+
if (before !== this.mouseDown(button)) this.notify();
|
|
5321
|
+
}
|
|
5322
|
+
/** @internal */ releaseMouse(source, remove) {
|
|
5323
|
+
const buttons = this.mice.get(source);
|
|
5324
|
+
if (!buttons) return;
|
|
5325
|
+
const changed = buttons.size > 0;
|
|
5326
|
+
buttons.clear();
|
|
5327
|
+
if (remove) this.mice.delete(source);
|
|
5328
|
+
if (changed && !this.dead) this.notify();
|
|
5329
|
+
}
|
|
4952
5330
|
/** @internal */ writeKey(source, code, pressed) {
|
|
4953
5331
|
this.assertWrite(!pressed);
|
|
4954
5332
|
const keys = this.keyboards.get(source);
|
|
4955
5333
|
if (!keys || this.dead) throw new EngineError("OWNER_DISPOSED", "Input has been disposed");
|
|
5334
|
+
if (this.captureCancel && pressed) return;
|
|
4956
5335
|
if (keys.has(code) === pressed) return;
|
|
4957
5336
|
const before = this.keyDown(code);
|
|
4958
5337
|
if (pressed) keys.add(code);
|
|
@@ -4991,11 +5370,41 @@ var InputSystem = class {
|
|
|
4991
5370
|
this.playback = false;
|
|
4992
5371
|
this.clear();
|
|
4993
5372
|
}
|
|
4994
|
-
|
|
5373
|
+
/** @internal Host capture gate. Program ActionSource values remain explicit. */
|
|
5374
|
+
suspendLiveInput(cancel) {
|
|
5375
|
+
if (!this.liveInput) throw new EngineError("INPUT_CAPTURE_UNAVAILABLE", "Live input is unavailable or another capture is active");
|
|
5376
|
+
this.captureCancel = cancel;
|
|
5377
|
+
try {
|
|
5378
|
+
this.resetPhysical();
|
|
5379
|
+
} catch (error) {
|
|
5380
|
+
this.captureCancel = void 0;
|
|
5381
|
+
throw error;
|
|
5382
|
+
}
|
|
5383
|
+
return () => {
|
|
5384
|
+
if (this.captureCancel !== cancel) return;
|
|
5385
|
+
this.captureCancel = void 0;
|
|
5386
|
+
this.resetPhysical();
|
|
5387
|
+
};
|
|
5388
|
+
}
|
|
5389
|
+
resetPhysical() {
|
|
4995
5390
|
for (const keys of this.keyboards.values()) keys.clear();
|
|
4996
|
-
|
|
5391
|
+
for (const buttons of this.mice.values()) buttons.clear();
|
|
5392
|
+
cleanupAll([...[...this.adapters].map((adapter) => () => {
|
|
4997
5393
|
if (this.adapters.has(adapter)) adapter.reset();
|
|
4998
|
-
})], "
|
|
5394
|
+
}), ...[...this.actions].map((actions) => () => actions.resetPhysical())], "Physical input reset failed");
|
|
5395
|
+
}
|
|
5396
|
+
clear() {
|
|
5397
|
+
const cancel = this.captureCancel;
|
|
5398
|
+
this.captureCancel = void 0;
|
|
5399
|
+
for (const keys of this.keyboards.values()) keys.clear();
|
|
5400
|
+
for (const buttons of this.mice.values()) buttons.clear();
|
|
5401
|
+
cleanupAll([
|
|
5402
|
+
() => cancel?.(),
|
|
5403
|
+
...[...this.actions].map((actions) => () => actions.reset()),
|
|
5404
|
+
...[...this.adapters].map((adapter) => () => {
|
|
5405
|
+
if (this.adapters.has(adapter)) adapter.reset();
|
|
5406
|
+
})
|
|
5407
|
+
], "Input reset failed");
|
|
4999
5408
|
}
|
|
5000
5409
|
/** Device diagnostics only; game state is ActionController.snapshot(). */
|
|
5001
5410
|
snapshot() {
|
|
@@ -5006,18 +5415,122 @@ var InputSystem = class {
|
|
|
5006
5415
|
dispose() {
|
|
5007
5416
|
if (this.dead) return;
|
|
5008
5417
|
this.dead = true;
|
|
5418
|
+
const cancel = this.captureCancel;
|
|
5419
|
+
this.captureCancel = void 0;
|
|
5009
5420
|
try {
|
|
5010
5421
|
cleanupAll([
|
|
5422
|
+
() => cancel?.(),
|
|
5011
5423
|
...[...this.adapters].map((a) => () => a.dispose()),
|
|
5012
5424
|
...[...this.actions].map((a) => () => a.dispose()),
|
|
5013
|
-
...[...this.keyboards.keys()].map((s) => () => s.dispose())
|
|
5425
|
+
...[...this.keyboards.keys()].map((s) => () => s.dispose()),
|
|
5426
|
+
...[...this.mice.keys()].map((s) => () => s.dispose())
|
|
5014
5427
|
], "Input cleanup failed");
|
|
5015
5428
|
} finally {
|
|
5016
5429
|
this.adapters.clear();
|
|
5017
5430
|
this.actions.clear();
|
|
5018
5431
|
this.keyboards.clear();
|
|
5432
|
+
this.mice.clear();
|
|
5433
|
+
}
|
|
5434
|
+
}
|
|
5435
|
+
};
|
|
5436
|
+
// packages/core/src/interaction/input-capture.ts
|
|
5437
|
+
var InputCaptureState = Object.freeze({
|
|
5438
|
+
Arming: "arming",
|
|
5439
|
+
Listening: "listening",
|
|
5440
|
+
Completed: "completed",
|
|
5441
|
+
Cancelled: "cancelled"
|
|
5442
|
+
});
|
|
5443
|
+
/** A portable single-input session. Hosts supply neutral arming and physical events. */
|
|
5444
|
+
var InputCapture = class {
|
|
5445
|
+
life = new Lifetime();
|
|
5446
|
+
status = InputCaptureState.Arming;
|
|
5447
|
+
devices;
|
|
5448
|
+
gamepadIndex;
|
|
5449
|
+
result;
|
|
5450
|
+
settle = () => {};
|
|
5451
|
+
constructor(options = {}) {
|
|
5452
|
+
if (!options || typeof options !== "object" || Array.isArray(options) || Object.keys(options).some((key) => ![
|
|
5453
|
+
"devices",
|
|
5454
|
+
"gamepadIndex",
|
|
5455
|
+
"owner"
|
|
5456
|
+
].includes(key))) throw new EngineError("INVALID_INPUT_CAPTURE", "Invalid input capture options");
|
|
5457
|
+
const devices = options.devices ?? Object.values(InputDevice);
|
|
5458
|
+
if (!Array.isArray(devices) || !devices.length || devices.some((device) => !Object.values(InputDevice).includes(device))) throw new EngineError("INVALID_INPUT_CAPTURE", "Select at least one known capture device");
|
|
5459
|
+
this.devices = Object.freeze([...new Set(devices)]);
|
|
5460
|
+
this.gamepadIndex = options.gamepadIndex === void 0 ? void 0 : gamepadIndex(options.gamepadIndex);
|
|
5461
|
+
if (options.owner?.disposed) throw new EngineError("OWNER_DISPOSED", "Capture owner has been disposed");
|
|
5462
|
+
this.result = new Promise((resolve) => {
|
|
5463
|
+
this.settle = resolve;
|
|
5464
|
+
});
|
|
5465
|
+
if (options.owner) this.life.onDispose(options.owner.onDispose(() => this.cancel()));
|
|
5466
|
+
}
|
|
5467
|
+
get state() {
|
|
5468
|
+
return this.status;
|
|
5469
|
+
}
|
|
5470
|
+
get disposed() {
|
|
5471
|
+
return this.life.disposed;
|
|
5472
|
+
}
|
|
5473
|
+
onDispose(callback) {
|
|
5474
|
+
return this.life.onDispose(callback);
|
|
5475
|
+
}
|
|
5476
|
+
/** @internal Hosts call only after all eligible preheld buttons/keys are neutral. */
|
|
5477
|
+
arm() {
|
|
5478
|
+
if (this.status === InputCaptureState.Arming) this.status = InputCaptureState.Listening;
|
|
5479
|
+
}
|
|
5480
|
+
/** @internal Offer one fresh physical down, never a repeat or opening gesture. */
|
|
5481
|
+
accept(input) {
|
|
5482
|
+
if (this.status !== InputCaptureState.Listening) return false;
|
|
5483
|
+
if (!input || typeof input !== "object" || !Object.values(InputDevice).includes(input.device)) throw new EngineError("INVALID_INPUT_CAPTURE", "Unknown physical input device");
|
|
5484
|
+
if (!this.devices.includes(input.device)) return false;
|
|
5485
|
+
let descriptor, binding;
|
|
5486
|
+
if (input.device === InputDevice.Keyboard) {
|
|
5487
|
+
const code = parseKeyCode(input.code);
|
|
5488
|
+
descriptor = {
|
|
5489
|
+
device: InputDevice.Keyboard,
|
|
5490
|
+
code
|
|
5491
|
+
};
|
|
5492
|
+
binding = Object.freeze({ keys: Object.freeze([code]) });
|
|
5493
|
+
} else if (input.device === InputDevice.Mouse) {
|
|
5494
|
+
const button = parseMouseButton(input.button);
|
|
5495
|
+
descriptor = {
|
|
5496
|
+
device: InputDevice.Mouse,
|
|
5497
|
+
button
|
|
5498
|
+
};
|
|
5499
|
+
binding = Object.freeze({ mouse: Object.freeze([button]) });
|
|
5500
|
+
} else {
|
|
5501
|
+
const index = gamepadIndex(input.index), button = gamepadIndex(input.button);
|
|
5502
|
+
if (this.gamepadIndex !== void 0 && this.gamepadIndex !== index) return false;
|
|
5503
|
+
if (typeof input.id !== "string" || typeof input.mapping !== "string") throw new EngineError("INVALID_INPUT_CAPTURE", "Gamepad capture requires device facts");
|
|
5504
|
+
descriptor = {
|
|
5505
|
+
device: InputDevice.Gamepad,
|
|
5506
|
+
index,
|
|
5507
|
+
button,
|
|
5508
|
+
id: input.id,
|
|
5509
|
+
mapping: input.mapping
|
|
5510
|
+
};
|
|
5511
|
+
binding = Object.freeze({ gamepad: Object.freeze({ buttons: Object.freeze([button]) }) });
|
|
5512
|
+
}
|
|
5513
|
+
this.finish(InputCaptureState.Completed, Object.freeze({
|
|
5514
|
+
...descriptor,
|
|
5515
|
+
binding
|
|
5516
|
+
}));
|
|
5517
|
+
return true;
|
|
5518
|
+
}
|
|
5519
|
+
finish(state, input) {
|
|
5520
|
+
if (this.disposed) return;
|
|
5521
|
+
this.status = state;
|
|
5522
|
+
try {
|
|
5523
|
+
this.life.dispose();
|
|
5524
|
+
} finally {
|
|
5525
|
+
this.settle(input);
|
|
5019
5526
|
}
|
|
5020
5527
|
}
|
|
5528
|
+
cancel() {
|
|
5529
|
+
this.finish(InputCaptureState.Cancelled, void 0);
|
|
5530
|
+
}
|
|
5531
|
+
dispose() {
|
|
5532
|
+
this.cancel();
|
|
5533
|
+
}
|
|
5021
5534
|
};
|
|
5022
5535
|
// packages/core/src/ui/canvas-layout.ts
|
|
5023
5536
|
var finite = (v) => {
|
|
@@ -5535,6 +6048,11 @@ var PointerRouting = class {
|
|
|
5535
6048
|
owns(id) {
|
|
5536
6049
|
return this.gestures.has(id) || this.suppressed.has(id);
|
|
5537
6050
|
}
|
|
6051
|
+
/** @internal Mouse bindings observe world ownership without claiming a second gesture. */
|
|
6052
|
+
worldOwns(id) {
|
|
6053
|
+
const gesture = this.gestures.get(id);
|
|
6054
|
+
return Boolean(gesture && !gesture.node && !gesture.target && !gesture.scroll && !gesture.candidates.length);
|
|
6055
|
+
}
|
|
5538
6056
|
move(data) {
|
|
5539
6057
|
this.validate(data);
|
|
5540
6058
|
if (this.suppressed.has(data.pointerId)) return;
|
|
@@ -7082,7 +7600,7 @@ var ReplayPlayer = class {
|
|
|
7082
7600
|
this.engine = engine;
|
|
7083
7601
|
this.data = parseReplayData(data);
|
|
7084
7602
|
this.bound = bindings(engine, options.controllers);
|
|
7085
|
-
if (this.data.engineVersion !== "0.1.
|
|
7603
|
+
if (this.data.engineVersion !== "0.1.6" || engine.random.seed !== this.data.random.seed) throw new EngineError("REPLAY_INCOMPATIBLE", "Engine version or initial seed does not match Replay");
|
|
7086
7604
|
if (!compatible(this.bound.map(([id, c]) => ({
|
|
7087
7605
|
id,
|
|
7088
7606
|
actions: c.schema()
|
|
@@ -8980,6 +9498,6 @@ var CanvasUI = class {
|
|
|
8980
9498
|
], "Canvas UI cleanup failed");
|
|
8981
9499
|
}
|
|
8982
9500
|
};
|
|
8983
|
-
export { Action, ActionController, ActionMovement, ActionSource, Actor, ActorState, Aspect, BodyType, Camera, CameraFollow, Cancellation, CanvasButton, CanvasCheckbox, CanvasCheckboxNode, CanvasColumn, CanvasHoldButton, CanvasInputNode, CanvasLabel, CanvasNode, CanvasNumberInput, CanvasNumberInputNode, CanvasPanel, CanvasRow, CanvasScroll, CanvasSelect, CanvasSelectNode, CanvasSlider, CanvasSliderNode, CanvasTextEditorNode, CanvasTextInput, CanvasTextInputNode, CanvasUI, Character, CharacterActor, Collider, CollisionBody, CollisionResponse, CollisionShape, CollisionWorld, Component, ComponentPhase, ContactEnter, ContactExit, ContactStay, DEFAULT_RANDOM_STREAM, ENGINE_VERSION, Easing, Engine, EngineError, EventBus, FixedStepRunner, GeometryTilemap, GeometryTilemapLayer, Grid, HexOrientation, InputSystem, KeyCode, KeyboardBindings, KeyboardSource, Lifetime, Motion, PointerCancel, PointerClick, PointerDown, PointerEnter, PointerLeave, PointerMove, PointerRouting, PointerUp, RANDOM_ALGORITHM, RandomManager, RandomStream, Renderable, ReplayPlayer, ReplayRecorder, Scene, ScenePointer, SceneState, Shape, SpriteAnimation, SpriteAnimationState, SpriteFit, SpriteSheet, TileContactEnter, TileContactExit, TileContactStay, TileGeometry, Tilemap, TilemapLayer, Transform, Tween, TweenBinding, TweenPlayback, TweenScheduler, VirtualButton, VirtualControl, VirtualInput, VirtualRegions, VirtualStick, VirtualStickMode, actorTween, canvasControlText, canvasHoverHighlight, canvasNumericRange, canvasNumericValue, canvasOpacity, canvasScrollbars, canvasSliderGeometry, canvasTween, cleanupAll, containsScreenPoint, containsUI, createViewTransform, defaultCanvasStyle, defineActions, defineComponent, defineEvent, deriveStreamSeed, imageSize, intersectUI, isKeyCode, layoutCanvas, nativeSession, parseKeyCode, parseReplayData, positive, screenPoint, screenToPhysical, screenToWorld, scrollbarContains, sliderTween, spriteFrame, spriteFrameBounds, tweenFinite, worldPoint, worldToScreen, wrapCanvasText };
|
|
9501
|
+
export { Action, ActionController, ActionMovement, ActionSource, Actor, ActorState, Aspect, BodyType, Camera, CameraFollow, Cancellation, CanvasButton, CanvasCheckbox, CanvasCheckboxNode, CanvasColumn, CanvasHoldButton, CanvasInputNode, CanvasLabel, CanvasNode, CanvasNumberInput, CanvasNumberInputNode, CanvasPanel, CanvasRow, CanvasScroll, CanvasSelect, CanvasSelectNode, CanvasSlider, CanvasSliderNode, CanvasTextEditorNode, CanvasTextInput, CanvasTextInputNode, CanvasUI, Character, CharacterActor, Collider, CollisionBody, CollisionResponse, CollisionShape, CollisionWorld, Component, ComponentPhase, ContactEnter, ContactExit, ContactStay, DEFAULT_RANDOM_STREAM, ENGINE_VERSION, Easing, Engine, EngineError, EventBus, FixedStepRunner, GamepadAxis, GamepadBindings, GamepadButton, GeometryTilemap, GeometryTilemapLayer, Grid, HexOrientation, InputCapture, InputCaptureState, InputDevice, InputSystem, KeyCode, KeyboardBindings, KeyboardSource, Lifetime, Motion, MouseButton, MouseSource, PointerCancel, PointerClick, PointerDown, PointerEnter, PointerLeave, PointerMove, PointerRouting, PointerUp, RANDOM_ALGORITHM, RandomManager, RandomStream, Renderable, ReplayPlayer, ReplayRecorder, Scene, ScenePointer, SceneState, Shape, SpriteAnimation, SpriteAnimationState, SpriteFit, SpriteSheet, TileContactEnter, TileContactExit, TileContactStay, TileGeometry, Tilemap, TilemapLayer, Transform, Tween, TweenBinding, TweenPlayback, TweenScheduler, VirtualButton, VirtualControl, VirtualInput, VirtualRegions, VirtualStick, VirtualStickMode, actorTween, canvasControlText, canvasHoverHighlight, canvasNumericRange, canvasNumericValue, canvasOpacity, canvasScrollbars, canvasSliderGeometry, canvasTween, checkedGamepadBindings, cleanupAll, containsScreenPoint, containsUI, createViewTransform, defaultCanvasStyle, defineActions, defineComponent, defineEvent, deriveStreamSeed, gamepadDeadZone, gamepadIndex, imageSize, intersectUI, isKeyCode, isMouseButton, layoutCanvas, nativeSession, parseKeyCode, parseMouseButton, parseReplayData, positive, screenPoint, screenToPhysical, screenToWorld, scrollbarContains, sliderTween, spriteFrame, spriteFrameBounds, tweenFinite, worldPoint, worldToScreen, wrapCanvasText };
|
|
8984
9502
|
|
|
8985
9503
|
//# sourceMappingURL=index.js.map
|