From c9655a37c34659c47fb0fdd7e7961950ab6667ca Mon Sep 17 00:00:00 2001 From: Kevin Lee <kevin@infinite-lee.com> Date: Fri, 26 Jan 2018 17:24:28 -0800 Subject: [PATCH] Adding "network-counter" component- keeps track of networked entities and limits how many you can have, and how long they can live for. --- src/components/networked-counter.js | 127 ++++++++++++++++++++++++++ src/components/remote-dynamic-body.js | 38 +++++--- src/room.js | 1 + templates/room.hbs | 9 +- 4 files changed, 160 insertions(+), 15 deletions(-) create mode 100644 src/components/networked-counter.js diff --git a/src/components/networked-counter.js b/src/components/networked-counter.js new file mode 100644 index 000000000..7b31fdb31 --- /dev/null +++ b/src/components/networked-counter.js @@ -0,0 +1,127 @@ +AFRAME.registerComponent("networked-counter", { + schema: { + max: { default: 3 }, + ttl: { default: 120 } + }, + + init: function() { + this.count = 0; + this.queue = {}; + this.timeouts = {}; + }, + + getCount: function() { + return queue.length; + }, + + getMax: function() { + return this.data.max; + }, + + getTtl: function() { + return this.data.ttl; + }, + + register: function(networkedEl) { + if (this.data.max <= 0) { + return; + } + + const id = this._getNetworkId(networkedEl); + if (this.queue.hasOwnProperty(id)) { + return; + } + + const now = Date.now(); + const onGrabHandler = this._onGrabbed.bind(this, id); + const onReleaseHandler = this._onReleased.bind(this, id); + this.queue[id] = { + ts: now, + el: networkedEl, + onGrabHandler: onGrabHandler, + onReleaseHandler: onReleaseHandler + }; + + networkedEl.addEventListener("grab-start", onGrabHandler); + networkedEl.addEventListener("grab-end", onReleaseHandler); + + this.count++; + + if (!this._isCurrentlyGrabbed(id)) { + this._addTimeout(id); + } + + this._removeOldest(); + }, + + deregister: function(networkedEl) { + const id = this._getNetworkId(networkedEl); + if (this.queue.hasOwnProperty(id)) { + const item = this.queue[id]; + networkedEl.removeEventListener("grab-start", item.onGrabHandler); + networkedEl.removeEventListener("grab-end", item.onReleaseHandler); + + delete this.queue[id]; + + this._removeTimeout(id); + delete this.timeouts[id]; + + this.count--; + } + }, + + _onGrabbed: function(id, e) { + this._removeTimeout(id); + }, + + _onReleased: function(id, e) { + this._removeTimeout(id); + this._addTimeout(id); + }, + + _removeOldest: function() { + if (this.count > this.data.max) { + let oldest = null, ts = Number.MAX_VALUE; + Object.keys(this.queue).forEach(function(id) { + const expiration = this.queue[id].ts + this.data.ttl * 1000; + if (this.queue[id].ts < ts && !this._isCurrentlyGrabbed(id)) { + oldest = this.queue[id]; + ts = this.queue[id].ts; + } + }, this); + if (ts > 0) { + this.deregister(oldest.el); + this._destroy(oldest.el); + } + } + }, + + _isCurrentlyGrabbed: function(id) { + const networkedEl = this.queue[id].el; + return networkedEl.is("grabbed"); + }, + + _addTimeout: function(id) { + const timeout = this.data.ttl * 1000; + this.timeouts[id] = setTimeout(() => { + + const el = this.queue[id].el; + this.deregister(el); + this._destroy(el); + }, timeout); + }, + + _removeTimeout: function(id) { + if (this.timeouts.hasOwnProperty(id)) { + clearTimeout(this.timeouts[id]); + } + }, + + _destroy: function(networkedEl) { + networkedEl.parentNode.removeChild(networkedEl); + }, + + _getNetworkId: function(networkedEl) { + return networkedEl.components.networked.data.networkId; + } +}); diff --git a/src/components/remote-dynamic-body.js b/src/components/remote-dynamic-body.js index de7482606..09ebc617a 100644 --- a/src/components/remote-dynamic-body.js +++ b/src/components/remote-dynamic-body.js @@ -1,36 +1,48 @@ AFRAME.registerComponent("remote-dynamic-body", { + schema: { + mass: { default: 1 }, + counter: { type: "selector" } + }, init: function() { + this.counter = this.data.counter.components["networked-counter"]; + this.timer = 0; + this.networkedEl = NAF.utils.getNetworkedEntity(this.el); if (!this._isMine()) { this.networkedEl.setAttribute("dynamic-body", "mass: 0;"); this.networkedEl.setAttribute("grabbable", ""); this.networkedEl.setAttribute("stretchable", ""); - this.el.setAttribute("color", "white"); + } else { + this.counter.register(this.networkedEl); + this.timer = Date.now(); } this.wasMine = this._isMine(); - const self = this; - - this.networkedEl.addEventListener('grab-start', function(e){ - if (!self._isMine()) { - if(self.networkedEl.components.networked.takeOwnership()) { - self.networkedEl.components["dynamic-body"].updateMass(1); - self.el.setAttribute("color", "green"); - self.wasMine = true; - } - } + this.networkedEl.addEventListener("grab-start", e => { + this._onGrabStart(e); }); }, tick: function(t) { - if(this.wasMine && !this._isMine()) { + if (this.wasMine && !this._isMine()) { this.wasMine = false; this.networkedEl.components["dynamic-body"].updateMass(0); - this.el.setAttribute("color", "white"); this.networkedEl.components["grabbable"].resetGrabber(); + this.counter.deregister(this.networkedEl); + this.timer = 0; + } + }, + + _onGrabStart: function(e) { + if (!this._isMine()) { + if (this.networkedEl.components.networked.takeOwnership()) { + this.networkedEl.components["dynamic-body"].updateMass(this.data.mass); + this.wasMine = true; + this.counter.register(this.networkedEl); + } } }, diff --git a/src/room.js b/src/room.js index c836acaf4..7840ccff6 100644 --- a/src/room.js +++ b/src/room.js @@ -41,6 +41,7 @@ import "./components/skybox"; import "./components/layers"; import "./components/spawn-controller"; import "./components/remote-dynamic-body"; +import "./components/networked-counter"; import "./systems/personal-space-bubble"; import { promptForName, getCookie, parseJwt } from "./utils/identity"; diff --git a/templates/room.hbs b/templates/room.hbs index 342cb1f82..97b6b1cb6 100644 --- a/templates/room.hbs +++ b/templates/room.hbs @@ -117,12 +117,17 @@ scale="6 6 6" ></a-entity> </script> - <script id="physics-cube" type="text/html"> - <a-box class="box" remote-dynamic-body physics-collider scale="0.25 0.25 0.25" material="color: green"></a-box> + <a-box class="box" remote-dynamic-body="counter: #counter" physics-collider scale="0.25 0.25 0.25" material="color: green"></a-box> </script> </a-assets> + <a-entity + id="counter" + networked-counter="max: 3; ttl: 120" + > + </a-entity> + <!-- Player Rig --> <a-entity id="player-rig" -- GitLab