import "./assets/stylesheets/room.scss"; import queryString from "query-string"; import { patchWebGLRenderingContext } from "./utils/webgl"; patchWebGLRenderingContext(); import "aframe-xr"; import "./vendor/GLTFLoader"; import "networked-aframe"; import "naf-janus-adapter"; import "aframe-teleport-controls"; import "aframe-input-mapping-component"; import "aframe-billboard-component"; import "webrtc-adapter"; 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/bone-mute-state-indicator"; import "./components/2d-mute-state-indicator"; import "./components/virtual-gamepad-controls"; import "./components/ik-controller"; import "./components/hand-controls2"; import "./components/character-controller"; import "./components/haptic-feedback"; import "./components/networked-video-player"; import "./components/offset-relative-to"; import "./components/water"; import "./components/skybox"; import "./components/layers"; import "./components/spawn-controller"; import "./components/animated-robot-hands"; import "./components/hide-when-quality"; import "./components/animation-mixer"; import "./components/loop-animation"; import ReactDOM from "react-dom"; import React from "react"; import UIRoot from "./react-components/ui-root"; import "./systems/personal-space-bubble"; import "./gltf-component-mappings"; import { App } from "./App"; window.APP = new App(); const qs = queryString.parse(location.search); const isMobile = AFRAME.utils.device.isMobile(); if (qs.quality) { window.APP.quality = qs.quality; } else { window.APP.quality = isMobile ? "low" : "high"; } import "./elements/a-progressive-asset"; import "aframe-physics-system"; import "aframe-physics-extras"; import "super-hands"; import "./components/super-networked-interactable"; import "./components/networked-counter"; import "./components/super-spawner"; import "./components/super-cursor"; import "./components/event-repeater"; import registerNetworkSchemas from "./network-schemas"; import { inGameActions, config as inputConfig } from "./input-mappings"; import registerTelemetry from "./telemetry"; import Store from "./storage/store"; import { generateDefaultProfile } from "./utils/identity.js"; import { getAvailableVREntryTypes } from "./utils/vr-caps-detect.js"; import ConcurrentLoadDetector from "./utils/concurrent-load-detector.js"; registerTelemetry(); AFRAME.registerInputMappings(inputConfig, true); const store = new Store(); const concurrentLoadDetector = new ConcurrentLoadDetector(); concurrentLoadDetector.start(); // Always layer in any new default profile bits store.update({ profile: { ...generateDefaultProfile(), ...(store.state.profile || {}) }}) async function shareMedia(audio, video) { const constraints = { audio: !!audio, video: video ? { mediaSource: "screen", height: 720, frameRate: 30 } : false }; const mediaStream = await navigator.mediaDevices.getUserMedia(constraints); NAF.connection.adapter.setLocalMediaStream(mediaStream); const id = `${NAF.clientId}-screen`; let entity = document.getElementById(id); if (entity) { entity.setAttribute("visible", !!video); } else if (video) { const sceneEl = document.querySelector("a-scene"); entity = document.createElement("a-entity"); entity.id = id; entity.setAttribute("offset-relative-to", { target: "#player-camera", offset: "0 0 -2", on: "action_share_screen" }); entity.setAttribute("networked", { template: "#video-template" }); sceneEl.appendChild(entity); } } async function exitScene() { const scene = document.querySelector("a-scene"); scene.renderer.animate(null); // Stop animation loop, TODO A-Frame should do this document.body.removeChild(scene); } function setNameTagFromStore() { const myNametag = document.querySelector("#player-rig .nametag"); myNametag.setAttribute("text", "value", store.state.profile.display_name); } async function enterScene(mediaStream, enterInVR) { const scene = document.querySelector("a-scene"); document.querySelector("a-scene canvas").classList.remove("blurred") scene.setAttribute("networked-scene", "adapter: janus; audio: true; debug: true; connectOnLoad: false;"); registerNetworkSchemas(); if (enterInVR) { scene.enterVR(); } 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"); document.querySelector("#player-camera").setAttribute("look-controls", "pointerLockEnabled: true;"); const qs = queryString.parse(location.search); scene.setAttribute("networked-scene", { room: qs.room && !isNaN(parseInt(qs.room)) ? parseInt(qs.room) : 1, serverURL: process.env.JANUS_SERVER }); if (!qs.stats || !/off|false|0/.test(qs.stats)) { scene.setAttribute("stats", true); } if (isMobile || qs.mobile) { const playerRig = document.querySelector("#player-rig"); playerRig.setAttribute("virtual-gamepad-controls", {}); } setNameTagFromStore(); store.subscribe(setNameTagFromStore); const avatarScale = parseInt(qs.avatarScale, 10); if (avatarScale) { playerRig.setAttribute("scale", { x: avatarScale, y: avatarScale, z: avatarScale }); } let sharingScreen = false; // TODO remove scene.addEventListener("action_share_screen", () => { sharingScreen = !sharingScreen; shareMedia(true, sharingScreen); }); if (qs.offline) { onConnect(); } else { document.body.addEventListener("connected", onConnect); scene.components["networked-scene"].connect(); if (mediaStream) { NAF.connection.adapter.setLocalMediaStream(mediaStream); const hasVideo = !!(mediaStream.getVideoTracks().length > 0); const id = `${NAF.clientId}-screen`; let entity = document.getElementById(id); if (entity) { entity.setAttribute("visible", hasVideo); } else if (hasVideo) { const sceneEl = document.querySelector("a-scene"); entity = document.createElement("a-entity"); entity.id = id; entity.setAttribute("offset-relative-to", { target: "#head", offset: "0 0 -2", on: "action_share_screen" }); entity.setAttribute("networked", { template: "#video-template" }); sceneEl.appendChild(entity); } } } } function onConnect() { } function mountUI(scene) { const qs = queryString.parse(location.search); const disableAutoExitOnConcurrentLoad = qs.allow_multi === "true" let forcedVREntryType = null; if (qs.vr_entry_type) { forcedVREntryType = qs.vr_entry_type; } const uiRoot = ReactDOM.render(<UIRoot {...{ scene, enterScene, exitScene, concurrentLoadDetector, disableAutoExitOnConcurrentLoad, forcedVREntryType, store }} />, document.getElementById("ui-root")); getAvailableVREntryTypes().then(availableVREntryTypes => { uiRoot.setState({ availableVREntryTypes }); }); } const onReady = () => { const scene = document.querySelector("a-scene"); document.querySelector("a-scene canvas").classList.add("blurred"); window.APP.scene = scene; mountUI(scene); }; document.addEventListener("DOMContentLoaded", onReady);