diff --git a/dist/networked-aframe.js b/dist/networked-aframe.js index c143316a..75099012 100644 --- a/dist/networked-aframe.js +++ b/dist/networked-aframe.js @@ -207,7 +207,7 @@ eval("/* global AFRAME, NAF, THREE */\nvar naf = __webpack_require__(/*! ../NafI \*************************************/ /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { -eval("/* global AFRAME, NAF, THREE */\nvar deepEqual = __webpack_require__(/*! ../DeepEquals */ \"./src/DeepEquals.js\");\nvar InterpolationBuffer = __webpack_require__(/*! buffered-interpolation */ \"./node_modules/buffered-interpolation/dist/buffered-interpolation.js\");\n// InterpolationBuffer.MODE_LERP is not exported, it's undefined\nvar MODE_LERP = 0;\nvar DEG2RAD = THREE.MathUtils.DEG2RAD;\nvar OBJECT3D_COMPONENTS = ['position', 'rotation', 'scale'];\n\n// Expose InterpolationBuffer on NAF global\nNAF.InterpolationBuffer = InterpolationBuffer;\nfunction defaultRequiresUpdate() {\n var cachedData = null;\n return function (newData) {\n if (cachedData === null || !deepEqual(cachedData, newData)) {\n cachedData = AFRAME.utils.clone(newData);\n return true;\n }\n return false;\n };\n}\nfunction isValidVector3(v) {\n return !!(v.isVector3 && !isNaN(v.x) && !isNaN(v.y) && !isNaN(v.z) && v.x !== null && v.y !== null && v.z !== null);\n}\nfunction isValidQuaternion(q) {\n return !!(q.isQuaternion && !isNaN(q.x) && !isNaN(q.y) && !isNaN(q.z) && !isNaN(q.w) && q.x !== null && q.y !== null && q.z !== null && q.w !== null);\n}\nvar throttle = function () {\n var previousLogTime = 0;\n return function throttle(f, milliseconds) {\n var now = Date.now();\n if (now - previousLogTime > milliseconds) {\n previousLogTime = now;\n f();\n }\n };\n}();\nfunction warnOnInvalidNetworkUpdate() {\n NAF.log.warn(\"Received invalid network update.\");\n}\nAFRAME.registerSystem(\"networked\", {\n init: function init() {\n // An array of \"networked\" component instances.\n this.components = [];\n this.nextSyncTime = 0;\n },\n register: function register(component) {\n this.components.push(component);\n },\n deregister: function deregister(component) {\n var idx = this.components.indexOf(component);\n if (idx > -1) {\n this.components.splice(idx, 1);\n }\n },\n tick: function () {\n return function () {\n if (!NAF.connection.adapter) return;\n if (this.el.clock.elapsedTime < this.nextSyncTime) return;\n\n // \"d\" is an array of entity datas per entity in this.components.\n var data = {\n d: []\n };\n for (var i = 0, l = this.components.length; i < l; i++) {\n var c = this.components[i];\n if (!c.isMine()) continue;\n if (!c.el.parentElement) {\n NAF.log.error(\"entity registered with system despite being removed\");\n //TODO: Find out why tick is still being called\n return;\n }\n var syncData = this.components[i].syncDirty();\n if (!syncData) continue;\n data.d.push(syncData);\n }\n if (data.d.length > 0) {\n NAF.connection.broadcastData('um', data);\n }\n this.updateNextSyncTime();\n };\n }(),\n updateNextSyncTime: function updateNextSyncTime() {\n this.nextSyncTime = this.el.clock.elapsedTime + 1 / NAF.options.updateRate;\n }\n});\nAFRAME.registerComponent('networked', {\n schema: {\n template: {\n \"default\": ''\n },\n attachTemplateToLocal: {\n \"default\": true\n },\n persistent: {\n \"default\": false\n },\n networkId: {\n \"default\": ''\n },\n owner: {\n \"default\": ''\n },\n creator: {\n \"default\": ''\n }\n },\n init: function init() {\n this.OWNERSHIP_GAINED = 'ownership-gained';\n this.OWNERSHIP_CHANGED = 'ownership-changed';\n this.OWNERSHIP_LOST = 'ownership-lost';\n this.onOwnershipGainedEvent = {\n el: this.el\n };\n this.onOwnershipChangedEvent = {\n el: this.el\n };\n this.onOwnershipLostEvent = {\n el: this.el\n };\n this.conversionEuler = new THREE.Euler();\n this.conversionEuler.order = \"YXZ\";\n this.bufferInfos = [];\n this.bufferPosition = new THREE.Vector3();\n this.bufferQuaternion = new THREE.Quaternion();\n this.bufferScale = new THREE.Vector3();\n var wasCreatedByNetwork = this.wasCreatedByNetwork();\n this.onConnected = this.onConnected.bind(this);\n this.syncData = {};\n this.componentSchemas = NAF.schemas.getComponents(this.data.template);\n this.cachedElements = new Array(this.componentSchemas.length);\n this.networkUpdatePredicates = this.componentSchemas.map(function (x) {\n return x.requiresNetworkUpdate && x.requiresNetworkUpdate() || defaultRequiresUpdate();\n });\n\n // Fill cachedElements array with null elements\n this.invalidateCachedElements();\n this.initNetworkParent();\n var networkId;\n if (this.data.networkId === '') {\n networkId = NAF.utils.createNetworkId();\n this.el.setAttribute(this.name, {\n networkId: networkId\n });\n } else {\n networkId = this.data.networkId;\n }\n if (!this.el.id) {\n this.el.setAttribute('id', 'naf-' + networkId);\n }\n if (wasCreatedByNetwork) {\n this.firstUpdate();\n } else {\n if (this.data.attachTemplateToLocal) {\n this.attachTemplateToLocal();\n }\n this.registerEntity(this.data.networkId);\n }\n this.lastOwnerTime = -1;\n if (NAF.clientId) {\n this.onConnected();\n } else {\n document.body.addEventListener('connected', this.onConnected, false);\n }\n document.body.dispatchEvent(this.entityCreatedEvent());\n this.el.dispatchEvent(new CustomEvent('instantiated', {\n detail: {\n el: this.el\n }\n }));\n this.el.sceneEl.systems.networked.register(this);\n },\n attachTemplateToLocal: function attachTemplateToLocal() {\n var template = NAF.schemas.getCachedTemplate(this.data.template);\n var elAttrs = template.attributes;\n\n // Merge root element attributes with this entity\n for (var attrIdx = 0; attrIdx < elAttrs.length; attrIdx++) {\n this.el.setAttribute(elAttrs[attrIdx].name, elAttrs[attrIdx].value);\n }\n\n // Append all child elements\n while (template.firstElementChild) {\n this.el.appendChild(template.firstElementChild);\n }\n },\n takeOwnership: function takeOwnership() {\n var owner = this.data.owner;\n var lastOwnerTime = this.lastOwnerTime;\n var now = NAF.connection.getServerTime();\n if (owner && !this.isMine() && lastOwnerTime < now) {\n this.lastOwnerTime = now;\n this.removeLerp();\n this.el.setAttribute('networked', {\n owner: NAF.clientId\n });\n this.syncAll();\n this.onOwnershipGainedEvent.oldOwner = owner;\n this.el.emit(this.OWNERSHIP_GAINED, this.onOwnershipGainedEvent);\n this.onOwnershipChangedEvent.oldOwner = owner;\n this.onOwnershipChangedEvent.newOwner = NAF.clientId;\n this.el.emit(this.OWNERSHIP_CHANGED, this.onOwnershipChangedEvent);\n return true;\n }\n return false;\n },\n wasCreatedByNetwork: function wasCreatedByNetwork() {\n return !!this.el.firstUpdateData;\n },\n initNetworkParent: function initNetworkParent() {\n var parentEl = this.el.parentElement;\n if (parentEl['components'] && parentEl.components['networked']) {\n this.parent = parentEl;\n } else {\n this.parent = null;\n }\n },\n registerEntity: function registerEntity(networkId) {\n NAF.entities.registerEntity(networkId, this.el);\n },\n applyPersistentFirstSync: function applyPersistentFirstSync() {\n var networkId = this.data.networkId;\n var persistentFirstSync = NAF.entities.getPersistentFirstSync(networkId);\n if (persistentFirstSync) {\n this.networkUpdate(persistentFirstSync);\n NAF.entities.forgetPersistentFirstSync(networkId);\n }\n },\n firstUpdate: function firstUpdate() {\n var entityData = this.el.firstUpdateData;\n this.networkUpdate(entityData);\n },\n onConnected: function onConnected() {\n var _this = this;\n if (this.data.owner === '') {\n this.lastOwnerTime = NAF.connection.getServerTime();\n this.el.setAttribute(this.name, {\n owner: NAF.clientId,\n creator: NAF.clientId\n });\n setTimeout(function () {\n //a-primitives attach their components on the next frame; wait for components to be attached before calling syncAll\n if (!_this.el.parentNode) {\n NAF.log.warn(\"Networked element was removed before ever getting the chance to syncAll\");\n return;\n }\n _this.syncAll(undefined, true);\n }, 0);\n }\n document.body.removeEventListener('connected', this.onConnected, false);\n },\n isMine: function isMine() {\n return this.data.owner === NAF.clientId;\n },\n createdByMe: function createdByMe() {\n return this.data.creator === NAF.clientId;\n },\n tick: function tick(time, dt) {\n if (!this.isMine() && NAF.options.useLerp) {\n for (var i = 0; i < this.bufferInfos.length; i++) {\n var bufferInfo = this.bufferInfos[i];\n var buffer = bufferInfo.buffer;\n var object3D = bufferInfo.object3D;\n var componentNames = bufferInfo.componentNames;\n buffer.update(dt);\n if (componentNames.includes(\"position\")) {\n var position = buffer.getPosition();\n if (isValidVector3(position)) {\n object3D.position.copy(position);\n } else {\n throttle(warnOnInvalidNetworkUpdate, 5000);\n }\n }\n if (componentNames.includes(\"rotation\")) {\n var quaternion = buffer.getQuaternion();\n if (isValidQuaternion(quaternion)) {\n object3D.quaternion.copy(quaternion);\n } else {\n throttle(warnOnInvalidNetworkUpdate, 5000);\n }\n }\n if (componentNames.includes(\"scale\")) {\n var scale = buffer.getScale();\n if (isValidVector3(scale)) {\n object3D.scale.copy(scale);\n } else {\n throttle(warnOnInvalidNetworkUpdate, 5000);\n }\n }\n }\n }\n },\n /* Sending updates */\n\n syncAll: function syncAll(targetClientId, isFirstSync) {\n if (!this.canSync()) {\n return;\n }\n var components = this.gatherComponentsData(true);\n var syncData = this.createSyncData(components, isFirstSync);\n if (targetClientId) {\n NAF.connection.sendDataGuaranteed(targetClientId, 'u', syncData);\n } else {\n NAF.connection.broadcastDataGuaranteed('u', syncData);\n }\n },\n syncDirty: function syncDirty() {\n if (!this.canSync()) {\n return;\n }\n var components = this.gatherComponentsData(false);\n if (components === null) {\n return;\n }\n return this.createSyncData(components);\n },\n getCachedElement: function getCachedElement(componentSchemaIndex) {\n var cachedElement = this.cachedElements[componentSchemaIndex];\n if (cachedElement) {\n return cachedElement;\n }\n var componentSchema = this.componentSchemas[componentSchemaIndex];\n if (componentSchema.selector) {\n return this.cachedElements[componentSchemaIndex] = this.el.querySelector(componentSchema.selector);\n } else {\n return this.cachedElements[componentSchemaIndex] = this.el;\n }\n },\n invalidateCachedElements: function invalidateCachedElements() {\n for (var i = 0; i < this.cachedElements.length; i++) {\n this.cachedElements[i] = null;\n }\n },\n gatherComponentsData: function gatherComponentsData(fullSync) {\n var componentsData = null;\n for (var i = 0; i < this.componentSchemas.length; i++) {\n var componentSchema = this.componentSchemas[i];\n var componentElement = this.getCachedElement(i);\n if (!componentElement) {\n if (fullSync) {\n componentsData = componentsData || {};\n componentsData[i] = null;\n }\n continue;\n }\n var componentName = componentSchema.component ? componentSchema.component : componentSchema;\n var componentData = componentElement.getAttribute(componentName);\n if (componentData === null) {\n if (fullSync) {\n componentsData = componentsData || {};\n componentsData[i] = null;\n }\n continue;\n }\n var syncedComponentData = componentSchema.property ? componentData[componentSchema.property] : componentData;\n\n // Use networkUpdatePredicate to check if the component needs to be updated.\n // Call networkUpdatePredicate first so that it can update any cached values in the event of a fullSync.\n if (this.networkUpdatePredicates[i](syncedComponentData) || fullSync) {\n componentsData = componentsData || {};\n componentsData[i] = syncedComponentData;\n }\n }\n return componentsData;\n },\n createSyncData: function createSyncData(components, isFirstSync) {\n var syncData = this.syncData,\n data = this.data;\n syncData.networkId = data.networkId;\n syncData.owner = data.owner;\n syncData.creator = data.creator;\n syncData.lastOwnerTime = this.lastOwnerTime;\n syncData.template = data.template;\n syncData.persistent = data.persistent;\n syncData.parent = this.getParentId();\n syncData.components = components;\n syncData.isFirstSync = !!isFirstSync;\n return syncData;\n },\n canSync: function canSync() {\n // This client will send a sync if:\n //\n // - The client is the owner\n // - The client is the creator, and the owner is not in the room.\n //\n // The reason for the latter case is so the object will still be\n // properly instantiated if the owner leaves. (Since the object lifetime\n // is tied to the creator.)\n if (this.data.owner && this.isMine()) return true;\n if (!this.createdByMe()) return false;\n var clients = NAF.connection.getConnectedClients();\n for (var clientId in clients) {\n if (clientId === this.data.owner) return false;\n }\n return true;\n },\n getParentId: function getParentId() {\n this.initNetworkParent(); // TODO fix calling this each network tick\n if (!this.parent) {\n return null;\n }\n var netComp = this.parent.getAttribute('networked');\n return netComp.networkId;\n },\n /* Receiving updates */\n\n networkUpdate: function networkUpdate(entityData) {\n // Avoid updating components if the entity data received did not come from the current owner.\n if (entityData.lastOwnerTime < this.lastOwnerTime || this.lastOwnerTime === entityData.lastOwnerTime && this.data.owner > entityData.owner) {\n return;\n }\n\n // Hack to solve this bug: https://github.com/networked-aframe/networked-aframe/issues/200\n if (this.data === undefined) {\n return;\n }\n if (this.data.owner !== entityData.owner) {\n var wasMine = this.isMine();\n this.lastOwnerTime = entityData.lastOwnerTime;\n var oldOwner = this.data.owner;\n var newOwner = entityData.owner;\n this.el.setAttribute('networked', {\n owner: entityData.owner\n });\n if (wasMine) {\n this.onOwnershipLostEvent.newOwner = newOwner;\n this.el.emit(this.OWNERSHIP_LOST, this.onOwnershipLostEvent);\n }\n this.onOwnershipChangedEvent.oldOwner = oldOwner;\n this.onOwnershipChangedEvent.newOwner = newOwner;\n this.el.emit(this.OWNERSHIP_CHANGED, this.onOwnershipChangedEvent);\n }\n if (this.data.persistent !== entityData.persistent) {\n this.el.setAttribute('networked', {\n persistent: entityData.persistent\n });\n }\n this.updateNetworkedComponents(entityData.components);\n },\n updateNetworkedComponents: function updateNetworkedComponents(components) {\n for (var componentIndex = 0, l = this.componentSchemas.length; componentIndex < l; componentIndex++) {\n var componentData = components[componentIndex];\n var componentSchema = this.componentSchemas[componentIndex];\n var componentElement = this.getCachedElement(componentIndex);\n if (componentElement === null || componentData === null || componentData === undefined) {\n continue;\n }\n if (componentSchema.component) {\n if (componentSchema.property) {\n this.updateNetworkedComponent(componentElement, componentSchema.component, componentSchema.property, componentData);\n } else {\n this.updateNetworkedComponent(componentElement, componentSchema.component, componentData);\n }\n } else {\n this.updateNetworkedComponent(componentElement, componentSchema, componentData);\n }\n }\n },\n updateNetworkedComponent: function updateNetworkedComponent(el, componentName, data, value) {\n if (!NAF.options.useLerp || !OBJECT3D_COMPONENTS.includes(componentName)) {\n if (value === undefined) {\n el.setAttribute(componentName, data);\n } else {\n el.setAttribute(componentName, data, value);\n }\n return;\n }\n var bufferInfo;\n for (var i = 0, l = this.bufferInfos.length; i < l; i++) {\n var info = this.bufferInfos[i];\n if (info.object3D === el.object3D) {\n bufferInfo = info;\n break;\n }\n }\n if (!bufferInfo) {\n bufferInfo = {\n buffer: new InterpolationBuffer(MODE_LERP, 0.1),\n object3D: el.object3D,\n componentNames: [componentName]\n };\n this.bufferInfos.push(bufferInfo);\n } else {\n var componentNames = bufferInfo.componentNames;\n if (!componentNames.includes(componentName)) {\n componentNames.push(componentName);\n }\n }\n var buffer = bufferInfo.buffer;\n switch (componentName) {\n case 'position':\n buffer.setPosition(this.bufferPosition.set(data.x, data.y, data.z));\n return;\n case 'rotation':\n this.conversionEuler.set(DEG2RAD * data.x, DEG2RAD * data.y, DEG2RAD * data.z);\n buffer.setQuaternion(this.bufferQuaternion.setFromEuler(this.conversionEuler));\n return;\n case 'scale':\n buffer.setScale(this.bufferScale.set(data.x, data.y, data.z));\n return;\n }\n NAF.log.error('Could not set value in interpolation buffer.', el, componentName, data, bufferInfo);\n },\n removeLerp: function removeLerp() {\n this.bufferInfos = [];\n },\n remove: function remove() {\n if (this.isMine() && NAF.connection.isConnected()) {\n var syncData = {\n networkId: this.data.networkId\n };\n if (NAF.entities.hasEntity(this.data.networkId)) {\n NAF.connection.broadcastDataGuaranteed('r', syncData);\n } else {\n // The entity may already have been removed if the creator (different of the current owner) left the room.\n // Don't log an error in this case.\n if (!(this.data.creator && NAF.connection.activeDataChannels[this.data.creator] === false)) {\n NAF.log.error(\"Removing networked entity that is not in entities array.\");\n }\n }\n }\n NAF.entities.forgetEntity(this.data.networkId);\n document.body.dispatchEvent(this.entityRemovedEvent(this.data.networkId));\n this.el.sceneEl.systems.networked.deregister(this);\n },\n entityCreatedEvent: function entityCreatedEvent() {\n return new CustomEvent('entityCreated', {\n detail: {\n el: this.el\n }\n });\n },\n entityRemovedEvent: function entityRemovedEvent(networkId) {\n return new CustomEvent('entityRemoved', {\n detail: {\n networkId: networkId\n }\n });\n }\n});\n\n//# sourceURL=webpack://networked-aframe/./src/components/networked.js?"); +eval("/* global AFRAME, NAF, THREE */\nvar deepEqual = __webpack_require__(/*! ../DeepEquals */ \"./src/DeepEquals.js\");\nvar InterpolationBuffer = __webpack_require__(/*! buffered-interpolation */ \"./node_modules/buffered-interpolation/dist/buffered-interpolation.js\");\n// InterpolationBuffer.MODE_LERP is not exported, it's undefined\nvar MODE_LERP = 0;\nvar DEG2RAD = THREE.MathUtils.DEG2RAD;\nvar OBJECT3D_COMPONENTS = ['position', 'rotation', 'scale'];\n\n// Expose InterpolationBuffer on NAF global\nNAF.InterpolationBuffer = InterpolationBuffer;\nfunction defaultRequiresUpdate() {\n var cachedData = null;\n return function (newData) {\n if (cachedData === null || !deepEqual(cachedData, newData)) {\n cachedData = AFRAME.utils.clone(newData);\n return true;\n }\n return false;\n };\n}\nfunction isValidVector3(v) {\n return !!(v.isVector3 && !isNaN(v.x) && !isNaN(v.y) && !isNaN(v.z) && v.x !== null && v.y !== null && v.z !== null);\n}\nfunction isValidQuaternion(q) {\n return !!(q.isQuaternion && !isNaN(q.x) && !isNaN(q.y) && !isNaN(q.z) && !isNaN(q.w) && q.x !== null && q.y !== null && q.z !== null && q.w !== null);\n}\nvar throttle = function () {\n var previousLogTime = 0;\n return function throttle(f, milliseconds) {\n var now = Date.now();\n if (now - previousLogTime > milliseconds) {\n previousLogTime = now;\n f();\n }\n };\n}();\nfunction warnOnInvalidNetworkUpdate() {\n NAF.log.warn(\"Received invalid network update.\");\n}\nAFRAME.registerSystem(\"networked\", {\n init: function init() {\n // An array of \"networked\" component instances.\n this.components = [];\n this.nextSyncTime = 0;\n },\n register: function register(component) {\n this.components.push(component);\n },\n deregister: function deregister(component) {\n var idx = this.components.indexOf(component);\n if (idx > -1) {\n this.components.splice(idx, 1);\n }\n },\n tick: function () {\n return function () {\n if (!NAF.connection.adapter) return;\n if (this.el.clock.elapsedTime < this.nextSyncTime) return;\n\n // \"d\" is an array of entity datas per entity in this.components.\n var data = {\n d: []\n };\n for (var i = 0, l = this.components.length; i < l; i++) {\n var c = this.components[i];\n if (!c.isMine()) continue;\n if (!c.el.parentElement) {\n NAF.log.error(\"entity registered with system despite being removed\");\n //TODO: Find out why tick is still being called\n return;\n }\n var syncData = this.components[i].syncDirty();\n if (!syncData) continue;\n data.d.push(syncData);\n }\n if (data.d.length > 0) {\n NAF.connection.broadcastData('um', data);\n }\n this.updateNextSyncTime();\n };\n }(),\n updateNextSyncTime: function updateNextSyncTime() {\n this.nextSyncTime = this.el.clock.elapsedTime + 1 / NAF.options.updateRate;\n }\n});\nAFRAME.registerComponent('networked', {\n schema: {\n template: {\n \"default\": ''\n },\n attachTemplateToLocal: {\n \"default\": true\n },\n persistent: {\n \"default\": false\n },\n networkId: {\n \"default\": ''\n },\n owner: {\n \"default\": ''\n },\n creator: {\n \"default\": ''\n }\n },\n init: function init() {\n this.OWNERSHIP_GAINED = 'ownership-gained';\n this.OWNERSHIP_CHANGED = 'ownership-changed';\n this.OWNERSHIP_LOST = 'ownership-lost';\n this.onOwnershipGainedEvent = {\n el: this.el\n };\n this.onOwnershipChangedEvent = {\n el: this.el\n };\n this.onOwnershipLostEvent = {\n el: this.el\n };\n this.conversionEuler = new THREE.Euler();\n this.conversionEuler.order = \"YXZ\";\n this.bufferInfos = [];\n this.bufferPosition = new THREE.Vector3();\n this.bufferQuaternion = new THREE.Quaternion();\n this.bufferScale = new THREE.Vector3();\n var wasCreatedByNetwork = this.wasCreatedByNetwork();\n this.onConnected = this.onConnected.bind(this);\n this.syncData = {};\n this.componentSchemas = NAF.schemas.getComponents(this.data.template);\n this.cachedElements = new Array(this.componentSchemas.length);\n this.networkUpdatePredicates = this.componentSchemas.map(function (x) {\n return x.requiresNetworkUpdate && x.requiresNetworkUpdate() || defaultRequiresUpdate();\n });\n\n // Fill cachedElements array with null elements\n this.invalidateCachedElements();\n this.initNetworkParent();\n var networkId;\n if (this.data.networkId === '') {\n networkId = NAF.utils.createNetworkId();\n this.el.setAttribute(this.name, {\n networkId: networkId\n });\n } else {\n networkId = this.data.networkId;\n }\n if (!this.el.id) {\n this.el.setAttribute('id', 'naf-' + networkId);\n }\n if (wasCreatedByNetwork) {\n this.firstUpdate();\n } else {\n if (this.data.attachTemplateToLocal) {\n this.attachTemplateToLocal();\n }\n this.registerEntity(this.data.networkId);\n }\n this.lastOwnerTime = -1;\n if (NAF.clientId) {\n this.onConnected();\n } else {\n document.body.addEventListener('connected', this.onConnected, false);\n }\n document.body.dispatchEvent(this.entityCreatedEvent());\n this.el.dispatchEvent(new CustomEvent('instantiated', {\n detail: {\n el: this.el\n }\n }));\n this.el.sceneEl.systems.networked.register(this);\n },\n attachTemplateToLocal: function attachTemplateToLocal() {\n var template = NAF.schemas.getCachedTemplate(this.data.template);\n var elAttrs = template.attributes;\n\n // Merge root element attributes with this entity\n for (var attrIdx = 0; attrIdx < elAttrs.length; attrIdx++) {\n this.el.setAttribute(elAttrs[attrIdx].name, elAttrs[attrIdx].value);\n }\n\n // Append all child elements\n while (template.firstElementChild) {\n this.el.appendChild(template.firstElementChild);\n }\n },\n takeOwnership: function takeOwnership() {\n var owner = this.data.owner;\n var lastOwnerTime = this.lastOwnerTime;\n var now = NAF.connection.getServerTime();\n if (owner && !this.isMine() && lastOwnerTime < now) {\n this.lastOwnerTime = now;\n this.removeLerp();\n this.el.setAttribute('networked', {\n owner: NAF.clientId\n });\n this.syncAll();\n this.onOwnershipGainedEvent.oldOwner = owner;\n this.el.emit(this.OWNERSHIP_GAINED, this.onOwnershipGainedEvent);\n this.onOwnershipChangedEvent.oldOwner = owner;\n this.onOwnershipChangedEvent.newOwner = NAF.clientId;\n this.el.emit(this.OWNERSHIP_CHANGED, this.onOwnershipChangedEvent);\n return true;\n }\n return false;\n },\n wasCreatedByNetwork: function wasCreatedByNetwork() {\n return !!this.el.firstUpdateData;\n },\n initNetworkParent: function initNetworkParent() {\n var parentEl = this.el.parentElement;\n if (parentEl['components'] && parentEl.components['networked']) {\n this.parent = parentEl;\n } else {\n this.parent = null;\n }\n },\n registerEntity: function registerEntity(networkId) {\n NAF.entities.registerEntity(networkId, this.el);\n },\n applyPersistentFirstSync: function applyPersistentFirstSync() {\n var networkId = this.data.networkId;\n var persistentFirstSync = NAF.entities.getPersistentFirstSync(networkId);\n if (persistentFirstSync) {\n this.networkUpdate(persistentFirstSync);\n NAF.entities.forgetPersistentFirstSync(networkId);\n }\n },\n firstUpdate: function firstUpdate() {\n var entityData = this.el.firstUpdateData;\n this.networkUpdate(entityData);\n },\n onConnected: function onConnected() {\n var _this = this;\n if (this.data.owner === '') {\n this.lastOwnerTime = NAF.connection.getServerTime();\n this.el.setAttribute(this.name, {\n owner: NAF.clientId,\n creator: NAF.clientId\n });\n setTimeout(function () {\n //a-primitives attach their components on the next frame; wait for components to be attached before calling syncAll\n if (!_this.el.parentNode) {\n NAF.log.warn(\"Networked element was removed before ever getting the chance to syncAll\");\n return;\n }\n _this.syncAll(undefined, true);\n }, 0);\n }\n document.body.removeEventListener('connected', this.onConnected, false);\n },\n isMine: function isMine() {\n return this.data.owner === NAF.clientId;\n },\n createdByMe: function createdByMe() {\n return this.data.creator === NAF.clientId;\n },\n tick: function tick(time, dt) {\n if (!this.isMine() && NAF.options.useLerp) {\n for (var i = 0; i < this.bufferInfos.length; i++) {\n var bufferInfo = this.bufferInfos[i];\n var buffer = bufferInfo.buffer;\n var object3D = bufferInfo.object3D;\n var componentNames = bufferInfo.componentNames;\n buffer.update(dt);\n if (componentNames.includes(\"position\")) {\n var position = buffer.getPosition();\n if (isValidVector3(position)) {\n object3D.position.copy(position);\n } else {\n throttle(warnOnInvalidNetworkUpdate, 5000);\n }\n }\n if (componentNames.includes(\"rotation\")) {\n var quaternion = buffer.getQuaternion();\n if (isValidQuaternion(quaternion)) {\n object3D.quaternion.copy(quaternion);\n } else {\n throttle(warnOnInvalidNetworkUpdate, 5000);\n }\n }\n if (componentNames.includes(\"scale\")) {\n var scale = buffer.getScale();\n if (isValidVector3(scale)) {\n object3D.scale.copy(scale);\n } else {\n throttle(warnOnInvalidNetworkUpdate, 5000);\n }\n }\n }\n }\n },\n /* Sending updates */\n\n syncAll: function syncAll(targetClientId, isFirstSync) {\n if (!this.canSync()) {\n return;\n }\n var components = this.gatherComponentsData(true);\n var syncData = this.createSyncData(components, isFirstSync);\n if (targetClientId) {\n NAF.connection.sendDataGuaranteed(targetClientId, 'u', syncData);\n } else {\n NAF.connection.broadcastDataGuaranteed('u', syncData);\n }\n },\n syncDirty: function syncDirty() {\n if (!this.canSync()) {\n return;\n }\n var components = this.gatherComponentsData(false);\n if (components === null) {\n return;\n }\n return this.createSyncData(components);\n },\n getCachedElement: function getCachedElement(componentSchemaIndex) {\n var cachedElement = this.cachedElements[componentSchemaIndex];\n if (cachedElement) {\n return cachedElement;\n }\n var componentSchema = this.componentSchemas[componentSchemaIndex];\n if (componentSchema.selector) {\n return this.cachedElements[componentSchemaIndex] = this.el.querySelector(componentSchema.selector);\n } else {\n return this.cachedElements[componentSchemaIndex] = this.el;\n }\n },\n invalidateCachedElements: function invalidateCachedElements() {\n for (var i = 0; i < this.cachedElements.length; i++) {\n this.cachedElements[i] = null;\n }\n },\n gatherComponentsData: function gatherComponentsData(fullSync) {\n var componentsData = null;\n for (var i = 0; i < this.componentSchemas.length; i++) {\n var componentSchema = this.componentSchemas[i];\n var componentElement = this.getCachedElement(i);\n if (!componentElement) {\n if (fullSync) {\n componentsData = componentsData || {};\n componentsData[i] = null;\n }\n continue;\n }\n var componentName = componentSchema.component ? componentSchema.component : componentSchema;\n var componentData = componentElement.getAttribute(componentName);\n if (componentData === null) {\n if (fullSync) {\n componentsData = componentsData || {};\n componentsData[i] = null;\n }\n continue;\n }\n var syncedComponentData = componentSchema.property ? componentData[componentSchema.property] : componentData;\n\n // Use networkUpdatePredicate to check if the component needs to be updated.\n // Call networkUpdatePredicate first so that it can update any cached values in the event of a fullSync.\n if (this.networkUpdatePredicates[i](syncedComponentData) || fullSync) {\n componentsData = componentsData || {};\n componentsData[i] = syncedComponentData;\n }\n }\n return componentsData;\n },\n createSyncData: function createSyncData(components, isFirstSync) {\n var syncData = this.syncData,\n data = this.data;\n syncData.networkId = data.networkId;\n syncData.owner = data.owner;\n syncData.creator = data.creator;\n syncData.lastOwnerTime = this.lastOwnerTime;\n syncData.template = data.template;\n syncData.persistent = data.persistent;\n syncData.parent = this.getParentId();\n syncData.components = components;\n syncData.isFirstSync = !!isFirstSync;\n return syncData;\n },\n canSync: function canSync() {\n // This client will send a sync if:\n //\n // - The client is the owner\n // - The client is the creator, and the owner is not in the room.\n //\n // The reason for the latter case is so the object will still be\n // properly instantiated if the owner leaves. (Since the object lifetime\n // is tied to the creator.)\n if (this.data.owner && this.isMine()) return true;\n if (!this.createdByMe()) return false;\n var clients = NAF.connection.getConnectedClients();\n for (var clientId in clients) {\n if (clientId === this.data.owner) return false;\n }\n return true;\n },\n getParentId: function getParentId() {\n this.initNetworkParent(); // TODO fix calling this each network tick\n if (!this.parent) {\n return null;\n }\n var netComp = this.parent.getAttribute('networked');\n return netComp.networkId;\n },\n /* Receiving updates */\n\n networkUpdate: function networkUpdate(entityData) {\n // Avoid updating components if the entity data received did not come from the current owner.\n if (entityData.lastOwnerTime < this.lastOwnerTime || this.lastOwnerTime === entityData.lastOwnerTime && this.data.owner > entityData.owner) {\n return;\n }\n\n // Hack to solve this bug: https://github.com/networked-aframe/networked-aframe/issues/200\n if (this.data === undefined) {\n return;\n }\n if (this.data.owner !== entityData.owner) {\n var wasMine = this.isMine();\n this.lastOwnerTime = entityData.lastOwnerTime;\n var oldOwner = this.data.owner;\n var newOwner = entityData.owner;\n this.el.setAttribute('networked', {\n owner: entityData.owner\n });\n if (wasMine) {\n this.onOwnershipLostEvent.newOwner = newOwner;\n this.el.emit(this.OWNERSHIP_LOST, this.onOwnershipLostEvent);\n }\n this.onOwnershipChangedEvent.oldOwner = oldOwner;\n this.onOwnershipChangedEvent.newOwner = newOwner;\n this.el.emit(this.OWNERSHIP_CHANGED, this.onOwnershipChangedEvent);\n }\n if (this.data.persistent !== entityData.persistent) {\n this.el.setAttribute('networked', {\n persistent: entityData.persistent\n });\n }\n this.updateNetworkedComponents(entityData.components);\n },\n updateNetworkedComponents: function updateNetworkedComponents(components) {\n for (var componentIndex = 0, l = this.componentSchemas.length; componentIndex < l; componentIndex++) {\n var componentData = components[componentIndex];\n var componentSchema = this.componentSchemas[componentIndex];\n var componentElement = this.getCachedElement(componentIndex);\n if (componentElement === null || componentData === null || componentData === undefined) {\n continue;\n }\n if (componentSchema.component) {\n if (componentSchema.property) {\n this.updateNetworkedComponent(componentElement, componentSchema.component, componentSchema.property, componentData);\n } else {\n this.updateNetworkedComponent(componentElement, componentSchema.component, componentData);\n }\n } else {\n this.updateNetworkedComponent(componentElement, componentSchema, componentData);\n }\n }\n },\n updateNetworkedComponent: function updateNetworkedComponent(el, componentName, data, value) {\n if (!NAF.options.useLerp || !OBJECT3D_COMPONENTS.includes(componentName)) {\n if (value === undefined) {\n el.setAttribute(componentName, data);\n } else {\n el.setAttribute(componentName, data, value);\n }\n return;\n }\n var bufferInfo;\n for (var i = 0, l = this.bufferInfos.length; i < l; i++) {\n var info = this.bufferInfos[i];\n if (info.object3D === el.object3D) {\n bufferInfo = info;\n break;\n }\n }\n if (!bufferInfo) {\n bufferInfo = {\n buffer: new InterpolationBuffer(MODE_LERP, 0.1),\n object3D: el.object3D,\n componentNames: [componentName]\n };\n this.bufferInfos.push(bufferInfo);\n } else {\n var componentNames = bufferInfo.componentNames;\n if (!componentNames.includes(componentName)) {\n componentNames.push(componentName);\n }\n }\n var buffer = bufferInfo.buffer;\n switch (componentName) {\n case 'position':\n buffer.setPosition(this.bufferPosition.set(data.x, data.y, data.z));\n return;\n case 'rotation':\n this.conversionEuler.set(DEG2RAD * data.x, DEG2RAD * data.y, DEG2RAD * data.z);\n buffer.setQuaternion(this.bufferQuaternion.setFromEuler(this.conversionEuler));\n return;\n case 'scale':\n buffer.setScale(this.bufferScale.set(data.x, data.y, data.z));\n return;\n }\n NAF.log.error('Could not set value in interpolation buffer.', el, componentName, data, bufferInfo);\n },\n removeLerp: function removeLerp() {\n this.bufferInfos = [];\n },\n remove: function remove() {\n document.body.removeEventListener('connected', this.onConnected, false);\n if (this.isMine() && NAF.connection.isConnected()) {\n var syncData = {\n networkId: this.data.networkId\n };\n if (NAF.entities.hasEntity(this.data.networkId)) {\n NAF.connection.broadcastDataGuaranteed('r', syncData);\n } else {\n // The entity may already have been removed if the creator (different of the current owner) left the room.\n // Don't log an error in this case.\n if (!(this.data.creator && NAF.connection.activeDataChannels[this.data.creator] === false)) {\n NAF.log.error(\"Removing networked entity that is not in entities array.\");\n }\n }\n }\n NAF.entities.forgetEntity(this.data.networkId);\n document.body.dispatchEvent(this.entityRemovedEvent(this.data.networkId));\n this.el.sceneEl.systems.networked.deregister(this);\n },\n entityCreatedEvent: function entityCreatedEvent() {\n return new CustomEvent('entityCreated', {\n detail: {\n el: this.el\n }\n });\n },\n entityRemovedEvent: function entityRemovedEvent(networkId) {\n return new CustomEvent('entityRemoved', {\n detail: {\n networkId: networkId\n }\n });\n }\n});\n\n//# sourceURL=webpack://networked-aframe/./src/components/networked.js?"); /***/ }), diff --git a/dist/networked-aframe.min.js b/dist/networked-aframe.min.js index 856c2f97..823f2dbb 100644 --- a/dist/networked-aframe.min.js +++ b/dist/networked-aframe.min.js @@ -1 +1 @@ -(()=>{var t={934:t=>{"use strict";var e=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:0,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.state=0,this.buffer=[],this.bufferTime=1e3*n,this.time=0,this.mode=e,this.originFrame=i(),this.position=new THREE.Vector3,this.quaternion=new THREE.Quaternion,this.scale=new THREE.Vector3(1,1,1)}return e(t,[{key:"hermite",value:function(t,e,n,i,o,r){var s=e*e,a=e*e*e,c=2*a-3*s+1,u=-2*a+3*s,l=a-2*s+e,h=a-s;t.copy(n.multiplyScalar(c)),t.add(i.multiplyScalar(u)),t.add(o.multiplyScalar(l)),t.add(r.multiplyScalar(h))}},{key:"lerp",value:function(t,e,n,i){t.lerpVectors(e,n,i)}},{key:"slerp",value:function(t,e,n,i){t.slerpQuaternions(e,n,i)}},{key:"updateOriginFrameToBufferTail",value:function(){var t;t=this.originFrame,n.push(t),this.originFrame=this.buffer.shift()}},{key:"appendBuffer",value:function(t,e,n,o){var r=this.buffer.length>0?this.buffer[this.buffer.length-1]:null;if(r&&r.time===this.time)t&&r.position.copy(t),e&&r.velocity.copy(e),n&&r.quaternion.copy(n),o&&r.scale.copy(o);else{var s=r||this.originFrame,a=i();a.position.copy(t||s.position),a.velocity.copy(e||s.velocity),a.quaternion.copy(n||s.quaternion),a.scale.copy(o||s.scale),a.time=this.time,this.buffer.push(a)}}},{key:"setTarget",value:function(t,e,n,i){this.appendBuffer(t,e,n,i)}},{key:"setPosition",value:function(t,e){this.appendBuffer(t,e,null,null)}},{key:"setQuaternion",value:function(t){this.appendBuffer(null,null,t,null)}},{key:"setScale",value:function(t){this.appendBuffer(null,null,null,t)}},{key:"update",value:function(t){if(0===this.state&&this.buffer.length>0&&(this.updateOriginFrameToBufferTail(),this.position.copy(this.originFrame.position),this.quaternion.copy(this.originFrame.quaternion),this.scale.copy(this.originFrame.scale),this.state=1),1===this.state&&this.buffer.length>0&&this.time>this.bufferTime&&(this.state=2),2===this.state){for(var e=this.time-this.bufferTime;this.buffer.length>0&&e>this.buffer[0].time;)this.buffer.length>1?this.updateOriginFrameToBufferTail():(this.originFrame.position.copy(this.buffer[0].position),this.originFrame.velocity.copy(this.buffer[0].velocity),this.originFrame.quaternion.copy(this.buffer[0].quaternion),this.originFrame.scale.copy(this.buffer[0].scale),this.originFrame.time=this.buffer[0].time,this.buffer[0].time=this.time+t);if(this.buffer.length>0&&this.buffer[0].time>0){var n=this.buffer[0],i=n.time-this.originFrame.time,o=(e-this.originFrame.time)/i;0===this.mode?this.lerp(this.position,this.originFrame.position,n.position,o):1===this.mode&&this.hermite(this.position,o,this.originFrame.position,n.position,this.originFrame.velocity.multiplyScalar(i),n.velocity.multiplyScalar(i)),this.slerp(this.quaternion,this.originFrame.quaternion,n.quaternion,o),this.lerp(this.scale,this.originFrame.scale,n.scale,o)}}0!==this.state&&(this.time+=t)}},{key:"getPosition",value:function(){return this.position}},{key:"getQuaternion",value:function(){return this.quaternion}},{key:"getScale",value:function(){return this.scale}}]),t}();t.exports=o},737:t=>{function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},e(t)}function n(t,e){for(var n=0;n{"use strict";function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},e(t)}var n=Array.isArray,i=Object.keys,o=Object.prototype.hasOwnProperty;t.exports=function t(r,s){if(r===s)return!0;if(r&&s&&"object"==e(r)&&"object"==e(s)){var a,c,u,l=n(r),h=n(s);if(l&&h){if((c=r.length)!=s.length)return!1;for(a=c;0!=a--;)if(!t(r[a],s[a]))return!1;return!0}if(l!=h)return!1;var d=r instanceof Date,f=s instanceof Date;if(d!=f)return!1;if(d&&f)return r.getTime()==s.getTime();var p=r instanceof RegExp,m=s instanceof RegExp;if(p!=m)return!1;if(p&&m)return r.toString()==s.toString();var v=i(r);if((c=v.length)!==i(s).length)return!1;for(a=c;0!=a--;)if(!o.call(s,v[a]))return!1;for(a=c;0!=a--;)if(!t(r[u=v[a]],s[u]))return!1;return!0}return r!=r&&s!=s}},199:(t,e,n)=>{var i=n(172),o=n(347),r=n(759),s=n(758),a=n(815),c=n(192),u=n(724),l={app:"",room:"",clientId:""};l.options=i,l.utils=o,l.log=new r,l.schemas=new s,l.version="0.12.1",l.adapters=new u;var h=new a,d=new c(h);l.connection=d,l.entities=h,t.exports=window.NAF=l},564:t=>{function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},e(t)}function n(t,e){for(var n=0;n{function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},e(t)}function n(t,e){for(var n=0;n{function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},e(t)}function n(t,e){for(var n=0;n3&&void 0!==arguments[3]&&arguments[3],o=arguments.length>4&&void 0!==arguments[4]&&arguments[4];NAF.app=e,NAF.room=n,this.adapter.setServerUrl(t),this.adapter.setApp(e),this.adapter.setRoom(n);var r={audio:i,video:o,datachannel:!0};return this.adapter.setWebRtcOptions(r),this.adapter.setServerConnectListeners(this.connectSuccess.bind(this),this.connectFailure.bind(this)),this.adapter.setDataChannelListeners(this.dataChannelOpen.bind(this),this.dataChannelClosed.bind(this),this.receivedData.bind(this)),this.adapter.setRoomOccupantListener(this.occupantsReceived.bind(this)),this.adapter.connect()}},{key:"onConnect",value:function(t){this.onConnectCallback=t,this.isConnected()?t():document.body.addEventListener("connected",t,!1)}},{key:"connectSuccess",value:function(t){NAF.log.write("Networked-Aframe Client ID:",t),NAF.clientId=t;var e=new CustomEvent("connected",{detail:{clientId:t}});document.body.dispatchEvent(e)}},{key:"connectFailure",value:function(t,e){NAF.log.error(t,"failure to connect")}},{key:"occupantsReceived",value:function(t){var e=Object.assign({},this.connectedClients);this.connectedClients=t,this.checkForDisconnectingClients(e,t),this.checkForConnectingClients(t)}},{key:"checkForDisconnectingClients",value:function(t,e){for(var n in t)e[n]||(NAF.log.write("Closing stream to",n),this.adapter.closeStreamConnection(n))}},{key:"checkForConnectingClients",value:function(t){for(var e in t)this.isNewClient(e)&&this.adapter.shouldStartConnectionTo(t[e])&&(NAF.log.write("Opening datachannel to",e),this.adapter.startStreamConnection(e))}},{key:"getConnectedClients",value:function(){return this.connectedClients}},{key:"isConnected",value:function(){return!!NAF.clientId}},{key:"isMineAndConnected",value:function(t){return this.isConnected()&&NAF.clientId===t}},{key:"isNewClient",value:function(t){return!this.isConnectedTo(t)}},{key:"isConnectedTo",value:function(t){return this.adapter.getConnectStatus(t)===NAF.adapters.IS_CONNECTED}},{key:"dataChannelOpen",value:function(t){NAF.log.write("Opened data channel from "+t),this.activeDataChannels[t]=!0,this.entities.completeSync(t,!0);var e=new CustomEvent("clientConnected",{detail:{clientId:t}});document.body.dispatchEvent(e)}},{key:"dataChannelClosed",value:function(t){NAF.log.write("Closed data channel from "+t),this.activeDataChannels[t]=!1,this.entities.removeEntitiesOfClient(t);var e=new CustomEvent("clientDisconnected",{detail:{clientId:t}});document.body.dispatchEvent(e)}},{key:"hasActiveDataChannel",value:function(t){return!!this.activeDataChannels[t]}},{key:"broadcastData",value:function(t,e){this.adapter.broadcastData(t,e)}},{key:"broadcastDataGuaranteed",value:function(t,e){this.adapter.broadcastDataGuaranteed(t,e)}},{key:"sendData",value:function(t,e,n,i){this.hasActiveDataChannel(t)&&(i?this.adapter.sendDataGuaranteed(t,e,n):this.adapter.sendData(t,e,n))}},{key:"sendDataGuaranteed",value:function(t,e,n){this.sendData(t,e,n,!0)}},{key:"subscribeToDataChannel",value:function(t,e){this.isReservedDataType(t)?NAF.log.error("NetworkConnection@subscribeToDataChannel: "+t+" is a reserved dataType. Choose another"):this.dataChannelSubs[t]=e}},{key:"unsubscribeToDataChannel",value:function(t){this.isReservedDataType(t)?NAF.log.error("NetworkConnection@unsubscribeToDataChannel: "+t+" is a reserved dataType. Choose another"):delete this.dataChannelSubs[t]}},{key:"isReservedDataType",value:function(t){return"u"==t||"r"==t}},{key:"receivedData",value:function(t,e,n,i){this.dataChannelSubs[e]?this.dataChannelSubs[e](t,e,n,i):NAF.log.write("NetworkConnection@receivedData: "+e+" has not been subscribed to yet. Call subscribeToDataChannel()")}},{key:"getServerTime",value:function(){return this.adapter.getServerTime()}},{key:"disconnect",value:function(){this.entities.removeRemoteEntities(),this.adapter&&this.adapter.disconnect(),NAF.app="",NAF.room="",NAF.clientId="",this.connectedClients={},this.activeDataChannels={},this.adapter=null,this.setupDefaultDataSubscriptions(),document.body.removeEventListener("connected",this.onConnectCallback)}}],i&&n(e.prototype,i),Object.defineProperty(e,"prototype",{writable:!1}),t}();t.exports=o},815:(t,e,n)=>{function i(t){return i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i(t)}function o(t,e){for(var n=0;n{function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},e(t)}function n(t,e){for(var n=0;n is defined."));if(!this.validateTemplate(t,e))return;this.templateCache[t.template]=document.importNode(e.content,!0)}else NAF.log.error("Schema not valid: ",t),NAF.log.error("See https://github.com/networked-aframe/networked-aframe#syncing-custom-components")}},{key:"getCachedTemplate",value:function(t){return this.templateIsCached(t)||(this.templateExistsInScene(t)?this.add(this.createDefaultSchema(t)):NAF.log.error("Template el for ".concat(t," is not in the scene, add the template to and register with NAF.schemas.add."))),this.templateCache[t].firstElementChild.cloneNode(!0)}},{key:"templateIsCached",value:function(t){return!!this.templateCache[t]}},{key:"getComponents",value:function(t){var e=["position","rotation"];return this.hasTemplate(t)&&(e=this.schemaDict[t].components),e}},{key:"hasTemplate",value:function(t){return!!this.schemaDict[t]}},{key:"templateExistsInScene",value:function(t){var e=document.querySelector(t);return e&&this.isTemplateTag(e)}},{key:"validateSchema",value:function(t){return!(!t.template||!t.components)}},{key:"validateTemplate",value:function(t,e){return this.isTemplateTag(e)?!!this.templateHasOneOrZeroChildren(e)||(NAF.log.error("Template for ".concat(t.template," has more than one child. Templates must have one direct child element, no more. Template found:"),e),!1):(NAF.log.error("Template for ".concat(t.template," is not a