@needle-tools/engine 2.28.0-pre → 2.30.0-pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/needle-engine.d.ts +232 -139
  3. package/dist/needle-engine.js +349 -345
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +24 -20
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/engine.d.ts +1 -0
  8. package/lib/engine/engine_input.d.ts +13 -1
  9. package/lib/engine/engine_input.js +47 -16
  10. package/lib/engine/engine_input.js.map +1 -1
  11. package/lib/engine/engine_physics.d.ts +1 -0
  12. package/lib/engine/engine_physics.js +2 -1
  13. package/lib/engine/engine_physics.js.map +1 -1
  14. package/lib/engine/engine_playerview.d.ts +26 -0
  15. package/lib/engine/engine_playerview.js +65 -0
  16. package/lib/engine/engine_playerview.js.map +1 -0
  17. package/lib/engine/engine_serialization.d.ts +1 -0
  18. package/lib/engine/engine_serialization.js +1 -0
  19. package/lib/engine/engine_serialization.js.map +1 -1
  20. package/lib/engine/engine_serialization_core.js +5 -0
  21. package/lib/engine/engine_serialization_core.js.map +1 -1
  22. package/lib/engine/engine_setup.d.ts +8 -0
  23. package/lib/engine/engine_setup.js +23 -0
  24. package/lib/engine/engine_setup.js.map +1 -1
  25. package/lib/engine/engine_utils.d.ts +1 -1
  26. package/lib/engine/engine_utils.js +25 -8
  27. package/lib/engine/engine_utils.js.map +1 -1
  28. package/lib/engine/extensions/NEEDLE_deferred_texture.d.ts +1 -1
  29. package/lib/engine/extensions/NEEDLE_deferred_texture.js +26 -14
  30. package/lib/engine/extensions/NEEDLE_deferred_texture.js.map +1 -1
  31. package/lib/engine/extensions/NEEDLE_lighting_settings.js +6 -2
  32. package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
  33. package/lib/engine/extensions/extension_utils.js +24 -13
  34. package/lib/engine/extensions/extension_utils.js.map +1 -1
  35. package/lib/engine/extensions/extensions.js +3 -1
  36. package/lib/engine/extensions/extensions.js.map +1 -1
  37. package/lib/engine-components/Camera.js +7 -0
  38. package/lib/engine-components/Camera.js.map +1 -1
  39. package/lib/engine-components/Component.d.ts +1 -1
  40. package/lib/engine-components/Component.js.map +1 -1
  41. package/lib/engine-components/Light.js +1 -0
  42. package/lib/engine-components/Light.js.map +1 -1
  43. package/lib/engine-components/OrbitControls.js +3 -3
  44. package/lib/engine-components/OrbitControls.js.map +1 -1
  45. package/lib/engine-components/ParticleSystem.d.ts +0 -1
  46. package/lib/engine-components/ParticleSystem.js +24 -27
  47. package/lib/engine-components/ParticleSystem.js.map +1 -1
  48. package/lib/engine-components/PlayerColor.js +1 -2
  49. package/lib/engine-components/PlayerColor.js.map +1 -1
  50. package/lib/engine-components/Renderer.d.ts +1 -0
  51. package/lib/engine-components/Renderer.js +10 -3
  52. package/lib/engine-components/Renderer.js.map +1 -1
  53. package/lib/engine-components/ScreenCapture.d.ts +1 -0
  54. package/lib/engine-components/ScreenCapture.js +265 -1
  55. package/lib/engine-components/ScreenCapture.js.map +1 -1
  56. package/lib/engine-components/SpectatorCamera.d.ts +24 -17
  57. package/lib/engine-components/SpectatorCamera.js +435 -182
  58. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  59. package/lib/engine-components/SyncedCamera.d.ts +8 -4
  60. package/lib/engine-components/SyncedCamera.js +15 -18
  61. package/lib/engine-components/SyncedCamera.js.map +1 -1
  62. package/lib/engine-components/SyncedRoom.js +2 -0
  63. package/lib/engine-components/SyncedRoom.js.map +1 -1
  64. package/lib/engine-components/VideoPlayer.d.ts +10 -1
  65. package/lib/engine-components/VideoPlayer.js +64 -15
  66. package/lib/engine-components/VideoPlayer.js.map +1 -1
  67. package/lib/engine-components/Volume.d.ts +4 -0
  68. package/lib/engine-components/Volume.js +44 -3
  69. package/lib/engine-components/Volume.js.map +1 -1
  70. package/lib/engine-components/WebARSessionRoot.d.ts +9 -2
  71. package/lib/engine-components/WebARSessionRoot.js +69 -24
  72. package/lib/engine-components/WebARSessionRoot.js.map +1 -1
  73. package/lib/engine-components/WebXR.d.ts +6 -3
  74. package/lib/engine-components/WebXR.js +43 -7
  75. package/lib/engine-components/WebXR.js.map +1 -1
  76. package/lib/engine-components/WebXRAvatar.d.ts +3 -0
  77. package/lib/engine-components/WebXRAvatar.js +20 -0
  78. package/lib/engine-components/WebXRAvatar.js.map +1 -1
  79. package/lib/engine-components/WebXRController.js +14 -8
  80. package/lib/engine-components/WebXRController.js.map +1 -1
  81. package/lib/engine-components/WebXRSync.js +3 -3
  82. package/lib/engine-components/WebXRSync.js.map +1 -1
  83. package/lib/engine-components/XRFlag.d.ts +2 -1
  84. package/lib/engine-components/XRFlag.js +1 -0
  85. package/lib/engine-components/XRFlag.js.map +1 -1
  86. package/lib/engine-components/ui/CanvasGroup.d.ts +1 -0
  87. package/lib/engine-components/ui/CanvasGroup.js +1 -0
  88. package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
  89. package/lib/engine-components/ui/EventSystem.js +13 -4
  90. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  91. package/lib/engine-components/ui/Graphic.d.ts +1 -0
  92. package/lib/engine-components/ui/Graphic.js +2 -0
  93. package/lib/engine-components/ui/Graphic.js.map +1 -1
  94. package/lib/engine-components/ui/Interfaces.d.ts +2 -0
  95. package/package.json +2 -2
  96. package/src/engine/engine_components.js +16 -0
  97. package/src/engine/engine_input.ts +62 -20
  98. package/src/engine/engine_physics.ts +2 -1
  99. package/src/engine/engine_playerview.ts +80 -0
  100. package/src/engine/engine_serialization.ts +3 -1
  101. package/src/engine/engine_serialization_core.ts +8 -0
  102. package/src/engine/engine_setup.ts +24 -0
  103. package/src/engine/engine_utils.ts +34 -8
  104. package/src/engine/extensions/NEEDLE_deferred_texture.ts +25 -19
  105. package/src/engine/extensions/NEEDLE_lighting_settings.ts +4 -2
  106. package/src/engine/extensions/extension_utils.ts +24 -12
  107. package/src/engine/extensions/extensions.ts +3 -2
  108. package/src/engine-components/Camera.ts +9 -1
  109. package/src/engine-components/Component.ts +1 -1
  110. package/src/engine-components/Light.ts +3 -0
  111. package/src/engine-components/OrbitControls.ts +3 -3
  112. package/src/engine-components/ParticleSystem.ts +25 -26
  113. package/src/engine-components/PlayerColor.ts +1 -1
  114. package/src/engine-components/Renderer.ts +11 -3
  115. package/src/engine-components/ScreenCapture.ts +312 -2
  116. package/src/engine-components/SpectatorCamera.ts +490 -195
  117. package/src/engine-components/SyncedCamera.ts +23 -22
  118. package/src/engine-components/SyncedRoom.ts +1 -0
  119. package/src/engine-components/VideoPlayer.ts +97 -21
  120. package/src/engine-components/Volume.ts +47 -4
  121. package/src/engine-components/WebARSessionRoot.ts +78 -28
  122. package/src/engine-components/WebXR.ts +51 -15
  123. package/src/engine-components/WebXRAvatar.ts +27 -2
  124. package/src/engine-components/WebXRController.ts +21 -15
  125. package/src/engine-components/WebXRSync.ts +3 -3
  126. package/src/engine-components/XRFlag.ts +1 -0
  127. package/src/engine-components/ui/CanvasGroup.ts +2 -0
  128. package/src/engine-components/ui/EventSystem.ts +21 -15
  129. package/src/engine-components/ui/Graphic.ts +3 -0
  130. package/src/engine-components/ui/Interfaces.ts +2 -0
