Skip to content

Commit c21006d

Browse files
committed
wip
1 parent ff34e5e commit c21006d

File tree

11 files changed

+205
-23
lines changed

11 files changed

+205
-23
lines changed

browser-interface/packages/shared/comms/actions.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@ export const SET_ROOM_CONNECTION = '[COMMS] setRoomConnection'
1010
export const setRoomConnection = (room: RoomConnection | undefined) => action(SET_ROOM_CONNECTION, room)
1111
export type SetRoomConnectionAction = ReturnType<typeof setRoomConnection>
1212

13+
export const SET_SCENE_ROOM_CONNECTION = '[COMMS] setSceneRoomConnection'
14+
export const setSceneRoomConnection = (sceneId: string, room: RoomConnection) =>
15+
action(SET_SCENE_ROOM_CONNECTION, { sceneId, room })
16+
export type SetSceneRoomConnectionAction = ReturnType<typeof setSceneRoomConnection>
17+
1318
export const HANDLE_ROOM_DISCONNECTION = '[COMMS] handleRoomDisconnection'
1419
export const handleRoomDisconnection = (room: RoomConnection) => action(HANDLE_ROOM_DISCONNECTION, { context: room })
1520
export type HandleRoomDisconnection = ReturnType<typeof handleRoomDisconnection>
1621

1722
export const SET_LIVEKIT_ADAPTER = '[COMMS] setLiveKitAdapter'
18-
export const setLiveKitAdapter = (livekitAdapter: LivekitAdapter | undefined) => action(SET_LIVEKIT_ADAPTER, livekitAdapter)
19-
export type SetLiveKitAdapterAction = ReturnType<typeof setLiveKitAdapter>
23+
export const setLiveKitAdapter = (livekitAdapter: LivekitAdapter | undefined) =>
24+
action(SET_LIVEKIT_ADAPTER, livekitAdapter)
25+
export type SetLiveKitAdapterAction = ReturnType<typeof setLiveKitAdapter>

browser-interface/packages/shared/comms/handlers.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@ const sendMyProfileOverCommsChannel = new Observable<Record<string, never>>()
4949
const pingRequests = new Map<number, PingRequest>()
5050
let pingIndex = 0
5151

