diff --git a/package.json b/package.json index 8e9686b49f005683ee8839013b58ad4c8095e166..304d7bff27963b890eb12e5c698ac619041e84f5 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dependencies": { "aframe": "https://github.com/robertlong/aframe#fix-increasing-offset", "aframe-extras": "^3.12.4", - "aframe-input-mapping-component": "https://github.com/fernandojsg/aframe-input-mapping-component#6ebc38f", + "aframe-input-mapping-component": "https://github.com/johnshaughnessy/aframe-input-mapping-component#23e2855", "aframe-teleport-controls": "https://github.com/netpro2k/aframe-teleport-controls#feature/teleport-origin", "extract-text-webpack-plugin": "^3.0.2", "material-design-lite": "^1.3.0", diff --git a/src/activators/pressedmove.js b/src/activators/pressedmove.js new file mode 100644 index 0000000000000000000000000000000000000000..c035383186e0997908be2eae5868a1a97e546dd4 --- /dev/null +++ b/src/activators/pressedmove.js @@ -0,0 +1,35 @@ +function PressedMove(el, button, onActivate) { + this.down = button + "down"; + this.up = button + "up"; + this.pressed = false; + this.onActivate = onActivate; + this.el = el; + this.onButtonDown = this.onButtonDown.bind(this); + this.onButtonUp = this.onButtonUp.bind(this); + this.onAxisMove = this.onAxisMove.bind(this); + el.addEventListener(this.down, this.onButtonDown); + el.addEventListener(this.up, this.onButtonUp); + el.addEventListener("axismove", this.onAxisMove); +} + +PressedMove.prototype = { + onAxisMove: function(event) { + if (this.pressed) { + this.onActivate(event); + } + }, + onButtonDown: function(event) { + this.pressed = true; + }, + onButtonUp: function(event) { + this.pressed = false; + }, + + removeListeners: function() { + this.el.addEventListener(this.down, this.onButtonDown); + this.el.addEventListener(this.up, this.onButtonUp); + this.el.addEventListener("axismove", this.onAxisMove); + } +}; + +export { PressedMove }; diff --git a/src/activators/reversey.js b/src/activators/reversey.js new file mode 100644 index 0000000000000000000000000000000000000000..d3f3967f2da72d954b9a47d81bfaa0f1782f95f2 --- /dev/null +++ b/src/activators/reversey.js @@ -0,0 +1,20 @@ +function ReverseY(el, button, onActivate) { + this.el = el; + this.emitReverseY = this.emitReverseY.bind(this); + this.onActivate = onActivate; + this.button = button; + this.removeListeners = this.removeListeners.bind(this); + el.addEventListener(button, this.emitReverseY); +} + +ReverseY.prototype = { + emitReverseY: function(event) { + event.detail.axis[1] *= -1; + this.onActivate(event); + }, + removeListeners: function() { + this.el.removeEventListener(this.button, this.emitReverseY); + } +}; + +export { ReverseY }; diff --git a/src/activators/shortpress.js b/src/activators/shortpress.js new file mode 100644 index 0000000000000000000000000000000000000000..494de3f7ab9e7ebb11c04a227740fe9fcd7e6a42 --- /dev/null +++ b/src/activators/shortpress.js @@ -0,0 +1,39 @@ +function ShortPress(el, button, onActivate) { + this.lastTime = 0; + this.timeOut = 500; + this.eventNameDown = button + "down"; + this.eventNameUp = button + "up"; + + this.el = el; + this.onActivate = onActivate; + + this.onButtonDown = this.onButtonDown.bind(this); + this.onButtonUp = this.onButtonUp.bind(this); + + el.addEventListener(this.eventNameDown, this.onButtonDown); + el.addEventListener(this.eventNameUp, this.onButtonUp); +} + +ShortPress.prototype = { + onButtonDown(event) { + console.log("down"); + var self = this; + this.pressTimer = window.setTimeout(function() { + console.log("activate"); + self.onActivate(event); + }, this.timeOut); + }, + + onButtonUp(event) { + console.log("up"); + clearTimeout(this.pressTimer); + }, + + removeListeners() { + this.el.removeEventListener(this.eventNameDown, this.onButtonDown); + this.el.removeEventListener(this.eventNameUp, this.onButtonUp); + } +}; + +console.log("foo"); +AFRAME.registerInputActivator("shortpress", ShortPress); diff --git a/src/behaviours/oculus-touch-joystick-dpad4.js b/src/behaviours/oculus-touch-joystick-dpad4.js new file mode 100644 index 0000000000000000000000000000000000000000..ed85bca9555cf127d6fd90e196753cfcd47e9f97 --- /dev/null +++ b/src/behaviours/oculus-touch-joystick-dpad4.js @@ -0,0 +1,31 @@ +import { angleTo4Direction, angleTo8Direction } from "../utils"; + +// @TODO specify 4 or 8 direction +function oculus_touch_joystick_dpad4(el, outputPrefix) { + this.angleToDirection = angleTo4Direction; + this.outputPrefix = outputPrefix; + this.centerRadius = 0.6; + this.previous = "none"; + this.hapticIntensity = "low"; + this.emitDPad4 = this.emitDPad4.bind(this); + el.addEventListener("axismove", this.emitDPad4); +} + +oculus_touch_joystick_dpad4.prototype = { + emitDPad4: function(event) { + const x = event.detail.axis[0]; + const y = event.detail.axis[1]; + const inCenter = + Math.abs(x) < this.centerRadius && Math.abs(y) < this.centerRadius; + const current = inCenter + ? "center" + : this.angleToDirection(Math.atan2(x, -y)); + if (current !== this.previous) { + this.previous = current; + event.target.emit(`${this.outputPrefix}_dpad4_${current}`); + event.target.emit("haptic_pulse", { intensity: this.hapticIntensity }); + } + } +}; + +export { oculus_touch_joystick_dpad4 }; diff --git a/src/behaviours/vive-trackpad-dpad4.js b/src/behaviours/vive-trackpad-dpad4.js new file mode 100644 index 0000000000000000000000000000000000000000..4ef7364ab7d8ee4c22780c68b1183b4eba0db82a --- /dev/null +++ b/src/behaviours/vive-trackpad-dpad4.js @@ -0,0 +1,57 @@ +import { angleTo4Direction, angleTo8Direction } from "../utils"; + +function vive_trackpad_dpad4(el, outputPrefix) { + this.outputPrefix = outputPrefix; + this.lastDirection = ""; + this.previous = ""; + this.pressed = false; + this.emitDPad4 = this.emitDPad4.bind(this); + this.press = this.press.bind(this); + this.unpress = this.unpress.bind(this); + this.hapticIntensity = "low"; + this.centerRadius = 0.6; + el.addEventListener("axismove", this.emitDPad4); + el.addEventListener("trackpaddown", this.press); + el.addEventListener("trackpadup", this.unpress); +} + +vive_trackpad_dpad4.prototype = { + press: function(_) { + this.pressed = true; + }, + unpress: function(_) { + this.pressed = false; + }, + emitDPad4: function(event) { + const x = event.detail.axis[0]; + const y = event.detail.axis[1]; + const inCenter = + Math.abs(x) < this.centerRadius && Math.abs(y) < this.centerRadius; + const direction = inCenter + ? "center" + : angleTo4Direction(Math.atan2(x, -y)); + const pressed = this.pressed ? "pressed_" : ""; + const current = `${pressed + direction}`; // e.g. "pressed_north" + + // Real axismove events are not perfectly [0,0]... + // This is a touchend event. + if (x === 0 && y === 0) { + event.target.emit(`${this.outputPrefix}_dpad4_${this.previous}_up`); + this.previous = ""; // Clear this because the user has lifted their finger. + return; + } + + if (current === this.previous) { + return; + } + + if (this.previous !== "") { + event.target.emit(`${this.outputPrefix}_dpad4_${this.previous}_up`); + } + + event.target.emit(`${this.outputPrefix}_dpad4_${current}_down`); + this.previous = current; + } +}; + +export { vive_trackpad_dpad4 }; diff --git a/src/components/axis-dpad.js b/src/components/axis-dpad.js deleted file mode 100644 index 90fb29176013384f42d3c2da02631a1f0a88c634..0000000000000000000000000000000000000000 --- a/src/components/axis-dpad.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @fileOverview - * Treats a pair of axes and a button as a dpad - * This is useful for Vive trackpad and Oculus Touch thumbstick - * - * @name axis-dpad.js - * @TODO allow use of thumbstick without press - * @TODO make axes configurable - */ - -const angleToDirection = function(angle) { - angle = (angle * THREE.Math.RAD2DEG + 180 + 45) % 360; - if (angle > 0 && angle < 90) { - return "down"; - } else if (angle >= 90 && angle < 180) { - return "left"; - } else if (angle >= 180 && angle < 270) { - return "up"; - } else { - return "right"; - } -}; - -AFRAME.registerComponent("axis-dpad", { - schema: { - centerZone: { default: 0.5 }, - moveEvents: { default: ["axismove"] }, - downEvents: { default: ["trackpaddown", "thumbstickdown"] }, - upEvents: { default: ["trackpadup", "thumbstickup"] } - }, - - init: function() { - this.onAxisMove = this.onAxisMove.bind(this); - this.onButtonPressed = this.onButtonPressed.bind(this); - this.lastPos = [0, 0]; - }, - - play: function() { - const { moveEvents, downEvents, upEvents } = this.data; - moveEvents.forEach(moveEvent => { - this.el.addEventListener(moveEvent, this.onAxisMove); - }); - downEvents.concat(upEvents).forEach(eventName => { - this.el.addEventListener(eventName, this.onButtonPressed); - }); - }, - - pause: function() { - const { moveEvents, downEvents, upEvents } = this.data; - moveEvents.forEach(moveEvent => { - this.el.removeEventListener(moveEvent, this.onAxisMove); - }); - downEvents.concat(upEvents).forEach(eventName => { - this.el.removeEventListener(eventName, this.onButtonPressed); - }); - }, - - onAxisMove: function(e) { - this.lastPos = e.detail.axis; - }, - - onButtonPressed: function(e) { - const [x, y] = this.lastPos; - const { upEvents, centerZone } = this.data; - const state = upEvents.includes(e.type) ? "up" : "down"; - const direction = - state === "up" && this.lastDirection // Always trigger the up event for the last down event - ? this.lastDirection - : x * x + y * y < centerZone * centerZone // If within center zone angle does not matter - ? "center" - : angleToDirection(Math.atan2(x, y)); - - this.el.emit(`dpad${direction}${state}`); - - if (state === "down") { - this.lastDirection = direction; - } else { - delete this.lastDirection; - } - } -}); diff --git a/src/components/character-controller.js b/src/components/character-controller.js index f20c758d04fec67ca3b8a20070965b4c8714073b..bd0a6617abaaaed5fdda9fc2e0c0811d97021a4c 100644 --- a/src/components/character-controller.js +++ b/src/components/character-controller.js @@ -4,196 +4,66 @@ const MAX_DELTA = 0.2; // Does not have any type of collisions yet. AFRAME.registerComponent("character-controller", { schema: { - groundAcc: { default: 10 }, - easing: { default: 8 }, + groundAcc: { default: 7 }, + easing: { default: 10 }, pivot: { type: "selector" }, - snapRotationRadian: { default: THREE.Math.DEG2RAD * 45 }, - wasdSpeed: { default: 0.8 }, + snapRotationDegrees: { default: THREE.Math.DEG2RAD * 45 }, rotationSpeed: { default: -3 } }, init: function() { this.velocity = new THREE.Vector3(0, 0, 0); this.accelerationInput = new THREE.Vector3(0, 0, 0); - this.onStopMoving = this.onStopMoving.bind(this); - this.onTranslateX = this.onTranslateX.bind(this); - this.onTranslateY = this.onTranslateY.bind(this); - this.onTranslateZ = this.onTranslateZ.bind(this); - this.onMoveForward = this.onMoveForward.bind(this); - this.onDontMoveForward = this.onDontMoveForward.bind(this); - this.onMoveBackward = this.onMoveBackward.bind(this); - this.onDontMoveBackward = this.onDontMoveBackward.bind(this); - this.onMoveLeft = this.onMoveLeft.bind(this); - this.onDontMoveLeft = this.onDontMoveLeft.bind(this); - this.onMoveRight = this.onMoveRight.bind(this); - this.onDontMoveRight = this.onDontMoveRight.bind(this); - this.boost = 1.0; - this.onBoost = this.onBoost.bind(this); - this.pendingSnapRotationMatrix = new THREE.Matrix4(); - this.onSnapRotateLeft = this.onSnapRotateLeft.bind(this); - this.onSnapRotateRight = this.onSnapRotateRight.bind(this); this.angularVelocity = 0; // Scalar value because we only allow rotation around Y - this.onRotateY = this.onRotateY.bind(this); + this.setAccelerationInput = this.setAccelerationInput.bind(this); + this.snapRotateLeft = this.snapRotateLeft.bind(this); + this.snapRotateRight = this.snapRotateRight.bind(this); + this.setAngularVelocity = this.setAngularVelocity.bind(this); }, update: function() { this.leftRotationMatrix = new THREE.Matrix4().makeRotationY( - this.data.snapRotationRadian + this.data.snapRotationDegrees ); this.rightRotationMatrix = new THREE.Matrix4().makeRotationY( - -this.data.snapRotationRadian + -this.data.snapRotationDegrees ); }, play: function() { const eventSrc = this.el.sceneEl; - eventSrc.addEventListener("stop_moving", this.onStopMoving); - eventSrc.addEventListener("translateX", this.onTranslateX); - eventSrc.addEventListener("translateY", this.onTranslateY); - eventSrc.addEventListener("translateZ", this.onTranslateZ); - eventSrc.addEventListener("action_move_forward", this.onMoveForward); - eventSrc.addEventListener( - "action_dont_move_forward", - this.onDontMoveForward - ); - eventSrc.addEventListener("action_move_backward", this.onMoveBackward); - eventSrc.addEventListener( - "action_dont_move_backward", - this.onDontMoveBackward - ); - eventSrc.addEventListener("action_move_left", this.onMoveLeft); - eventSrc.addEventListener("action_dont_move_left", this.onDontMoveLeft); - eventSrc.addEventListener("action_move_right", this.onMoveRight); - eventSrc.addEventListener("action_dont_move_right", this.onDontMoveRight); - - eventSrc.addEventListener("rotateY", this.onRotateY); - eventSrc.addEventListener("action_snap_rotate_left", this.onSnapRotateLeft); - eventSrc.addEventListener( - "action_snap_rotate_right", - this.onSnapRotateRight - ); - eventSrc.addEventListener("boost", this.onBoost); + eventSrc.addEventListener("move", this.setAccelerationInput); + eventSrc.addEventListener("rotateY", this.setAngularVelocity); + eventSrc.addEventListener("snap_rotate_left", this.snapRotateLeft); + eventSrc.addEventListener("snap_rotate_right", this.snapRotateRight); }, pause: function() { const eventSrc = this.el.sceneEl; - eventSrc.removeEventListener("stop_moving", this.onStopMoving); - eventSrc.removeEventListener("translateX", this.onTranslateX); - eventSrc.removeEventListener("translateY", this.onTranslateY); - eventSrc.removeEventListener("translateZ", this.onTranslateZ); - eventSrc.removeEventListener("action_move_forward", this.onMoveForward); - eventSrc.removeEventListener( - "action_dont_move_forward", - this.onDontMoveForward - ); - eventSrc.removeEventListener("action_move_backward", this.onMoveBackward); - eventSrc.removeEventListener( - "action_dont_move_backward", - this.onDontMoveBackward - ); - eventSrc.removeEventListener("action_move_left", this.onMoveLeft); - eventSrc.removeEventListener("action_dont_move_left", this.onDontMoveLeft); - eventSrc.removeEventListener("action_move_right", this.onMoveRight); - eventSrc.removeEventListener( - "action_dont_move_right", - this.onDontMoveRight - ); - eventSrc.removeEventListener("rotateY", this.onRotateY); - eventSrc.removeEventListener( - "action_snap_rotate_left", - this.onSnapRotateLeft - ); - eventSrc.removeEventListener( - "action_snap_rotate_right", - this.onSnapRotateRight - ); + eventSrc.removeEventListener("move", this.setAccelerationInput); + eventSrc.removeEventListener("rotateY", this.setAngularVelocity); + eventSrc.removeEventListener("snap_rotate_left", this.snapRotateLeft); + eventSrc.removeEventListener("snap_rotate_right", this.snapRotateRight); }, - onStopMoving: function(event) { - this.accelerationInput.set(0, 0, 0); + setAccelerationInput: function(event) { + const axes = event.detail.axis; + this.accelerationInput.set(axes[0], 0, axes[1]); }, - onTranslateX: function(event) { - // TODO: event.detail should't default to an object. - if (typeof event.detail !== "object") { - this.accelerationInput.setX(event.detail); - } else { - this.accelerationInput.setX(0); - } - }, - - onTranslateY: function(event) { - // TODO: event.detail should't default to an object. - if (typeof event.detail !== "object") { - this.accelerationInput.setY(event.detail); - } else { - this.accelerationInput.setY(0); - } - }, - - onTranslateZ: function(event) { - // TODO: event.detail should't default to an object. - if (typeof event.detail !== "object") { - this.accelerationInput.setZ(event.detail); - } else { - this.accelerationInput.setZ(0); - } + setAngularVelocity: function(event) { + this.angularVelocity = event.detail.value; }, - onMoveForward: function(event) { - this.accelerationInput.z = this.data.wasdSpeed; - }, - - onDontMoveForward: function(event) { - this.accelerationInput.z = 0; - }, - - onMoveBackward: function(event) { - this.accelerationInput.z = -this.data.wasdSpeed; - }, - - onDontMoveBackward: function(event) { - this.accelerationInput.z = 0; - }, - - onMoveLeft: function(event) { - this.accelerationInput.x = -this.data.wasdSpeed; - }, - - onDontMoveLeft: function(event) { - this.accelerationInput.x = 0; - }, - - onMoveRight: function(event) { - this.accelerationInput.x = this.data.wasdSpeed; - }, - - onDontMoveRight: function(event) { - this.accelerationInput.x = 0; - }, - - onRotateY: function(event) { - // TODO: event.detail should't default to an object. - if (typeof event.detail !== "object") { - this.angularVelocity = event.detail; - } else { - this.angularVelocity = 0; - } - }, - - onSnapRotateLeft: function(event) { + snapRotateLeft: function(event) { this.pendingSnapRotationMatrix.copy(this.leftRotationMatrix); }, - onSnapRotateRight: function(event) { + snapRotateRight: function(event) { this.pendingSnapRotationMatrix.copy(this.rightRotationMatrix); }, - onBoost: function(event) { - this.boost = event.detail; - }, - tick: (function() { const move = new THREE.Matrix4(); const trans = new THREE.Matrix4(); @@ -298,9 +168,13 @@ AFRAME.registerComponent("character-controller", { velocity.z = 0; } - const dvx = data.groundAcc * dt * this.accelerationInput.x * this.boost; - const dvz = data.groundAcc * dt * -this.accelerationInput.z * this.boost; + const dvx = data.groundAcc * dt * this.accelerationInput.x; + const dvz = data.groundAcc * dt * -this.accelerationInput.z; velocity.x += dvx; velocity.z += dvz; + + const decay = 0.7; + this.accelerationInput.x = this.accelerationInput.x * decay; + this.accelerationInput.z = this.accelerationInput.z * decay; } }); diff --git a/src/components/haptic-feedback.js b/src/components/haptic-feedback.js new file mode 100644 index 0000000000000000000000000000000000000000..1ef413d38939a183c25438694cebaec934d9cf23 --- /dev/null +++ b/src/components/haptic-feedback.js @@ -0,0 +1,57 @@ +const strengthForIntensity = { + low: 0.07, + medium: 0.2, + high: 1 +}; + +AFRAME.registerComponent("haptic-feedback", { + schema: { + hapticEventName: { default: "haptic_pulse" } + }, + + init: function() { + this.pulse = this.pulse.bind(this); + this.getActuator = this.getActuator.bind(this); + this.getActuator().then(actuator => { + this.actuator = actuator; + }); + }, + + getActuator() { + return new Promise((resolve, reject) => { + const tryGetActivator = () => { + var trackedControls = this.el.components["tracked-controls"]; + if ( + trackedControls && + trackedControls.controller && + trackedControls.controller.hapticActuators && + trackedControls.controller.hapticActuators.length + ) { + resolve(trackedControls.controller.hapticActuators[0]); + } else { + setTimeout(tryGetActivator, 1000); + } + }; + setTimeout(tryGetActivator, 1000); + }); + }, + + play: function() { + this.el.addEventListener(this.data.hapticEventName, this.pulse); + }, + pause: function() { + this.el.removeEventListener(this.data.hapticEventName, this.pulse); + }, + + pulse: function(event) { + let { intensity } = event.detail; + if (!strengthForIntensity[intensity]) { + console.warn(`Invalid intensity : ${intensity}`); + return; + } + + if (this.actuator) { + this.actuator.pulse(strengthForIntensity[intensity], 15); + } + } +}); diff --git a/src/components/split-axis-events.js b/src/components/split-axis-events.js deleted file mode 100644 index 291b91ff6ebcf4add84004bc49002e936423b2df..0000000000000000000000000000000000000000 --- a/src/components/split-axis-events.js +++ /dev/null @@ -1,30 +0,0 @@ -AFRAME.registerComponent("split-axis-events", { - init: function() { - this.pressed = false; - this.onAxisMove = this.onAxisMove.bind(this); - this.onButtonChanged = this.onButtonChanged.bind(this); - }, - - play: function() { - this.el.addEventListener("axismove", this.onAxisMove); - this.el.addEventListener("buttonchanged", this.onButtonChanged); - }, - - pause: function() { - this.el.removeEventListener("axismove", this.onAxisMove); - this.el.removeEventListener("buttonchanged", this.onButtonChanged); - }, - - onAxisMove: function(event) { - var name = "touchpad" + (this.pressed ? "pressed" : "") + "axismove"; - this.el.emit(name + "x", event.detail.axis[0]); - this.el.emit(name + "y", event.detail.axis[1]); - }, - - onButtonChanged: function(event) { - if (this.pressed && !event.detail.state.pressed) { - this.el.emit("touchpadbuttonup"); - } - this.pressed = event.detail.state.pressed; - } -}); diff --git a/src/components/virtual-gamepad-controls.js b/src/components/virtual-gamepad-controls.js index 21ecac8e22386e2a0bf6543a18903c959fb89891..d399e38b29765280a677bb23289cdc3e4c2aff6b 100644 --- a/src/components/virtual-gamepad-controls.js +++ b/src/components/virtual-gamepad-controls.js @@ -57,11 +57,9 @@ AFRAME.registerComponent("virtual-gamepad-controls", { const force = joystick.force < 1 ? joystick.force : 1; const x = Math.cos(angle) * force; const z = Math.sin(angle) * force; - this.el.sceneEl.emit("translateX", x); - this.el.sceneEl.emit("translateZ", z); + this.el.sceneEl.emit("move", { axis: [x, z] }); } else { - this.el.sceneEl.emit("translateX", 0); - this.el.sceneEl.emit("translateZ", 0); + this.el.sceneEl.emit("move", { axis: [0, 0] }); } } else { if (event.type === "move") { @@ -69,10 +67,10 @@ AFRAME.registerComponent("virtual-gamepad-controls", { const angle = joystick.angle.radian; const force = joystick.force < 1 ? joystick.force : 1; this.yaw = Math.cos(angle) * force; - this.el.sceneEl.emit("rotateY", this.yaw); + this.el.sceneEl.emit("rotateY", { value: this.yaw }); } else { this.yaw = 0; - this.el.sceneEl.emit("rotateY", this.yaw); + this.el.sceneEl.emit("rotateY", { value: this.yaw }); } } }, diff --git a/src/components/wasd-to-analog2d.js b/src/components/wasd-to-analog2d.js new file mode 100644 index 0000000000000000000000000000000000000000..1b83f8f63a2ef969300ef1c91a0814f04a1f0ed8 --- /dev/null +++ b/src/components/wasd-to-analog2d.js @@ -0,0 +1,100 @@ +AFRAME.registerComponent("wasd-to-analog2d", { + schema: { + analog2dOutputAction: { default: "wasd_analog2d" } + }, + + init: function() { + this.output = [0, 0]; + this.vectors = { + w: [0, 1], + a: [-1, 0], + s: [0, -1], + d: [1, 0] + }; + this.onWasd = this.onWasd.bind(this); + this.keys = {}; + this.move = this.move.bind(this); + }, + + play: function() { + const eventNames = [ + "w_down", + "w_up", + "a_down", + "a_up", + "s_down", + "s_up", + "d_down", + "d_up" + ]; + for (var name of eventNames) { + this.el.sceneEl.addEventListener(name, this.onWasd); + } + // I listen to events that this component generates instead of emitting "move" + // directly because ideally this would live as an input mapping, but the events + // generated by this component won't actually get mapped. + this.el.sceneEl.addEventListener(this.data.analog2dOutputAction, this.move); + }, + + move: function(event) { + this.el.emit("move", { axis: event.detail.axis }); + }, + + pause: function() { + this.el.sceneEl.removeEventListener("wasd", this.onWasd); + this.el.sceneEl.removeEventListener( + this.data.analog2dOutputAction, + this.move + ); + }, + + onWasd: function(event) { + const keyEvent = event.type; + const down = keyEvent.indexOf("down") !== -1; + const key = keyEvent[0].toLowerCase(); + this.keys[key] = down; + }, + + tick: function(t, dt) { + this.target = [0, 0]; + + for (var key in this.keys) { + if (this.keys[key] && this.vectors[key]) { + this.target = [ + this.target[0] + this.vectors[key][0], + this.target[1] + this.vectors[key][1] + ]; + } + } + + const targetMagnitude = Math.sqrt( + this.target[0] * this.target[0] + this.target[1] * this.target[1] + ); + if (targetMagnitude !== 0) { + this.target[0] = this.target[0] / targetMagnitude; + this.target[1] = this.target[1] / targetMagnitude; + } + + const epsilon = 0.01; + if ( + Math.abs(this.output[0]) < epsilon && + Math.abs(this.output[1]) < epsilon && + this.target[0] === 0 && + this.target[1] === 0 + ) { + return; // Staying at [0,0] doesn't require new events. + } + + const easeInSpeed = 0.25; + this.output = [ + this.output[0] + easeInSpeed * (this.target[0] - this.output[0]), + this.output[1] + easeInSpeed * (this.target[1] - this.output[1]) + ]; + + if (this.output !== [0, 0]) { + this.el.emit(this.data.analog2dOutputAction, { + axis: this.output + }); + } + } +}); diff --git a/src/input-mappings.js b/src/input-mappings.js index d57ff6496b1d35bf0a435b06cfdb74dd807008e6..272e3889ada96d6638d27544d3ea27ec379e5395 100644 --- a/src/input-mappings.js +++ b/src/input-mappings.js @@ -1,47 +1,94 @@ -export default function registerInputMappings() { - AFRAME.registerInputMappings({ - mappings: { - default: { - common: { - // @TODO these dpad events are emmited by an axis-dpad component. This should probalby move into either tracked-controller or input-mapping - dpadleftdown: "action_snap_rotate_left", - dpadrightdown: "action_snap_rotate_right", - dpadcenterdown: "action_teleport_down", // @TODO once once #30 lands in aframe-teleport controls this just maps to "action_teleport_aim" - dpadcenterup: "action_teleport_up", // @TODO once once #30 lands in aframe-teleport controls this just maps to "action_teleport_teleport" - touchpadpressedaxismovex: "translateX", - touchpadpressedaxismovey: "translateZ", - touchpadbuttonup: "stop_moving" - }, - "vive-controls": { - menudown: "action_mute" - }, - "oculus-touch-controls": { - xbuttondown: "action_mute", - gripdown: "middle_ring_pinky_down", - gripup: "middle_ring_pinky_up", - thumbsticktouchstart: "thumb_down", - thumbsticktouchend: "thumb_up", - triggerdown: "index_down", - triggerup: "index_up" +const inGameActions = { + // Define action sets here. + // An action set separates "driving" controls from "menu" controls. + // Only one action set is active at a time. + default: { + move: { label: "Move" }, + snap_rotate_left: { label: "Snap Rotate Left" }, + snap_rotate_right: { label: "Snap Rotate Right" }, + action_mute: { label: "Mute" }, + action_teleport_down: { label: "Teleport Aim" }, + action_teleport_up: { label: "Teleport" }, + action_share_screen: { label: "Share Screen" } + } +}; + +const config = { + behaviours: { + default: { + "oculus-touch-controls": { + joystick: "oculus_touch_joystick_dpad4" + }, + "vive-controls": { + trackpad: "vive_trackpad_dpad4" + } + } + }, + mappings: { + default: { + "vive-controls": { + menudown: "action_mute", + "trackpad.pressedmove": { left: "move" }, + trackpad_dpad4_pressed_west_down: { right: "snap_rotate_left" }, + trackpad_dpad4_pressed_east_down: { right: "snap_rotate_right" }, + trackpad_dpad4_pressed_center_down: { right: "action_teleport_down" }, + trackpadup: { right: "action_teleport_up" } + }, + "oculus-touch-controls": { + joystick_dpad4_west: { + right: "snap_rotate_left" }, - daydream: { - menudown: "action_mute" + joystick_dpad4_east: { + right: "snap_rotate_right" }, - keyboard: { - m_press: "action_mute", - q_press: "action_snap_rotate_left", - e_press: "action_snap_rotate_right", - v_press: "action_share_screen", - w_down: "action_move_forward", - w_up: "action_dont_move_forward", - a_down: "action_move_left", - a_up: "action_dont_move_left", - s_down: "action_move_backward", - s_up: "action_dont_move_backward", - d_down: "action_move_right", - d_up: "action_dont_move_right" - } + xbuttondown: "action_mute", + gripdown: "middle_ring_pinky_down", + gripup: "middle_ring_pinky_up", + thumbsticktouchstart: "thumb_down", + thumbsticktouchend: "thumb_up", + // @TODO: How do I map more than one action to triggerdown? + // triggerdown: "index_down", + // triggerup: "index_up", + triggerdown: "action_teleport_down", + triggerup: "action_teleport_up", + "axismove.reverseY": { left: "move" }, + right_dpad_east: "snap_rotate_right", + right_dpad_west: "snap_rotate_left", + abuttondown: "action_teleport_down", + abuttonup: "action_teleport_up" + }, + "daydream-controls": { + menudown: "action_mute", + trackpaddown: "action_teleport_down", + trackpadup: "action_teleport_up" + }, + keyboard: { + m_press: "action_mute", + q_press: "snap_rotate_left", + e_press: "snap_rotate_right", + v_press: "action_share_screen", + + // We can't create a keyboard behaviour with AFIM yet, + // so these will get captured by wasd-to-analog2d + w_down: "w_down", + w_up: "w_up", + a_down: "a_down", + a_up: "a_up", + s_down: "s_down", + s_up: "s_up", + d_down: "d_down", + d_up: "d_up", + W_down: "w_down", + W_up: "w_up", + A_down: "a_down", + A_up: "a_up", + S_down: "s_down", + S_up: "s_up", + D_down: "d_down", + D_up: "d_up" } } - }); -} + } +}; + +export { inGameActions, config }; diff --git a/src/room.js b/src/room.js index b79902452663c26a2c8b16e611f697ee67269107..4124d5fd7f4719ccbe8fc99c0817621d2a879aa9 100644 --- a/src/room.js +++ b/src/room.js @@ -10,7 +10,13 @@ import "aframe-input-mapping-component"; import animationMixer from "aframe-extras/src/loaders/animation-mixer"; AFRAME.registerComponent("animation-mixer", animationMixer); -import "./components/axis-dpad"; +import { vive_trackpad_dpad4 } from "./behaviours/vive-trackpad-dpad4"; +import { oculus_touch_joystick_dpad4 } from "./behaviours/oculus-touch-joystick-dpad4"; +import { PressedMove } from "./activators/pressedmove"; +import { ReverseY } from "./activators/reversey"; +import "./activators/shortpress"; +import "./components/wasd-to-analog2d"; //Might be a behaviour or activator in the future + import "./components/mute-mic"; import "./components/audio-feedback"; import "./components/nametag-transform"; @@ -19,7 +25,7 @@ import "./components/virtual-gamepad-controls"; import "./components/body-controller"; import "./components/hand-controls2"; import "./components/character-controller"; -import "./components/split-axis-events"; +import "./components/haptic-feedback"; import "./components/networked-video-player"; import "./components/offset-relative-to"; import "./components/cached-gltf-model"; @@ -29,12 +35,21 @@ import "./components/layers"; import "./components/spawn-controller"; import "./systems/personal-space-bubble"; -import registerNetworkScheams from "./network-schemas"; -import registerInputMappings from "./input-mappings"; import { promptForName, getCookie, parseJwt } from "./utils"; - -registerNetworkScheams(); -registerInputMappings(); +import registerNetworkSchemas from "./network-schemas"; +import { inGameActions, config } from "./input-mappings"; + +AFRAME.registerInputBehaviour("vive_trackpad_dpad4", vive_trackpad_dpad4); +AFRAME.registerInputBehaviour( + "oculus_touch_joystick_dpad4", + oculus_touch_joystick_dpad4 +); +AFRAME.registerInputActivator("pressedmove", PressedMove); +AFRAME.registerInputActivator("reverseY", ReverseY); +AFRAME.registerInputActions(inGameActions, "default"); +AFRAME.registerInputMappings(config); + +registerNetworkSchemas(); function shareScreen() { const track = NAF.connection.adapter.localMediaStream.getVideoTracks()[0]; diff --git a/src/utils.js b/src/utils.js index b37764120a388120c89392fb6b9b97f31dd59578..346f0994cf16943b7461a34e778cca16c87eebfc 100644 --- a/src/utils.js +++ b/src/utils.js @@ -167,9 +167,8 @@ export function generateName() { } export function promptForName(username) { - if (!username) - username = generateName(); - + if (!username) username = generateName(); + do { username = prompt("Choose a username", username); } while (!(username && username.length)); @@ -179,11 +178,46 @@ export function promptForName(username) { export function getCookie(name) { var value = "; " + document.cookie; var parts = value.split("; " + name + "="); - if (parts.length == 2) return parts.pop().split(";").shift(); + if (parts.length == 2) + return parts + .pop() + .split(";") + .shift(); } -export function parseJwt (token) { - var base64Url = token.split('.')[1]; - var base64 = base64Url.replace('-', '+').replace('_', '/'); +export function parseJwt(token) { + var base64Url = token.split(".")[1]; + var base64 = base64Url.replace("-", "+").replace("_", "/"); return JSON.parse(window.atob(base64)); } + +export function angleTo4Direction(angle) { + angle = (angle * THREE.Math.RAD2DEG + 180 + 45) % 360; + if (angle > 0 && angle < 90) { + return "north"; + } else if (angle >= 90 && angle < 180) { + return "west"; + } else if (angle >= 180 && angle < 270) { + return "south"; + } else { + return "east"; + } +} + +export function angleTo8Direction(angle) { + angle = (angle * THREE.Math.RAD2DEG + 180 + 45) % 360; + var direction = ""; + if ((angle >= 0 && angle < 120) || angle >= 330) { + direction += "north"; + } + if (angle >= 150 && angle < 300) { + direction += "south"; + } + if (angle >= 60 && angle < 210) { + direction += "west"; + } + if ((angle >= 240 && angle < 360) || angle < 30) { + direction += "east"; + } + return direction; +} diff --git a/templates/room.hbs b/templates/room.hbs index 0e90903456c0dda97f644339b5cc3eea899c90c1..5a86966219e6648d0076302ae17d5ed28538bfca 100644 --- a/templates/room.hbs +++ b/templates/room.hbs @@ -14,7 +14,7 @@ <script src="{{asset "manifest.js" }}"></script> <script src="{{asset "room-vendor.js" }}"></script> <script src="{{asset "room.js" }}"></script> - + <meta charset="UTF-8"> <style> .a-enter-vr { top: 90px; @@ -123,6 +123,7 @@ id="player-rig" networked spawn-controller="radius: 4;" + wasd-to-analog2d character-controller="pivot: #head" > <a-entity @@ -130,7 +131,7 @@ camera="userHeight: 1.6" personal-space-bubble look-controls - networked="template: #head-template; showLocalTemplate: false;" + networked="template: #head-template; showLocalTemplate: false;" ></a-entity> <a-entity @@ -138,7 +139,6 @@ body-controller="eyeNeckOffset: 0 -0.11 0.09; neckHeight: 0.05" networked="template: #body-template;" ></a-entity> - <a-entity id="nametag" networked="template: #nametag-template; showLocalTemplate: false;" @@ -146,9 +146,9 @@ <a-entity id="left-hand" - split-axis-events hand-controls2="left" - axis-dpad="centerZone: 1" + tracked-controls + haptic-feedback teleport-controls="cameraRig: #player-rig; teleportOrigin: #head; button: action_teleport_" networked="template: #left-hand-template;" > @@ -165,7 +165,7 @@ <a-entity id="right-hand" hand-controls2="right" - axis-dpad + haptic-feedback teleport-controls="cameraRig: #player-rig; teleportOrigin: #head; hitEntity: #telepor-indicator; diff --git a/yarn.lock b/yarn.lock index b7dcd3fb103518f93c53d7dec1ac1fa0781aa98b..f80cf7ea4a2386dfa33d9e906fd203d28d923787 100644 --- a/yarn.lock +++ b/yarn.lock @@ -49,15 +49,15 @@ acorn@^5.0.0, acorn@^5.2.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" aframe-extras@^3.12.4: - version "3.12.4" - resolved "https://registry.yarnpkg.com/aframe-extras/-/aframe-extras-3.12.4.tgz#9276bde8b51a07a9822bbce1fc55f2eb8e6810dc" + version "3.13.1" + resolved "https://registry.yarnpkg.com/aframe-extras/-/aframe-extras-3.13.1.tgz#f8b6ef18c29e92538d05d94913640942a307c46c" dependencies: aframe-physics-system "^1.4.3" three-pathfinding "^0.2.2" -"aframe-input-mapping-component@https://github.com/fernandojsg/aframe-input-mapping-component#6ebc38f": - version "0.1.1" - resolved "https://github.com/fernandojsg/aframe-input-mapping-component#6ebc38f0e871e8ab66673aef5cd11f6ce052076c" +"aframe-input-mapping-component@https://github.com/johnshaughnessy/aframe-input-mapping-component#23e2855": + version "0.1.2" + resolved "https://github.com/johnshaughnessy/aframe-input-mapping-component#23e28559046a56e9606fd6cdb64cf8c2dfbd12ec" aframe-lerp-component@^1.1.0: version "1.1.0" @@ -117,8 +117,8 @@ ajv@^4.9.1: json-stable-stringify "^1.0.1" ajv@^5.0.0, ajv@^5.1.5, ajv@^5.2.3, ajv@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" + version "5.5.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.1.tgz#b38bb8876d9e86bee994956a04e721e88b248eb2" dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" @@ -934,8 +934,8 @@ big.js@^3.1.3: resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" binary-extensions@^1.0.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" blob@0.0.4: version "0.0.4" @@ -1077,11 +1077,11 @@ browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: electron-to-chromium "^1.2.7" browserslist@^2.1.2: - version "2.9.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.9.0.tgz#706aca15c53be15610f466e348cbfa0c00a6a379" + version "2.10.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.10.0.tgz#bac5ee1cc69ca9d96403ffb8a3abdc5b6aed6346" dependencies: - caniuse-lite "^1.0.30000760" - electron-to-chromium "^1.3.27" + caniuse-lite "^1.0.30000780" + electron-to-chromium "^1.3.28" buffer-equal@0.0.1: version "0.0.1" @@ -1186,12 +1186,12 @@ caniuse-api@^1.5.2: lodash.uniq "^4.5.0" caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000766" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000766.tgz#4c911aa3747f01388452fa4b927b78fcf1430680" + version "1.0.30000780" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000780.tgz#8d1977561d00ff0f0ed2b6b66140328ab4504c0a" -caniuse-lite@^1.0.30000760: - version "1.0.30000766" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000766.tgz#8a095cc5eb9923c27008ce4d0db23e65a3e28843" +caniuse-lite@^1.0.30000780: + version "1.0.30000780" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000780.tgz#1f9095f2efd4940e0ba6c5992ab7a9b64cc35ba4" "cannon@github:donmccurdy/cannon.js#v0.6.2-dev1": version "0.6.2" @@ -1227,8 +1227,8 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0: supports-color "^4.0.0" chardet@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.0.tgz#0bbe1355ac44d7a3ed4a925707c4ef70f8190f6c" + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" chokidar@^1.6.0, chokidar@^1.7.0: version "1.7.0" @@ -1362,11 +1362,7 @@ commander@2.2.x: version "2.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.2.0.tgz#175ad4b9317f3ff615f201c1e57224f55a3e91df" -commander@^2.5.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - -commander@~2.12.1: +commander@^2.5.0, commander@~2.12.1: version "2.12.2" resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" @@ -1469,8 +1465,8 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" convert-source-map@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" cookie-signature@1.0.6: version "1.0.6" @@ -1835,18 +1831,18 @@ detect-indent@^4.0.0: repeating "^2.0.0" detect-libc@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.2.tgz#71ad5d204bf17a6a6ca8f450c61454066ef461e1" + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" detect-node@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" detective@^4.3.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" + version "4.7.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.0.tgz#6276e150f9e50829ad1f90ace4d9a2304188afcf" dependencies: - acorn "^4.0.3" + acorn "^5.2.1" defined "^1.0.0" diffie-hellman@^5.0.0: @@ -1874,12 +1870,11 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" -doctrine@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" +doctrine@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" dependencies: esutils "^2.0.2" - isarray "^1.0.0" document-register-element@dmarcos/document-register-element#8ccc532b7: version "0.5.4" @@ -1932,9 +1927,9 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.27: - version "1.3.27" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz#78ecb8a399066187bb374eede35d9c70565a803d" +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.28: + version "1.3.28" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz#8dd4e6458086644e9f9f0a1cf32e2a1f9dffd9ee" elliptic@^6.0.0: version "6.4.0" @@ -2036,8 +2031,8 @@ error-ex@^1.2.0: is-arrayish "^0.2.1" es-abstract@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" + version "1.10.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -2054,8 +2049,8 @@ es-to-primitive@^1.1.1: is-symbol "^1.0.1" es5-ext@^0.10.12, es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.35" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.35.tgz#18ee858ce6a3c45c7d79e91c15fcca9ec568494f" + version "0.10.37" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" dependencies: es6-iterator "~2.0.1" es6-symbol "~3.1.1" @@ -2130,8 +2125,8 @@ escope@^3.6.0: estraverse "^4.1.1" eslint-config-prettier@^2.6.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.7.0.tgz#7bbfef66ad783277836f4ea556e68b9bcc9da4d0" + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" dependencies: get-stdin "^5.0.1" @@ -2150,8 +2145,8 @@ eslint-scope@^3.7.1: estraverse "^4.1.1" eslint@^4.10.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.11.0.tgz#39a8c82bc0a3783adf5a39fa27fdd9d36fac9a34" + version "4.12.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.12.1.tgz#5ec1973822b4a066b353770c3c6d69a2a188e880" dependencies: ajv "^5.3.0" babel-code-frame "^6.22.0" @@ -2159,7 +2154,7 @@ eslint@^4.10.0: concat-stream "^1.6.0" cross-spawn "^5.1.0" debug "^3.0.1" - doctrine "^2.0.0" + doctrine "^2.0.2" eslint-scope "^3.7.1" espree "^3.5.2" esquery "^1.0.0" @@ -2168,7 +2163,7 @@ eslint@^4.10.0: file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" glob "^7.1.2" - globals "^9.17.0" + globals "^11.0.1" ignore "^3.3.3" imurmurhash "^0.1.4" inquirer "^3.0.6" @@ -2304,7 +2299,7 @@ expand-tilde@^1.2.2: dependencies: os-homedir "^1.0.1" -express@^4.10.7, express@^4.13.3: +express@^4.10.7, express@^4.16.2: version "4.16.2" resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" dependencies: @@ -2366,10 +2361,14 @@ extract-text-webpack-plugin@^3.0.2: schema-utils "^0.3.0" webpack-sources "^1.0.1" -extsprintf@1.3.0, extsprintf@^1.2.0: +extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" @@ -2594,15 +2593,7 @@ fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" -fs-extra@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^4.0.3: +fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: @@ -2770,7 +2761,11 @@ global@~4.3.0: min-document "^2.19.0" process "~0.5.1" -globals@^9.17.0, globals@^9.18.0: +globals@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.0.1.tgz#12a87bb010e5154396acc535e1e43fc753b0e5e8" + +globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -3045,8 +3040,8 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" ini@^1.3.4, ini@~1.3.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" inquirer@^3.0.6: version "3.3.0" @@ -3074,8 +3069,8 @@ internal-ip@1.2.0: meow "^3.3.0" interpret@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" invariant@^2.2.2: version "2.2.2" @@ -3208,8 +3203,8 @@ is-path-in-cwd@^1.0.0: is-path-inside "^1.0.0" is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" @@ -3309,8 +3304,8 @@ jest-docblock@^21.0.0: resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" js-base64@^2.1.9: - version "2.3.2" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf" + version "2.4.0" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.0.tgz#9e566fee624751a1d720c966cd6226d29d4025aa" js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" @@ -3660,8 +3655,8 @@ miller-rabin@^4.0.0: brorand "^1.0.1" "mime-db@>= 1.30.0 < 2": - version "1.31.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.31.0.tgz#a49cd8f3ebf3ed1a482b60561d9105ad40ca74cb" + version "1.32.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414" mime-db@~1.30.0: version "1.30.0" @@ -3673,10 +3668,14 @@ mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.16, dependencies: mime-db "~1.30.0" -mime@1.4.1, mime@^1.3.4: +mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime@^1.3.4, mime@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" @@ -3773,8 +3772,8 @@ multicast-dns-service-types@^1.1.0: resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" multicast-dns@^6.0.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.1.1.tgz#6e7de86a570872ab17058adea7160bbeca814dde" + version "6.2.1" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.1.tgz#c5035defa9219d30640558a49298067352098060" dependencies: dns-packet "^1.0.1" thunky "^0.1.0" @@ -4565,8 +4564,8 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" prettier@^1.7.0: - version "1.8.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8" + version "1.9.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.9.1.tgz#41638a0d47c1efbd1b7d5a742aaa5548eab86d70" private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.8" @@ -4758,8 +4757,8 @@ rc@^1.1.7: strip-json-comments "~2.0.1" react-dom@^16.1.1: - version "16.1.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.1.1.tgz#b2e331b6d752faf1a2d31399969399a41d8d45f8" + version "16.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -4767,8 +4766,8 @@ react-dom@^16.1.1: prop-types "^15.6.0" react@^16.1.1: - version "16.1.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.1.1.tgz#d5c4ef795507e3012282dd51261ff9c0e824fe1f" + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -4879,8 +4878,8 @@ regenerate@^1.2.1: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" regenerator-runtime@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" regenerator-transform@^0.10.0: version "0.10.1" @@ -5911,18 +5910,18 @@ wbuf@^1.1.0, wbuf@^1.7.2: minimalistic-assert "^1.0.0" webpack-dev-middleware@^1.11.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709" + version "1.12.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" dependencies: memory-fs "~0.4.1" - mime "^1.3.4" + mime "^1.5.0" path-is-absolute "^1.0.0" range-parser "^1.0.3" time-stamp "^2.0.0" webpack-dev-server@^2.9.3: - version "2.9.4" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.4.tgz#7883e61759c6a4b33e9b19ec4037bd4ab61428d1" + version "2.9.7" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.7.tgz#100ad6a14775478924d417ca6dcfb9d52a98faed" dependencies: ansi-html "0.0.7" array-includes "^3.0.3" @@ -5932,7 +5931,7 @@ webpack-dev-server@^2.9.3: connect-history-api-fallback "^1.3.0" debug "^3.1.0" del "^3.0.0" - express "^4.13.3" + express "^4.16.2" html-entities "^1.2.0" http-proxy-middleware "~0.17.4" import-local "^0.1.1" @@ -5966,8 +5965,8 @@ webpack-sources@1.0.1, webpack-sources@^1.0.1: source-map "~0.5.3" webpack@^3.6.0: - version "3.8.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.8.1.tgz#b16968a81100abe61608b0153c9159ef8bb2bd83" + version "3.10.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" @@ -5993,8 +5992,8 @@ webpack@^3.6.0: yargs "^8.0.2" webrtc-adapter@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-6.0.2.tgz#765f99c163e46046a758fec457f7859c90a19487" + version "6.0.3" + resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-6.0.3.tgz#850ab1649099922086c2c038c87c10c46d0c42cc" dependencies: rtcpeerconnection-shim "^1.1.13" sdp "^2.3.0"