@@ -5,6 +5,7 @@ import { getParam } from "../engine/engine_utils";
5
5
  import { serializeable } from "../engine/engine_serialization_decorator";
6
6
  import { RGBAColor } from "./js-extensions/RGBAColor";
7
7
  import { PerspectiveCamera } from "three";
8
+ import { XRSessionMode } from "../engine/engine_setup";
8
9
 
9
10
  export enum ClearFlags {
10
11
  Skybox = 1,
@@ -192,13 +193,20 @@ export class Camera extends Behaviour {
192
193
  }
193
194
 
194
195
  private environmentIsTransparent(): boolean {
195
- const session = this.context.renderer.xr?.getSession()
196
+ const session = this.context.renderer.xr?.getSession();
196
197
  if (!session) return false;
197
198
  const environmentBlendMode = session.environmentBlendMode;
198
199
  const transparent = environmentBlendMode === 'additive' || environmentBlendMode === 'alpha-blend';
200
+ // workaround for Quest 2 returning opaque when it should be alpha-blend
201
+ // check user agent if this is the Quest browser and return true if so
202
+
203
+ if (environmentBlendMode === "opaque" && navigator.userAgent?.includes("OculusBrowser")) {
204
+ if (this.context.xrSessionMode === XRSessionMode.ImmersiveAR) return true;
205
+ }
199
206
  return transparent;
200
207
  }
201
208
 
209
+
202
210
  private enableSkybox() {
203
211
  if (!this._skybox)
204
212
  this._skybox = new CameraSkybox(this);
@@ -644,7 +644,7 @@ abstract class GameObject extends THREE.Object3D implements THREE.Object3D {
644
644
  return object.getComponentsInChildren(typeName, go, arr);
645
645
  }
646
646
 
647
- public static getComponentInParent<T>(go: GameObject | THREE.Object3D, typeName: Constructor<T>): T | null {
647
+ public static getComponentInParent<T>(go: GameObject | THREE.Object3D | Array<Object3D>, typeName: Constructor<T>): T | null {
648
648
  return object.getComponentInParent(typeName, go);
649
649
  }
650
650
 
@@ -334,7 +334,10 @@ export class Light extends Behaviour {
334
334
  }
335
335
  }
336
336
 
337
+
337
338
  if (this.light !== undefined) {
339
+ this._intensity = this.light.intensity;
340
+
338
341
  if (this.shadows !== LightShadows.None) {
339
342
  this.light.castShadow = true;
340
343
  }
@@ -9,7 +9,6 @@ import { serializeable } from "../engine/engine_serialization_decorator";
9
9
  import { Vector3 } from "three";
10
10
 
11
11
  export class OrbitControls extends Behaviour {
12
-
13
12
  public get controls() {
14
13
  return this._controls;
15
14
  }
@@ -31,7 +30,7 @@ export class OrbitControls extends Behaviour {
31
30
  minZoom: number = 0;
32
31
  maxZoom: number = Infinity;
33
32
  enablePan: boolean = true;
34
- @serializeable(LookAtConstraint)
33
+ @serializeable()
35
34
  lookAtConstraint: LookAtConstraint | null = null;
36
35
  lookAtConstraint01: number = 1;
37
36
  middleClickToFocus: boolean = true;
@@ -103,7 +102,8 @@ export class OrbitControls extends Behaviour {
103
102
  if (this._controls) {
104
103
  const camGo = GameObject.getComponent(this.gameObject, Camera);
105
104
  if (camGo && !this.setFromTargetPosition()) {
106
- console.log("NO TARGET");
105
+ if(this.debugLog)
106
+ console.log("NO TARGET");
107
107
  const forward = new THREE.Vector3(0, 0, -1).applyMatrix4(camGo.cam.matrixWorld);
108
108
  this.setTarget(forward, true);
109
109
  }
@@ -61,7 +61,7 @@ export class ParticleSystem extends Behaviour {
61
61
 
62
62
  awake(): void {
63
63
  this.renderer = GameObject.getComponent(this.gameObject, ParticleSystemRenderer)!;
64
- if (debug)
64
+ // if (debug)
65
65
  console.log(this);
66
66
  }
67
67
 
@@ -108,31 +108,30 @@ export class ParticleSystem extends Behaviour {
108
108
  this.activeCount = this.main.prewarm ? this.main.maxParticles : 0;
109
109
  }
110
110
 
111
- update() {
112
- if (!this.geometry) return;
113
-
114
- const t = this.context.time.deltaTime;
115
- this.emit(t);
116
-
117
- for (let i = 0; i < this.activeCount; i += 1) {
118
- const ps = this.particleStates[i];
119
- if (!ps) continue;
120
- const vx = ps.velocity.x * t;
121
- const vy = ps.velocity.y * t;
122
- const vz = ps.velocity.z * t;
123
- ps.position.x += vx;
124
- ps.position.y += vy;
125
- ps.position.z += vz;
126
- this.updateOverLifetime(i, ps);
127
- this.geometry.attributes.position.setXYZ(i, ps.position.x, ps.position.y, ps.position.z);
128
- this.geometry.attributes.color.setXYZ(i, ps.color.r, ps.color.g, ps.color.b);
129
- }
130
- if (this.geometry) {
131
- this.geometry.attributes.position.needsUpdate = true;
132
- this.geometry.setDrawRange(0, this.activeCount);
133
- }
134
- // console.log(this.activeCount);
135
- }
111
+ // update() {
112
+ // if (!this.geometry) return;
113
+
114
+ // const t = this.context.time.deltaTime;
115
+ // this.emit(t);
116
+
117
+ // for (let i = 0; i < this.activeCount; i += 1) {
118
+ // const ps = this.particleStates[i];
119
+ // if (!ps) continue;
120
+ // const vx = ps.velocity.x * t;
121
+ // const vy = ps.velocity.y * t;
122
+ // const vz = ps.velocity.z * t;
123
+ // ps.position.x += vx;
124
+ // ps.position.y += vy;
125
+ // ps.position.z += vz;
126
+ // this.updateOverLifetime(i, ps);
127
+ // this.geometry.attributes.position.setXYZ(i, ps.position.x, ps.position.y, ps.position.z);
128
+ // this.geometry.attributes.color.setXYZ(i, ps.color.r, ps.color.g, ps.color.b);
129
+ // }
130
+ // if (this.geometry) {
131
+ // this.geometry.attributes.position.needsUpdate = true;
132
+ // this.geometry.setDrawRange(0, this.activeCount);
133
+ // }
134
+ // }
136
135
 
137
136
  emit(deltaTime: number) {
138
137
  const count = this.activeCount;
@@ -68,7 +68,7 @@ export class PlayerColor extends Behaviour {
68
68
  mesh.material = mat;
69
69
  // console.log("CLONE", mat);
70
70
  }
71
- else console.log("DONT CLONE", mat);
71
+ // else console.log("DONT CLONE", mat);
72
72
  mat["color"] = col;
73
73
  }
74
74
 
@@ -13,6 +13,7 @@ const suppressInstancing = getParam("noInstancing");
13
13
  const debugLightmap = getParam("debuglightmaps") ? true : false;
14
14
  const debugInstancing = getParam("debuginstancing");
15
15
  const debugProgressiveLoading = getParam("debugprogressiveload");
16
+ const suppressProgressiveLoading = getParam("noprogressiveload");
16
17
 
17
18
  export class FieldWithDefault {
18
19
  public path: string | null = null;
@@ -172,6 +173,8 @@ export class Renderer extends Behaviour {
172
173
  }
173
174
 
174
175
  awake() {
176
+ this.clearInstancingState();
177
+
175
178
  const type = this.gameObject.type;
176
179
  if (type === "Group") {
177
180
  for (const child of this.gameObject.children) {
@@ -245,6 +248,11 @@ export class Renderer extends Behaviour {
245
248
  private handles: InstanceHandle[] | null | undefined = undefined;
246
249
  private prevLayers: number[] | null | undefined = undefined;
247
250
 
251
+ private clearInstancingState() {
252
+ this._isInstancingEnabled = false;
253
+ this.handles = undefined;
254
+ this.prevLayers = undefined;
255
+ }
248
256
  setInstancingEnabled(enabled: boolean): boolean {
249
257
  if (this._isInstancingEnabled === enabled) return enabled && (this.handles === undefined || this.handles != null && this.handles.length > 0);
250
258
  this._isInstancingEnabled = enabled;
@@ -338,16 +346,16 @@ export class Renderer extends Behaviour {
338
346
  onBeforeRenderThree(_renderer, _scene, _camera, _geometry, material, _group) {
339
347
 
340
348
  // progressive load before rendering so we only load textures for visible materials
341
- if (material._didRequestTextureLOD === undefined) {
349
+ if (!suppressProgressiveLoading && material._didRequestTextureLOD === undefined) {
342
350
  material._didRequestTextureLOD = 0;
343
351
  if (debugProgressiveLoading) {
344
352
  console.log("Load material LOD (with delay)", material.name);
345
353
  setTimeout(() => {
346
- NEEDLE_deferred_texture.assignTextureLOD(this.context, material);
354
+ NEEDLE_deferred_texture.assignTextureLOD(this.context, this.sourceId, material);
347
355
  }, 2000);
348
356
  }
349
357
  else {
350
- NEEDLE_deferred_texture.assignTextureLOD(this.context, material);
358
+ NEEDLE_deferred_texture.assignTextureLOD(this.context, this.sourceId, material);
351
359
  }
352
360
  }
353
361
 
@@ -1,11 +1,19 @@
1
1
  import { Behaviour, GameObject } from "./Component";
2
2
  import { VideoPlayer } from "./VideoPlayer";
3
+ import Peer from "peerjs"
4
+ import { Context } from "../engine/engine_setup";
5
+ import { RoomEvents } from "../engine/engine_networking";
6
+ import { UserJoinedOrLeftRoomModel } from "../engine/engine_networking";
7
+ import { serializeable } from "../engine/engine_serialization";
8
+ import { IModel } from "../engine/engine_networking";
3
9
 
4
10
  export class ScreenCapture extends Behaviour {
5
11
 
12
+ @serializeable()
6
13
  streamOnAwake: boolean = true;
7
14
 
8
15
  start() {
16
+ console.warn("EXPERIMENTAL screen capture", this);
9
17
  if (this.streamOnAwake)
10
18
  this.open();
11
19
  }
@@ -22,7 +30,7 @@ export class ScreenCapture extends Behaviour {
22
30
  if (player) {
23
31
  const displayMediaOptions: DisplayMediaStreamConstraints = {
24
32
  video: true,
25
- audio: false
33
+ audio: true
26
34
  };
27
35
  this.captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
28
36
  if (this.captureStream && this.requestOpen) {
@@ -30,6 +38,7 @@ export class ScreenCapture extends Behaviour {
30
38
  player.clip = this.captureStream;
31
39
  player.create(true);
32
40
  }
41
+ this.handleNetworkedVideo();
33
42
  }
34
43
  } catch (err) {
35
44
  console.error("Error: " + err);
@@ -44,4 +53,305 @@ export class ScreenCapture extends Behaviour {
44
53
  this.captureStream = null;
45
54
  }
46
55
  }
47
- }
56
+
57
+ private handleNetworkedVideo() {
58
+ if (!this.context.connection.isConnected) {
59
+ console.warn("Will not stream video - not connected to room");
60
+ return;
61
+ }
62
+ if (this.captureStream) {
63
+ const handle = PeerHandle.getOrCreate(this.context, this.guid);
64
+ handle.enable();
65
+ // if (!this.peer)
66
+ // this.peer = new Peer();
67
+ const net = new NetworkedVideo(this.context, handle);
68
+ net.enable();
69
+ net.startSendingVideo(this.captureStream);
70
+ }
71
+ }
72
+
73
+ }
74
+
75
+
76
+ enum PeerHandleEvent {
77
+ Connected = "peer-user-connected",
78
+ }
79
+
80
+ class PeerUserConnectedModel implements IModel {
81
+ /** the peer handle id */
82
+ readonly guid: string;
83
+ readonly peerId: string;
84
+ // internal so server doesnt save it to persistent storage
85
+ readonly dontSave: boolean = true;
86
+ constructor(handle: PeerHandle, peerId: string) {
87
+ this.guid = handle.id;
88
+ this.peerId = peerId;
89
+ }
90
+ }
91
+
92
+ enum CallDirection {
93
+ Incoming = "incoming",
94
+ Outgoing = "outgoing",
95
+ }
96
+
97
+ class CallHandle {
98
+ readonly direction: CallDirection;
99
+ readonly call: Peer.MediaConnection;
100
+ stream: MediaStream | null;
101
+
102
+ constructor(call: Peer.MediaConnection, direction: CallDirection) {
103
+ this.call = call;
104
+ this.direction = direction;
105
+ this.stream = null;
106
+ call.on("stream", stream => {
107
+ this.stream = stream;
108
+ });
109
+ }
110
+ }
111
+
112
+ class PeerHandle {
113
+
114
+ private static readonly instances: Map<string, PeerHandle> = new Map();
115
+
116
+ static getOrCreate(context: Context, guid: string): PeerHandle {
117
+ // if (id === undefined) {
118
+ // // randomId
119
+ // id = Math.random().toFixed(5);
120
+ // }
121
+ if (PeerHandle.instances.has(guid))
122
+ return PeerHandle.instances.get(guid)!;
123
+ const peer = new PeerHandle(context, guid);
124
+ PeerHandle.instances.set(guid, peer);
125
+ return peer;
126
+ }
127
+
128
+ getPeerIdFromUserId(userConnectionId: string): string {
129
+ // we build the peer id ourselves so we dont need to wait for peer to report it
130
+ return this.id + "-" + userConnectionId;
131
+ }
132
+
133
+ getUserIdFromPeerId(peerId: string): string {
134
+ return peerId.substring(this.id.length + 1);
135
+ }
136
+
137
+ makeCall(peerId: string, stream: MediaStream): CallHandle | undefined {
138
+ // if (userId === this.context.connection.connectionId) {
139
+ // console.warn("Can not call self");
140
+ // return;
141
+ // }
142
+ // const peerId = this.getUserPeerId(userId);
143
+ console.log("CALL", peerId);
144
+ const call = this._peer?.call(peerId, stream);
145
+ if (call)
146
+ return this.registerCall(call, CallDirection.Outgoing);
147
+ return undefined;
148
+ }
149
+
150
+ get peer(): Peer | undefined { return this._peer; }
151
+
152
+ readonly id: string;
153
+ readonly context: Context;
154
+ private _peer: Peer | undefined;
155
+ private _incomingCalls: CallHandle[] = [];
156
+ private _outgoingCalls: CallHandle[] = [];
157
+
158
+ private constructor(context: Context, id: string) {
159
+ this.context = context;
160
+ this.id = id;
161
+ this.setupPeer();
162
+ navigator["getUserMedia"] = (
163
+ navigator["getUserMedia"] || navigator["webkitGetUserMedia"] ||
164
+ navigator["mozGetUserMedia"] || navigator["msGetUserMedia"]
165
+ );
166
+ }
167
+
168
+ private _enabled: boolean = false;
169
+ private _enabledPeer: boolean = false;
170
+ private onConnectRoomFn: Function = this.onConnectRoom.bind(this);
171
+ private onUserJoinedOrLeftRoomFn: Function = this.onUserJoinedOrLeftRoom.bind(this);
172
+ private onPeerConnectFn: (id) => void = this.onPeerConnect.bind(this);
173
+ private onPeerReceiveCallFn: (call) => void = this.onPeerReceivingCall.bind(this);
174
+ // private _connectionPeerIdMap : Map<string, string> = new Map();
175
+
176
+ enable() {
177
+ if (this._enabled) return;
178
+ this._enabled = true;
179
+ this.context.connection.beginListen(RoomEvents.JoinedRoom, this.onConnectRoomFn);
180
+ this.context.connection.beginListen(RoomEvents.UserJoinedRoom, this.onUserJoinedOrLeftRoomFn);
181
+ this.context.connection.beginListen(RoomEvents.UserLeftRoom, this.onUserJoinedOrLeftRoomFn);
182
+ this.subscribePeerEvents();
183
+ }
184
+
185
+ disable() {
186
+ if (!this._enabled) return;
187
+ this._enabled = false;
188
+ this.context.connection.stopListening(RoomEvents.JoinedRoom, this.onConnectRoomFn);
189
+ this.context.connection.stopListening(RoomEvents.UserJoinedRoom, this.onUserJoinedOrLeftRoomFn);
190
+ this.context.connection.stopListening(RoomEvents.UserLeftRoom, this.onUserJoinedOrLeftRoomFn);
191
+ this.unsubscribePeerEvents();
192
+ }
193
+
194
+ private onConnectRoom(): void {
195
+ this.setupPeer();
196
+ };
197
+
198
+ private onUserJoinedOrLeftRoom(_: UserJoinedOrLeftRoomModel): void {
199
+ };
200
+
201
+ private setupPeer() {
202
+ if (!this.context.connection.connectionId) return;
203
+ if (this._enabledPeer) return;
204
+ this._enabledPeer = true;
205
+ if (!this._peer) {
206
+ const peerId = this.getPeerIdFromUserId(this.context.connection.connectionId);
207
+ this._peer = new Peer(peerId);
208
+ }
209
+ if (this._enabled)
210
+ this.subscribePeerEvents();
211
+ }
212
+
213
+ private subscribePeerEvents() {
214
+ if (!this._peer) return;
215
+ this._peer.on("open", this.onPeerConnectFn);
216
+ this._peer.on("call", this.onPeerReceiveCallFn);
217
+ // this.context.connection.beginListen(PeerEvent.Connected, this.onRemotePeerConnect.bind(this));
218
+ }
219
+
220
+ private unsubscribePeerEvents() {
221
+ }
222
+
223
+ private onPeerConnect(id): void {
224
+ console.log("connect", id);
225
+ this.context.connection.send(PeerHandleEvent.Connected, new PeerUserConnectedModel(this, id));
226
+ }
227
+
228
+ private onPeerReceivingCall(call: Peer.MediaConnection): void {
229
+ console.log("RECEIVE CALL");
230
+ call.answer();
231
+ this.registerCall(call, CallDirection.Incoming);
232
+ }
233
+
234
+ private registerCall(call: Peer.MediaConnection, direction: CallDirection): CallHandle {
235
+ const arr = direction === CallDirection.Incoming ? this._incomingCalls : this._outgoingCalls;
236
+ const handle = new CallHandle(call, direction);
237
+ arr.push(handle);
238
+ call.on("error", err => {
239
+ console.error(err);
240
+ });
241
+ call.on("close", () => {
242
+ const index = arr.indexOf(handle);
243
+ if (index !== -1)
244
+ arr.splice(index, 1);
245
+ });
246
+ return handle;
247
+ }
248
+
249
+ // private onRemotePeerConnect(user: PeerUserConnectedModel) {
250
+ // console.log("other user connected", user);
251
+ // }
252
+ }
253
+
254
+
255
+ type UserVideoCall = {
256
+ call: Peer.MediaConnection;
257
+ stream: MediaStream;
258
+ userId: string;
259
+ }
260
+
261
+ class NetworkedVideo {
262
+
263
+ private readonly context: Context;
264
+ private readonly peer: PeerHandle;
265
+
266
+ private _sendingVideoStreams: Map<MediaStream, UserVideoCall[]> = new Map();
267
+
268
+ constructor(context: Context, peer: PeerHandle) {
269
+ this.context = context;
270
+ this.peer = peer;
271
+
272
+ // this.peer.on("open", (id) => {
273
+ // console.log("PEERID", id);
274
+ // });
275
+ // // this.peer.on("call", (call) => {
276
+ // // });
277
+ // // this.peer.on("connection", (conn) => {
278
+ // // });
279
+ // // this.peer.on("error", (err) => {
280
+ // // });
281
+ // // this.peer.on("disconnected", () => {
282
+ // // });
283
+ // // this.peer.on("close", () => {
284
+ // // });
285
+ }
286
+
287
+ startSendingVideo(stream: MediaStream) {
288
+ if (!this._sendingVideoStreams.has(stream)) {
289
+ this._sendingVideoStreams.set(stream, []);
290
+ this.updateSendingCalls();
291
+ };
292
+ }
293
+
294
+ stopSendingVideo(_steam: MediaStream) {
295
+
296
+ }
297
+
298
+ private onConnectRoomFn: Function = this.onConnectRoom.bind(this);
299
+ private onUserConnectedFn: Function = this.onUserConnected.bind(this);
300
+ private onUserLeftFn: Function = this.onUserLeft.bind(this);
301
+
302
+ enable() {
303
+ this.context.connection.beginListen(PeerHandleEvent.Connected, this.onUserConnectedFn);
304
+ }
305
+
306
+ disable() {
307
+ // this.context.connection.stopListening(RoomEvents.UserJoinedRoom, this.onUserConnectedFn);
308
+ // this.context.connection.stopListening(RoomEvents.UserLeftRoom, this.onUserLeftFn);
309
+ }
310
+
311
+ private onConnectRoom() {
312
+
313
+ }
314
+
315
+ private onUserConnected(user: PeerUserConnectedModel) {
316
+ // console.log(this.peer.id, user.guid)
317
+ if (this.peer.id === user.guid) {
318
+ console.log("USER CONNECTED", user);
319
+ const userId = this.peer.getUserIdFromPeerId(user.peerId);
320
+ console.log(userId);
321
+ // this.updateSendingCalls();
322
+ const call = this.peer.makeCall(user.peerId, this._sendingVideoStreams.keys().next().value);
323
+
324
+ // for (const userId of this.context.connection.usersInRoom()) {
325
+ // const id = this.peer.getPeerIdFromUserId(userId);
326
+ // if(id === user.peerId) console.log(userId);
327
+ // }
328
+ }
329
+ }
330
+
331
+ private onUserLeft(_: UserJoinedOrLeftRoomModel) {
332
+
333
+ }
334
+
335
+ private updateSendingCalls() {
336
+ // for (const str of this._sendingVideoStreams.keys()) {
337
+ // const calls = this._sendingVideoStreams.get(str) || [];
338
+ // for (const userId of this.context.connection.usersInRoom()) {
339
+ // const existing = calls.find(c => c.userId === userId);
340
+ // if (!existing) {
341
+ // const call = this.peer.makeCall(userId, str);
342
+ // console.log(call);
343
+ // if (call) {
344
+ // calls.push({
345
+ // call: call,
346
+ // stream: str,
347
+ // userId: userId
348
+ // });
349
+ // }
350
+ // }
351
+ // }
352
+ // this._sendingVideoStreams.set(str, calls);
353
+ // }
354
+ }
355
+
356
+ // const call = peer.call(peerId, stream);
357
+ }