52-
export async function bindHandlersToCommsContext(room: RoomConnection) {
53-
removeAllPeers()
54-
pingRequests.clear()
52+
export async function bindHandlersToCommsContext(room: RoomConnection, islandRoom: boolean = true) {
53+
if (islandRoom) {
54+
removeAllPeers()
55+
pingRequests.clear()
56+
}
5557

5658
// RFC4 messages
5759
room.events.on('position', (e) => processPositionMessage(room, e))

browser-interface/packages/shared/comms/logic/rfc-4-room-connection.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,24 @@ export class Rfc4RoomConnection implements RoomConnection {
1717

1818
private positionIndex: number = 0
1919

20-
constructor(private transport: MinimumCommunicationsAdapter) {
20+
constructor(private transport: MinimumCommunicationsAdapter, private id: string = '-') {
2121
this.transport.events.on('message', this.handleMessage.bind(this))
2222
this.transport.events.on('DISCONNECTION', (event) => this.events.emit('DISCONNECTION', event))
2323
this.transport.events.on('PEER_DISCONNECTED', (event) => this.events.emit('PEER_DISCONNECTED', event))
2424
}
2525

2626
async connect(): Promise<void> {
27+
console.log('[RoomConnection Comms]: connect', this.id)
2728
await this.transport.connect()
2829
}
2930

3031
createVoiceHandler(): Promise<VoiceHandler> {
32+
console.log('[RoomConnection Comms]: createVoiceHandler', this.id)
3133
return this.transport.createVoiceHandler()
3234
}
3335

3436
sendPositionMessage(p: Omit<proto.Position, 'index'>): Promise<void> {
37+
console.log('[RoomConnection Comms]: sendPositionMessage', this.id)
3538
return this.sendMessage(false, {
3639
message: {
3740
$case: 'position',
@@ -43,25 +46,32 @@ export class Rfc4RoomConnection implements RoomConnection {
4346
})
4447
}
4548
sendParcelSceneMessage(scene: proto.Scene): Promise<void> {
49+
console.log('[RoomConnection Comms]: sendParcelSceneMessage', this.id)
4650
return this.sendMessage(false, { message: { $case: 'scene', scene } })
4751
}
4852
sendProfileMessage(profileVersion: proto.AnnounceProfileVersion): Promise<void> {
53+
console.log('[RoomConnection Comms]: sendProfileMessage', this.id)
4954
return this.sendMessage(false, { message: { $case: 'profileVersion', profileVersion } })
5055
}
5156
sendProfileRequest(profileRequest: proto.ProfileRequest): Promise<void> {
57+
console.log('[RoomConnection Comms]: sendProfileRequest', this.id)
5258
return this.sendMessage(false, { message: { $case: 'profileRequest', profileRequest } })
5359
}
5460
sendProfileResponse(profileResponse: proto.ProfileResponse): Promise<void> {
61+
console.log('[RoomConnection Comms]: sendProfileResponse', this.id)
5562
return this.sendMessage(false, { message: { $case: 'profileResponse', profileResponse } })
5663
}
5764
sendChatMessage(chat: proto.Chat): Promise<void> {
65+
console.log('[RoomConnection Comms]: sendChatMessage', this.id)
5866
return this.sendMessage(true, { message: { $case: 'chat', chat } })
5967
}
6068
sendVoiceMessage(voice: proto.Voice): Promise<void> {
69+
console.log('[RoomConnection Comms]: sendVoiceMessage', this.id)
6170
return this.sendMessage(false, { message: { $case: 'voice', voice } })
6271
}
6372

6473
async disconnect() {
74+
console.log('[RoomConnection Comms]: disconnect', this.id)
6575
await this.transport.disconnect()
6676
}
6777

@@ -72,6 +82,7 @@ export class Rfc4RoomConnection implements RoomConnection {
7282
return
7383
}
7484

85+
console.log('[RoomConnection Comms]: handleMessage', message.$case, this.id)
7586
switch (message.$case) {
7687
case 'position': {
7788
this.events.emit('position', { address, data: message.position })

browser-interface/packages/shared/comms/reducer.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { COMMS_ESTABLISHED } from 'shared/loading/types'
22

33
import { CommsActions, CommsState } from './types'
4-
import { SET_COMMS_ISLAND, SET_LIVEKIT_ADAPTER, SET_ROOM_CONNECTION } from './actions'
4+
import { SET_COMMS_ISLAND, SET_LIVEKIT_ADAPTER, SET_ROOM_CONNECTION, SET_SCENE_ROOM_CONNECTION } from './actions'
55

66
const INITIAL_COMMS: CommsState = {
77
initialized: false,
8-
context: undefined
8+
context: undefined,
9+
scene: undefined,
10+
scenes: new Map()
911
}
1012

1113
export function commsReducer(state?: CommsState, action?: CommsActions): CommsState {
@@ -26,7 +28,10 @@ export function commsReducer(state?: CommsState, action?: CommsActions): CommsSt
2628
}
2729
return { ...state, context: action.payload }
2830
case SET_LIVEKIT_ADAPTER:
29-
return { ...state, livekitAdapter: action.payload}
31+
return { ...state, livekitAdapter: action.payload }
32+
case SET_SCENE_ROOM_CONNECTION:
33+
state.scenes.set(action.payload.sceneId, action.payload.room)
34+
return { ...state, scene: action.payload.room }
3035
default:
3136
return state
3237
}

browser-interface/packages/shared/comms/sagas.ts

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import {
3636
setRoomConnection,
3737
SET_COMMS_ISLAND,
3838
SET_ROOM_CONNECTION,
39-
setLiveKitAdapter
39+
setLiveKitAdapter,
40+
setSceneRoomConnection
4041
} from './actions'
4142
import { LivekitAdapter } from './adapters/LivekitAdapter'
4243
import { OfflineAdapter } from './adapters/OfflineAdapter'
@@ -48,13 +49,16 @@ import { positionReportToCommsPositionRfc4 } from './interface/utils'
4849
import { commsLogger } from './logger'
4950
import { Rfc4RoomConnection } from './logic/rfc-4-room-connection'
5051
import { getConnectedPeerCount, processAvatarVisibility } from './peers'
51-
import { getCommsRoom, reconnectionState } from './selectors'
52+
import { getCommsRoom, getSceneRooms, reconnectionState } from './selectors'
5253
import { RootState } from 'shared/store/rootTypes'
5354
import { now } from 'lib/javascript/now'
5455
import { getGlobalAudioStream } from './adapters/voice/loopback'
5556
import { store } from 'shared/store/isolatedStore'
5657
import { buildSnapshotContent } from 'shared/profiles/sagas/handleDeployProfile'
5758
import { isBase64 } from 'lib/encoding/base64ToBlob'
59+
import { SET_PARCEL_POSITION } from 'shared/scene-loader/actions'
60+
import { getSceneLoader } from '../scene-loader/selectors'
61+
import { Vector2 } from '../protocol/decentraland/common/vectors.gen'
5862

5963
const TIME_BETWEEN_PROFILE_RESPONSES = 1000
6064
// this interval should be fast because this will be the delay other people around
@@ -89,6 +93,8 @@ export function* commsSaga() {
8993
yield fork(handleCommsReconnectionInterval)
9094
yield fork(pingerProcess)
9195
yield fork(reportPositionSaga)
96+
97+
yield fork(sceneRoomComms)
9298
}
9399

94100
/**
@@ -219,7 +225,11 @@ function* handleConnectToComms(action: ConnectToCommsAction) {
219225
}
220226
}
221227

222-
async function connectAdapter(connStr: string, identity: ExplorerIdentity): Promise<RoomConnection> {
228+
async function connectAdapter(
229+
connStr: string,
230+
identity: ExplorerIdentity,
231+
id: string = 'island'
232+
): Promise<RoomConnection> {
223233
const ix = connStr.indexOf(':')
224234
const protocol = connStr.substring(0, ix)
225235
const url = connStr.substring(ix + 1)
@@ -272,12 +282,12 @@ async function connectAdapter(connStr: string, identity: ExplorerIdentity): Prom
272282
throw new Error(`An unknown error was detected while trying to connect to the selected realm.`)
273283
}
274284
case 'offline': {
275-
return new Rfc4RoomConnection(new OfflineAdapter())
285+
return new Rfc4RoomConnection(new OfflineAdapter(), id)
276286
}
277287
case 'ws-room': {
278288
const finalUrl = !url.startsWith('ws:') && !url.startsWith('wss:') ? 'wss://' + url : url
279289

280-
return new Rfc4RoomConnection(new WebSocketAdapter(finalUrl, identity))
290+
return new Rfc4RoomConnection(new WebSocketAdapter(finalUrl, identity), id)
281291
}
282292
case 'simulator': {
283293
return new SimulationRoom(url)
@@ -298,7 +308,7 @@ async function connectAdapter(connStr: string, identity: ExplorerIdentity): Prom
298308

299309
store.dispatch(setLiveKitAdapter(livekitAdapter))
300310

301-
return new Rfc4RoomConnection(livekitAdapter)
311+
return new Rfc4RoomConnection(livekitAdapter, id)
302312
}
303313
}
304314
throw new Error(`A communications adapter could not be created for protocol=${protocol}`)
@@ -531,3 +541,61 @@ function* handleRoomDisconnectionSaga(action: HandleRoomDisconnection) {
531541
}
532542
}
533543
}
544+
545+
function* sceneRoomComms() {
546+
let currentSceneId: string = ''
547+
const commsSceneToRemove = new Map<string, NodeJS.Timeout>()
548+
549+
while (true) {
550+
const reason: { timeout?: unknown; newParcel?: { payload: { position: Vector2 } } } = yield race({
551+
newParcel: take(SET_PARCEL_POSITION),
552+
timeout: delay(5000)
553+
})
554+
const sceneLoader: ReturnType<typeof getSceneLoader> = yield select(getSceneLoader)
555+
if (!sceneLoader) continue
556+
if (reason.newParcel) {
557+
const sceneId = yield call(sceneLoader.getSceneId!, reason.newParcel.payload.position)
558+
// We are still on the same scene.
559+
if (sceneId === currentSceneId) continue
560+
const oldSceneId = currentSceneId
561+
yield call(checkDisconnectScene, sceneId, oldSceneId, commsSceneToRemove)
562+
yield call(connectSceneToComms, sceneId)
563+
// Player moved to a new scene. Instanciate new comms
564+
currentSceneId = sceneId
565+
}
566+
}
567+
}
568+
569+
function* checkDisconnectScene(
570+
currentSceneId: string,
571+
oldSceneId: string,
572+
commsSceneToRemove: Map<string, NodeJS.Timeout>
573+
) {
574+
// avoid deleting an already created comms. Use when the user is switching between two scenes
575+
if (commsSceneToRemove.has(currentSceneId)) {
576+
clearTimeout(commsSceneToRemove.get(currentSceneId))
577+
commsSceneToRemove.delete(currentSceneId)
578+
}
579+
if (!oldSceneId) return
580+
581+
console.log('[SceneComms]: will disconnect', oldSceneId)
582+
const sceneRooms: ReturnType<typeof getSceneRooms> = yield select(getSceneRooms)
583+
const oldRoom = sceneRooms.get(oldSceneId)
584+
const timeout = setTimeout(() => {
585+
console.log('[SceneComms]: disconnectSceneComms', oldSceneId)
586+
void oldRoom?.disconnect()
587+
commsSceneToRemove.delete(oldSceneId)
588+
}, 1000)
589+
commsSceneToRemove.set(oldSceneId, timeout)
590+
}
591+
592+
function* connectSceneToComms(sceneId: string) {
593+
console.log('[SceneComms]: connectSceneToComms', sceneId)
594+
// Fetch connection string
595+
// const connectionString = `https://boedo.com/${sceneId}`
596+
const connectionString = `offline:offline`
597+
const identity: ExplorerIdentity = yield select(getCurrentIdentity)
598+
const sceneRoomConnetion = yield call(connectAdapter, connectionString, identity, sceneId)
599+
yield call(bindHandlersToCommsContext, sceneRoomConnetion, false)
600+
yield put(setSceneRoomConnection(sceneId, sceneRoomConnetion))
601+
}

browser-interface/packages/shared/comms/selectors.ts

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,74 @@ import { RootState } from 'shared/store/rootTypes'
77
import { RoomConnection } from './interface'
88
import { RootCommsState } from './types'
99
import { ActiveVideoStreams } from './adapters/types'
10+
import {
11+
AnnounceProfileVersion,
12+
ProfileRequest,
13+
ProfileResponse,
14+
Position,
15+
Scene,
16+
Chat,
17+
Voice
18+
} from '../protocol/decentraland/kernel/comms/rfc4/comms.gen'
1019

1120
export const getCommsIsland = (store: RootCommsState): string | undefined => store.comms.island
12-
export const getCommsRoom = (state: RootCommsState): RoomConnection | undefined => state.comms.context
21+
export const getSceneRoomComms = (state: RootCommsState): RoomConnection | undefined => state.comms.scene
22+
export const getSceneRooms = (state: RootCommsState): Map<string, RoomConnection> => state.comms.scenes
23+
24+
export const getCommsRoom = (state: RootCommsState): RoomConnection | undefined => {
25+
const islandRoom = state.comms.context
26+
const sceneRoom = state.comms.scene
27+
if (!islandRoom) return undefined
28+
return {
29+
connect: async () => {
30+
debugger
31+
},
32+
// events: islandRoom.events,
33+
disconnect: async () => {
34+
await islandRoom.disconnect()
35+
// TBD: should we disconnect from scenes here too ?
36+
},
37+
sendProfileMessage: async (profile: AnnounceProfileVersion) => {
38+
const island = islandRoom.sendProfileMessage(profile)
39+
const scene = sceneRoom?.sendProfileMessage(profile)
40+
await Promise.all([island, scene])
41+
},
42+
sendProfileRequest: async (request: ProfileRequest) => {
43+
const island = islandRoom.sendProfileRequest(request)
44+
const scene = sceneRoom?.sendProfileRequest(request)
45+
await Promise.all([island, scene])
46+
},
47+
sendProfileResponse: async (response: ProfileResponse) => {
48+
const island = islandRoom.sendProfileResponse(response)
49+
const scene = sceneRoom?.sendProfileResponse(response)
50+
await Promise.all([island, scene])
51+
},
52+
sendPositionMessage: async (position: Omit<Position, 'index'>) => {
53+
const island = islandRoom.sendPositionMessage(position)
54+
const scene = sceneRoom?.sendPositionMessage(position)
55+
await Promise.all([island, scene])
56+
},
57+
sendParcelSceneMessage: async (message: Scene) => {
58+
const island = islandRoom.sendParcelSceneMessage(message)
59+
const scene = sceneRoom?.sendParcelSceneMessage(message)
60+
await Promise.all([island, scene])
61+
},
62+
sendChatMessage: async (message: Chat) => {
63+
const island = islandRoom.sendChatMessage(message)
64+
const scene = sceneRoom?.sendChatMessage(message)
65+
await Promise.all([island, scene])
66+
},
67+
sendVoiceMessage: async (message: Voice) => {
68+
// TBD: Feature flag for backwards compatibility
69+
await sceneRoom?.sendVoiceMessage(message)
70+
},
71+
createVoiceHandler: async () => {
72+
// TBD: Feature flag for backwards compatibility
73+
if (!sceneRoom) debugger
74+
return sceneRoom!.createVoiceHandler()
75+
}
76+
} as RoomConnection
77+
}
1378

1479
export function reconnectionState(state: RootState): {
1580
commsConnection: RoomConnection | undefined
@@ -25,4 +90,5 @@ export function reconnectionState(state: RootState): {
2590
}
2691
}
2792

28-
export const getLivekitActiveVideoStreams = (store: RootCommsState): Map<string, ActiveVideoStreams> | undefined => store.comms.livekitAdapter?.getActiveVideoStreams()
93+
export const getLivekitActiveVideoStreams = (store: RootCommsState): Map<string, ActiveVideoStreams> | undefined =>
94+
store.comms.livekitAdapter?.getActiveVideoStreams()

browser-interface/packages/shared/comms/types.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
import { CommsEstablished } from 'shared/loading/types'
2-
import { HandleRoomDisconnection, SetCommsIsland, SetLiveKitAdapterAction, SetRoomConnectionAction } from './actions'
2+
import { HandleRoomDisconnection, SetCommsIsland, SetLiveKitAdapterAction, SetRoomConnectionAction, SetSceneRoomConnectionAction } from './actions'
33
import { LivekitAdapter } from './adapters/LivekitAdapter'
44
import { RoomConnection } from './interface'
55

6+
type SceneId = string
7+
68
export type CommsState = {
79
initialized: boolean
810
island?: string
9-
context: RoomConnection | undefined,
11+
context: RoomConnection | undefined
1012
livekitAdapter?: LivekitAdapter
13+
scene: RoomConnection | undefined
14+
scenes: Map<SceneId, RoomConnection>
1115
}
1216

13-
export type CommsActions =
17+
export type CommsActions =
1418
| SetCommsIsland
1519
| SetRoomConnectionAction
1620
| HandleRoomDisconnection
1721
| SetLiveKitAdapterAction
1822
| CommsEstablished
23+
| SetSceneRoomConnectionAction
1924

2025
export type CommsConnectionState =
2126
| 'initial'

browser-interface/packages/shared/scene-loader/genesis-city-loader-impl/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ export function createGenesisCityLoader(options: {
3939
}
4040

4141
return {
42+
async getSceneId(parcel: Vector2): Promise<string | undefined> {
43+
const scene = downloadManager.pointerToEntity.get(encodeParcelPosition(parcel))
44+
if (scene) {
45+
return (await scene)?.id
46+
}
47+
},
4248
async fetchScenesByLocation(parcels) {
4349
const results = await downloadManager.resolveEntitiesByPointer(parcels)
4450
return {

0 commit comments

Comments
 (0)