@needle-tools/engine 2.29.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.
- package/CHANGELOG.md +9 -0
- package/dist/needle-engine.d.ts +44 -8
- package/dist/needle-engine.js +347 -343
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +20 -16
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/engine.d.ts +1 -0
- package/lib/engine/engine_serialization.d.ts +1 -0
- package/lib/engine/engine_serialization.js +1 -0
- package/lib/engine/engine_serialization.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +5 -0
- package/lib/engine/engine_setup.js +6 -0
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -1
- package/lib/engine/engine_utils.js +25 -8
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_deferred_texture.d.ts +1 -1
- package/lib/engine/extensions/NEEDLE_deferred_texture.js +26 -14
- package/lib/engine/extensions/NEEDLE_deferred_texture.js.map +1 -1
- package/lib/engine/extensions/extension_utils.js +24 -13
- package/lib/engine/extensions/extension_utils.js.map +1 -1
- package/lib/engine/extensions/extensions.js +3 -1
- package/lib/engine/extensions/extensions.js.map +1 -1
- package/lib/engine-components/Camera.js +7 -0
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +2 -1
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +1 -0
- package/lib/engine-components/Renderer.js +10 -3
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/ScreenCapture.d.ts +1 -0
- package/lib/engine-components/ScreenCapture.js +265 -1
- package/lib/engine-components/ScreenCapture.js.map +1 -1
- package/lib/engine-components/SpectatorCamera.js +29 -5
- package/lib/engine-components/SpectatorCamera.js.map +1 -1
- package/lib/engine-components/SyncedRoom.js +2 -0
- package/lib/engine-components/SyncedRoom.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +10 -1
- package/lib/engine-components/VideoPlayer.js +64 -15
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/Volume.d.ts +4 -0
- package/lib/engine-components/Volume.js +44 -3
- package/lib/engine-components/Volume.js.map +1 -1
- package/lib/engine-components/WebARSessionRoot.d.ts +9 -2
- package/lib/engine-components/WebARSessionRoot.js +69 -24
- package/lib/engine-components/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/WebXR.d.ts +6 -3
- package/lib/engine-components/WebXR.js +42 -7
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/WebXRAvatar.js +4 -0
- package/lib/engine-components/WebXRAvatar.js.map +1 -1
- package/lib/engine-components/WebXRController.js +13 -7
- package/lib/engine-components/WebXRController.js.map +1 -1
- package/lib/engine-components/ui/CanvasGroup.d.ts +1 -0
- package/lib/engine-components/ui/CanvasGroup.js +1 -0
- package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +13 -4
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/Graphic.d.ts +1 -0
- package/lib/engine-components/ui/Graphic.js +2 -0
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Interfaces.d.ts +2 -0
- package/package.json +2 -2
- package/src/engine/engine_serialization.ts +3 -1
- package/src/engine/engine_setup.ts +6 -0
- package/src/engine/engine_utils.ts +34 -8
- package/src/engine/extensions/NEEDLE_deferred_texture.ts +25 -19
- package/src/engine/extensions/extension_utils.ts +24 -12
- package/src/engine/extensions/extensions.ts +3 -2
- package/src/engine-components/Camera.ts +9 -1
- package/src/engine-components/OrbitControls.ts +2 -1
- package/src/engine-components/Renderer.ts +11 -3
- package/src/engine-components/ScreenCapture.ts +312 -2
- package/src/engine-components/SpectatorCamera.ts +28 -5
- package/src/engine-components/SyncedRoom.ts +1 -0
- package/src/engine-components/VideoPlayer.ts +97 -21
- package/src/engine-components/Volume.ts +47 -4
- package/src/engine-components/WebARSessionRoot.ts +78 -28
- package/src/engine-components/WebXR.ts +50 -15
- package/src/engine-components/WebXRAvatar.ts +5 -0
- package/src/engine-components/WebXRController.ts +20 -14
- package/src/engine-components/ui/CanvasGroup.ts +2 -0
- package/src/engine-components/ui/EventSystem.ts +21 -15
- package/src/engine-components/ui/Graphic.ts +3 -0
- package/src/engine-components/ui/Interfaces.ts +2 -0
|
@@ -10,13 +10,20 @@ declare type DependencyInfo = {
|
|
|
10
10
|
dependencyName: string,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const rootExtensionPrefix = "/extensions/";
|
|
13
|
+
const rootExtensionPrefix = ["/extensions/", "extensions/"];
|
|
14
14
|
const defaultDependencies = [
|
|
15
15
|
{ prefix: "/nodes/", dependencyName: "node" },
|
|
16
16
|
{ prefix: "/meshes/", dependencyName: "mesh" },
|
|
17
17
|
{ prefix: "/materials/", dependencyName: "material" },
|
|
18
18
|
{ prefix: "/textures/", dependencyName: "texture" },
|
|
19
|
-
{ prefix: "/animations/", dependencyName: "animation" }
|
|
19
|
+
{ prefix: "/animations/", dependencyName: "animation" },
|
|
20
|
+
|
|
21
|
+
// legacy support
|
|
22
|
+
{ prefix: "nodes/", dependencyName: "node" },
|
|
23
|
+
{ prefix: "meshes/", dependencyName: "mesh" },
|
|
24
|
+
{ prefix: "materials/", dependencyName: "material" },
|
|
25
|
+
{ prefix: "textures/", dependencyName: "texture" },
|
|
26
|
+
{ prefix: "animations/", dependencyName: "animation" },
|
|
20
27
|
]
|
|
21
28
|
|
|
22
29
|
export async function resolveReferences(parser: GLTFParser, obj) {
|
|
@@ -95,16 +102,21 @@ function internalResolve(paths: DependencyInfo[], parser: GLTFParser, obj, promi
|
|
|
95
102
|
|
|
96
103
|
|
|
97
104
|
function resolveExtension(parser: GLTFParser, str): Promise<void> | null {
|
|
98
|
-
if (parser && parser.plugins && typeof str === "string"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
if (parser && parser.plugins && typeof str === "string") {
|
|
106
|
+
for (const prefix of rootExtensionPrefix) {
|
|
107
|
+
if (str.startsWith(prefix)) {
|
|
108
|
+
let name = str.substring(prefix.length);
|
|
109
|
+
const endIndex = name.indexOf("/");
|
|
110
|
+
if (endIndex >= 0) name = name.substring(0, endIndex);
|
|
111
|
+
const ext = parser.plugins[name] as IExtensionReferenceResolver;
|
|
112
|
+
if (debugExtension)
|
|
113
|
+
console.log(name, ext);
|
|
114
|
+
if (typeof ext?.resolve === "function") {
|
|
115
|
+
const path = str.substring(prefix.length + name.length + 1);
|
|
116
|
+
return ext.resolve(parser, path);
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
108
120
|
}
|
|
109
121
|
}
|
|
110
122
|
return null;
|
|
@@ -26,8 +26,9 @@ export function registerComponentExtension(loader: GLTFLoader): NEEDLE_component
|
|
|
26
26
|
class PointerResolver {
|
|
27
27
|
resolvePath(path: string) {
|
|
28
28
|
if (path.includes('/extensions/builtin_components/'))
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
return path.replace('/extensions/builtin_components/', '/userData/components/');
|
|
30
|
+
if (path.includes('extensions/builtin_components/'))
|
|
31
|
+
return path.replace('extensions/builtin_components/', '/userData/components/');
|
|
31
32
|
return path;
|
|
32
33
|
}
|
|
33
34
|
}
|
|
@@ -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);
|
|
@@ -102,7 +102,8 @@ export class OrbitControls extends Behaviour {
|
|
|
102
102
|
if (this._controls) {
|
|
103
103
|
const camGo = GameObject.getComponent(this.gameObject, Camera);
|
|
104
104
|
if (camGo && !this.setFromTargetPosition()) {
|
|
105
|
-
|
|
105
|
+
if(this.debugLog)
|
|
106
|
+
console.log("NO TARGET");
|
|
106
107
|
const forward = new THREE.Vector3(0, 0, -1).applyMatrix4(camGo.cam.matrixWorld);
|
|
107
108
|
this.setTarget(forward, true);
|
|
108
109
|
}
|
|
@@ -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:
|
|
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
|
+
}
|
|
@@ -170,6 +170,7 @@ export class SpectatorCamera extends Behaviour {
|
|
|
170
170
|
|
|
171
171
|
private onXRSessionStart(_evt) {
|
|
172
172
|
if (!this.isSupportedPlatform()) return;
|
|
173
|
+
if (debug) console.log(this.context.mainCamera);
|
|
173
174
|
if (this.context.mainCamera) {
|
|
174
175
|
this.followSelf();
|
|
175
176
|
}
|
|
@@ -188,6 +189,7 @@ export class SpectatorCamera extends Behaviour {
|
|
|
188
189
|
|
|
189
190
|
private followSelf() {
|
|
190
191
|
this.target = this.context.players.getPlayerView(this.context.connection.connectionId);
|
|
192
|
+
if (debug) console.log("Follow self", this.target);
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
// TODO: only show Spectator cam for DesktopVR;
|
|
@@ -219,6 +221,8 @@ export class SpectatorCamera extends Behaviour {
|
|
|
219
221
|
|
|
220
222
|
this.setAvatarFlagsBeforeRender();
|
|
221
223
|
|
|
224
|
+
const mainCam = this.context.mainCameraComponent;
|
|
225
|
+
|
|
222
226
|
// these should not be needed if we don't override viewport/scissor
|
|
223
227
|
// renderer.getViewport(this.currentViewport);
|
|
224
228
|
// renderer.getScissor(this.currentScissor);
|
|
@@ -231,7 +235,17 @@ export class SpectatorCamera extends Behaviour {
|
|
|
231
235
|
// renderer.setViewport(left, bottom, width, height);
|
|
232
236
|
// renderer.setScissor(left, bottom, width, height);
|
|
233
237
|
// renderer.setScissorTest(true);
|
|
234
|
-
|
|
238
|
+
if (mainCam) {
|
|
239
|
+
const backgroundColor = mainCam.backgroundColor;
|
|
240
|
+
if (backgroundColor)
|
|
241
|
+
renderer.setClearColor(backgroundColor, backgroundColor.alpha);
|
|
242
|
+
this.cam.backgroundColor = backgroundColor;
|
|
243
|
+
this.cam.clearFlags = mainCam.clearFlags;
|
|
244
|
+
this.cam.nearClipPlane = mainCam.nearClipPlane;
|
|
245
|
+
this.cam.farClipPlane = mainCam.farClipPlane;
|
|
246
|
+
}
|
|
247
|
+
else
|
|
248
|
+
renderer.setClearColor(new THREE.Color(1, 1, 1));
|
|
235
249
|
renderer.setRenderTarget(null); // null: direct to Canvas
|
|
236
250
|
renderer.xr.enabled = false;
|
|
237
251
|
const cam = this.cam?.cam;
|
|
@@ -384,8 +398,16 @@ class SpectatorHandler implements ISpectatorHandler {
|
|
|
384
398
|
if (!target || !this.follow) return;
|
|
385
399
|
switch (mode) {
|
|
386
400
|
case SpectatorMode.FirstPerson:
|
|
387
|
-
this.
|
|
388
|
-
|
|
401
|
+
if (this.view?.viewDevice !== ViewDevice.Browser) {
|
|
402
|
+
// soft follow for AR and VR
|
|
403
|
+
this.follow.followFactor = 5;
|
|
404
|
+
this.follow.rotateFactor = 5;
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
// snappy follow for desktop
|
|
408
|
+
this.follow.followFactor = 50;
|
|
409
|
+
this.follow.rotateFactor = 50;
|
|
410
|
+
}
|
|
389
411
|
target.position.set(0, 0, 0);
|
|
390
412
|
break;
|
|
391
413
|
case SpectatorMode.ThirdPerson:
|
|
@@ -427,10 +449,11 @@ class SpectatorSelectionController {
|
|
|
427
449
|
downTime = this.context.time.time;
|
|
428
450
|
});
|
|
429
451
|
this.context.input.addEventListener(InputEvents.PointerUp, _ => {
|
|
430
|
-
|
|
452
|
+
const dt = this.context.time.time - downTime;
|
|
453
|
+
if (dt > 1) {
|
|
431
454
|
this.spectator.stopSpectating();
|
|
432
455
|
}
|
|
433
|
-
else
|
|
456
|
+
else if (this.context.input.getPointerClicked(0) && dt < .3)
|
|
434
457
|
this.trySelectObject();
|
|
435
458
|
});
|
|
436
459
|
}
|