From 482ba9690abf8e0aaa68c7ee0b61d9c7f1d9b9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Wed, 22 Dec 2021 18:30:23 +0100 Subject: [PATCH] Sharing outline color changes in real time --- back/src/Model/GameRoom.ts | 36 +++++++++++++++--- back/src/Model/PositionNotifier.ts | 31 ++++++++++++++-- back/src/Model/User.ts | 17 ++++++++- back/src/Model/Zone.ts | 21 ++++++++++- back/src/RoomManager.ts | 18 ++++++--- back/src/Services/SocketManager.ts | 32 ++++++++-------- front/src/Connexion/ConnexionModels.ts | 7 ++++ front/src/Connexion/RoomConnection.ts | 35 +++++++++++++++++- front/src/Phaser/Entity/Character.ts | 4 +- front/src/Phaser/Game/GameScene.ts | 51 +++++++++++++++++++++----- front/src/Stores/MediaStore.ts | 28 ++++++++++---- front/src/WebRtc/SimplePeer.ts | 2 +- messages/protos/messages.proto | 15 ++++++-- pusher/src/Model/Zone.ts | 15 ++++++++ pusher/src/Services/SocketManager.ts | 12 ++++++ 15 files changed, 268 insertions(+), 56 deletions(-) diff --git a/back/src/Model/GameRoom.ts b/back/src/Model/GameRoom.ts index 5c114f19..d708fba5 100644 --- a/back/src/Model/GameRoom.ts +++ b/back/src/Model/GameRoom.ts @@ -2,7 +2,13 @@ import { PointInterface } from "./Websocket/PointInterface"; import { Group } from "./Group"; import { User, UserSocket } from "./User"; import { PositionInterface } from "_Model/PositionInterface"; -import { EmoteCallback, EntersCallback, LeavesCallback, MovesCallback } from "_Model/Zone"; +import { + EmoteCallback, + EntersCallback, + LeavesCallback, + MovesCallback, + PlayerDetailsUpdatedCallback, +} from "_Model/Zone"; import { PositionNotifier } from "./PositionNotifier"; import { Movable } from "_Model/Movable"; import { @@ -11,6 +17,7 @@ import { EmoteEventMessage, ErrorMessage, JoinRoomMessage, + SetPlayerDetailsMessage, SubToPusherRoomMessage, VariableMessage, VariableWithTagMessage, @@ -56,10 +63,19 @@ export class GameRoom { onEnters: EntersCallback, onMoves: MovesCallback, onLeaves: LeavesCallback, - onEmote: EmoteCallback + onEmote: EmoteCallback, + onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback ) { // A zone is 10 sprites wide. - this.positionNotifier = new PositionNotifier(320, 320, onEnters, onMoves, onLeaves, onEmote); + this.positionNotifier = new PositionNotifier( + 320, + 320, + onEnters, + onMoves, + onLeaves, + onEmote, + onPlayerDetailsUpdated + ); } public static async create( @@ -71,7 +87,8 @@ export class GameRoom { onEnters: EntersCallback, onMoves: MovesCallback, onLeaves: LeavesCallback, - onEmote: EmoteCallback + onEmote: EmoteCallback, + onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback ): Promise { const mapDetails = await GameRoom.getMapDetails(roomUrl); @@ -85,7 +102,8 @@ export class GameRoom { onEnters, onMoves, onLeaves, - onEmote + onEmote, + onPlayerDetailsUpdated ); return gameRoom; @@ -180,6 +198,14 @@ export class GameRoom { this.updateUserGroup(user); } + updatePlayerDetails(user: User, playerDetailsMessage: SetPlayerDetailsMessage) { + if (playerDetailsMessage.getRemoveoutlinecolor()) { + user.outlineColor = undefined; + } else { + user.outlineColor = playerDetailsMessage.getOutlinecolor(); + } + } + private updateUserGroup(user: User): void { user.group?.updatePosition(); user.group?.searchForNearbyUsers(); diff --git a/back/src/Model/PositionNotifier.ts b/back/src/Model/PositionNotifier.ts index 2052f229..b059999a 100644 --- a/back/src/Model/PositionNotifier.ts +++ b/back/src/Model/PositionNotifier.ts @@ -8,12 +8,19 @@ * The PositionNotifier is important for performance. It allows us to send the position of players only to a restricted * number of players around the current player. */ -import { EmoteCallback, EntersCallback, LeavesCallback, MovesCallback, Zone } from "./Zone"; +import { + EmoteCallback, + EntersCallback, + LeavesCallback, + MovesCallback, + PlayerDetailsUpdatedCallback, + Zone, +} from "./Zone"; import { Movable } from "_Model/Movable"; import { PositionInterface } from "_Model/PositionInterface"; import { ZoneSocket } from "../RoomManager"; import { User } from "../Model/User"; -import { EmoteEventMessage } from "../Messages/generated/messages_pb"; +import { EmoteEventMessage, SetPlayerDetailsMessage } from "../Messages/generated/messages_pb"; interface ZoneDescriptor { i: number; @@ -42,7 +49,8 @@ export class PositionNotifier { private onUserEnters: EntersCallback, private onUserMoves: MovesCallback, private onUserLeaves: LeavesCallback, - private onEmote: EmoteCallback + private onEmote: EmoteCallback, + private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback ) {} private getZoneDescriptorFromCoordinates(x: number, y: number): ZoneDescriptor { @@ -98,7 +106,15 @@ export class PositionNotifier { let zone = this.zones[j][i]; if (zone === undefined) { - zone = new Zone(this.onUserEnters, this.onUserMoves, this.onUserLeaves, this.onEmote, i, j); + zone = new Zone( + this.onUserEnters, + this.onUserMoves, + this.onUserLeaves, + this.onEmote, + this.onPlayerDetailsUpdated, + i, + j + ); this.zones[j][i] = zone; } return zone; @@ -132,4 +148,11 @@ export class PositionNotifier { } } } + + public updatePlayerDetails(user: User, playerDetails: SetPlayerDetailsMessage) { + const position = user.getPosition(); + const zoneDesc = this.getZoneDescriptorFromCoordinates(position.x, position.y); + const zone = this.getZone(zoneDesc.i, zoneDesc.j); + zone.updatePlayerDetails(user, playerDetails); + } } diff --git a/back/src/Model/User.ts b/back/src/Model/User.ts index 186fb32a..a02ffde9 100644 --- a/back/src/Model/User.ts +++ b/back/src/Model/User.ts @@ -9,6 +9,7 @@ import { CompanionMessage, PusherToBackMessage, ServerToClientMessage, + SetPlayerDetailsMessage, SubMessage, } from "../Messages/generated/messages_pb"; import { CharacterLayer } from "_Model/Websocket/CharacterLayer"; @@ -31,7 +32,8 @@ export class User implements Movable { public readonly visitCardUrl: string | null, public readonly name: string, public readonly characterLayers: CharacterLayer[], - public readonly companion?: CompanionMessage + public readonly companion?: CompanionMessage, + private _outlineColor?: number | undefined ) { this.listenedZones = new Set(); @@ -69,4 +71,17 @@ export class User implements Movable { }, 100); } } + + public set outlineColor(value: number | undefined) { + this._outlineColor = value; + + const playerDetails = new SetPlayerDetailsMessage(); + if (value === undefined) { + playerDetails.setRemoveoutlinecolor(true); + } else { + playerDetails.setOutlinecolor(value); + } + + this.positionNotifier.updatePlayerDetails(this, playerDetails); + } } diff --git a/back/src/Model/Zone.ts b/back/src/Model/Zone.ts index d236e489..53f45464 100644 --- a/back/src/Model/Zone.ts +++ b/back/src/Model/Zone.ts @@ -3,12 +3,20 @@ import { PositionInterface } from "_Model/PositionInterface"; import { Movable } from "./Movable"; import { Group } from "./Group"; import { ZoneSocket } from "../RoomManager"; -import { EmoteEventMessage } from "../Messages/generated/messages_pb"; +import { + EmoteEventMessage, + SetPlayerDetailsMessage, + PlayerDetailsUpdatedMessage, +} from "../Messages/generated/messages_pb"; export type EntersCallback = (thing: Movable, fromZone: Zone | null, listener: ZoneSocket) => void; export type MovesCallback = (thing: Movable, position: PositionInterface, listener: ZoneSocket) => void; export type LeavesCallback = (thing: Movable, newZone: Zone | null, listener: ZoneSocket) => void; export type EmoteCallback = (emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) => void; +export type PlayerDetailsUpdatedCallback = ( + playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, + listener: ZoneSocket +) => void; export class Zone { private things: Set = new Set(); @@ -19,6 +27,7 @@ export class Zone { private onMoves: MovesCallback, private onLeaves: LeavesCallback, private onEmote: EmoteCallback, + private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback, public readonly x: number, public readonly y: number ) {} @@ -106,4 +115,14 @@ export class Zone { this.onEmote(emoteEventMessage, listener); } } + + public updatePlayerDetails(user: User, playerDetails: SetPlayerDetailsMessage) { + const playerDetailsUpdatedMessage = new PlayerDetailsUpdatedMessage(); + playerDetailsUpdatedMessage.setUserid(user.id); + playerDetailsUpdatedMessage.setDetails(playerDetails); + + for (const listener of this.listeners) { + this.onPlayerDetailsUpdated(playerDetailsUpdatedMessage, listener); + } + } } diff --git a/back/src/RoomManager.ts b/back/src/RoomManager.ts index 322c9b46..9f6b5d69 100644 --- a/back/src/RoomManager.ts +++ b/back/src/RoomManager.ts @@ -5,6 +5,7 @@ import { AdminPusherToBackMessage, AdminRoomMessage, BanMessage, + BanUserMessage, BatchToPusherMessage, BatchToPusherRoomMessage, EmotePromptMessage, @@ -16,7 +17,9 @@ import { QueryJitsiJwtMessage, RefreshRoomPromptMessage, RoomMessage, + SendUserMessage, ServerToAdminClientMessage, + SetPlayerDetailsMessage, SilentMessage, UserMovesMessage, VariableMessage, @@ -118,14 +121,17 @@ const roomManager: IRoomManagerServer = { ); } else if (message.hasSendusermessage()) { const sendUserMessage = message.getSendusermessage(); - if (sendUserMessage !== undefined) { - socketManager.handlerSendUserMessage(user, sendUserMessage); - } + socketManager.handleSendUserMessage(user, sendUserMessage as SendUserMessage); } else if (message.hasBanusermessage()) { const banUserMessage = message.getBanusermessage(); - if (banUserMessage !== undefined) { - socketManager.handlerBanUserMessage(room, user, banUserMessage); - } + socketManager.handlerBanUserMessage(room, user, banUserMessage as BanUserMessage); + } else if (message.hasSetplayerdetailsmessage()) { + const setPlayerDetailsMessage = message.getSetplayerdetailsmessage(); + socketManager.handleSetPlayerDetails( + room, + user, + setPlayerDetailsMessage as SetPlayerDetailsMessage + ); } else { throw new Error("Unhandled message type"); } diff --git a/back/src/Services/SocketManager.ts b/back/src/Services/SocketManager.ts index a5f53f4c..6d76f3af 100644 --- a/back/src/Services/SocketManager.ts +++ b/back/src/Services/SocketManager.ts @@ -33,6 +33,8 @@ import { VariableMessage, BatchToPusherRoomMessage, SubToPusherRoomMessage, + SetPlayerDetailsMessage, + PlayerDetailsUpdatedMessage, } from "../Messages/generated/messages_pb"; import { User, UserSocket } from "../Model/User"; import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils"; @@ -151,20 +153,9 @@ export class SocketManager { //room.setViewport(client, client.viewport); } - // Useless now, will be useful again if we allow editing details in game - /*handleSetPlayerDetails(client: UserSocket, playerDetailsMessage: SetPlayerDetailsMessage) { - const playerDetails = { - name: playerDetailsMessage.getName(), - characterLayers: playerDetailsMessage.getCharacterlayersList() - }; - //console.log(SocketIoEvent.SET_PLAYER_DETAILS, playerDetails); - if (!isSetPlayerDetailsMessage(playerDetails)) { - emitError(client, 'Invalid SET_PLAYER_DETAILS message received: '); - return; - } - client.name = playerDetails.name; - client.characterLayers = SocketManager.mergeCharacterLayersAndCustomTextures(playerDetails.characterLayers, client.textures); - }*/ + handleSetPlayerDetails(room: GameRoom, user: User, playerDetailsMessage: SetPlayerDetailsMessage) { + room.updatePlayerDetails(user, playerDetailsMessage); + } handleSilentMessage(room: GameRoom, user: User, silentMessage: SilentMessage) { room.setSilent(user, silentMessage.getSilent()); @@ -282,7 +273,9 @@ export class SocketManager { (thing: Movable, newZone: Zone | null, listener: ZoneSocket) => this.onClientLeave(thing, newZone, listener), (emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) => - this.onEmote(emoteEventMessage, listener) + this.onEmote(emoteEventMessage, listener), + (playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, listener: ZoneSocket) => + this.onPlayerDetailsUpdated(playerDetailsUpdatedMessage, listener) ) .then((gameRoom) => { gaugeManager.incNbRoomGauge(); @@ -378,6 +371,13 @@ export class SocketManager { emitZoneMessage(subMessage, client); } + private onPlayerDetailsUpdated(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, client: ZoneSocket) { + const subMessage = new SubToPusherMessage(); + subMessage.setPlayerdetailsupdatedmessage(playerDetailsUpdatedMessage); + + emitZoneMessage(subMessage, client); + } + private emitCreateUpdateGroupEvent(client: ZoneSocket, fromZone: Zone | null, group: Group): void { const position = group.getPosition(); const pointMessage = new PointMessage(); @@ -572,7 +572,7 @@ export class SocketManager { user.socket.write(serverToClientMessage); } - public handlerSendUserMessage(user: User, sendUserMessageToSend: SendUserMessage) { + public handleSendUserMessage(user: User, sendUserMessageToSend: SendUserMessage) { const sendUserMessage = new SendUserMessage(); sendUserMessage.setMessage(sendUserMessageToSend.getMessage()); sendUserMessage.setType(sendUserMessageToSend.getType()); diff --git a/front/src/Connexion/ConnexionModels.ts b/front/src/Connexion/ConnexionModels.ts index fa0f192e..a2dc68da 100644 --- a/front/src/Connexion/ConnexionModels.ts +++ b/front/src/Connexion/ConnexionModels.ts @@ -18,6 +18,7 @@ export enum EventMessage { GROUP_DELETE = "group-delete", SET_PLAYER_DETAILS = "set-player-details", // Send the name and character to the server (on connect), receive back the id. ITEM_EVENT = "item-event", + USER_DETAILS_UPDATED = "user-details-updated", CONNECT_ERROR = "connect_error", CONNECTING_ERROR = "connecting_error", @@ -102,6 +103,12 @@ export interface ItemEventMessageInterface { parameters: unknown; } +export interface PlayerDetailsUpdatedMessageInterface { + userId: number; + outlineColor: number; + removeOutlineColor: boolean; +} + export interface RoomJoinedMessageInterface { //users: MessageUserPositionInterface[], //groups: GroupCreatedUpdatedMessageInterface[], diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 9e4025b1..96191b15 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -34,6 +34,7 @@ import { BanUserMessage, VariableMessage, ErrorMessage, + PlayerDetailsUpdatedMessage, } from "../Messages/generated/messages_pb"; import type { UserSimplePeerInterface } from "../WebRtc/SimplePeer"; @@ -45,6 +46,7 @@ import { ItemEventMessageInterface, MessageUserJoined, OnConnectInterface, + PlayerDetailsUpdatedMessageInterface, PlayGlobalMessageInterface, PositionInterface, RoomJoinedMessageInterface, @@ -172,6 +174,9 @@ export class RoomConnection implements RoomConnection { } else if (subMessage.hasEmoteeventmessage()) { const emoteMessage = subMessage.getEmoteeventmessage() as EmoteEventMessage; emoteEventStream.fire(emoteMessage.getActoruserid(), emoteMessage.getEmote()); + } else if (subMessage.hasPlayerdetailsupdatedmessage()) { + event = EventMessage.USER_DETAILS_UPDATED; + payload = subMessage.getPlayerdetailsupdatedmessage(); } else if (subMessage.hasErrormessage()) { const errorMessage = subMessage.getErrormessage() as ErrorMessage; console.error("An error occurred server side: " + errorMessage.getMessage()); @@ -276,7 +281,7 @@ export class RoomConnection implements RoomConnection { } } - public emitPlayerDetailsMessage(userName: string, characterLayersSelected: BodyResourceDescriptionInterface[]) { + /*public emitPlayerDetailsMessage(userName: string, characterLayersSelected: BodyResourceDescriptionInterface[]) { const message = new SetPlayerDetailsMessage(); message.setName(userName); message.setCharacterlayersList(characterLayersSelected.map((characterLayer) => characterLayer.name)); @@ -284,6 +289,20 @@ export class RoomConnection implements RoomConnection { const clientToServerMessage = new ClientToServerMessage(); clientToServerMessage.setSetplayerdetailsmessage(message); + this.socket.send(clientToServerMessage.serializeBinary().buffer); + }*/ + + public emitPlayerOutlineColor(color: number | null) { + const message = new SetPlayerDetailsMessage(); + if (color === null) { + message.setRemoveoutlinecolor(true); + } else { + message.setOutlinecolor(color); + } + + const clientToServerMessage = new ClientToServerMessage(); + clientToServerMessage.setSetplayerdetailsmessage(message); + this.socket.send(clientToServerMessage.serializeBinary().buffer); } @@ -596,6 +615,20 @@ export class RoomConnection implements RoomConnection { }); } + onPlayerDetailsUpdated(callback: (message: PlayerDetailsUpdatedMessageInterface) => void): void { + this.onMessage(EventMessage.USER_DETAILS_UPDATED, (message: PlayerDetailsUpdatedMessage) => { + const details = message.getDetails(); + if (details === undefined) { + throw new Error("Malformed message. Missing details in PlayerDetailsUpdatedMessage"); + } + callback({ + userId: message.getUserid(), + outlineColor: details.getOutlinecolor(), + removeOutlineColor: details.getRemoveoutlinecolor(), + }); + }); + } + public uploadAudio(file: FormData) { return Axios.post(`${UPLOADER_URL}/upload-audio-message`, file) .then((res: { data: {} }) => { diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 3281afe3..98154e37 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -414,8 +414,8 @@ export abstract class Character extends Container { return this._pictureStore; } - public setOutlineColor(red: number, green: number, blue: number): void { - this.outlineColorStore.setColor((red << 16) | (green << 8) | blue); + public setOutlineColor(color: number): void { + this.outlineColorStore.setColor(color); } public removeOutlineColor(): void { diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index abe9137b..99580374 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -55,6 +55,7 @@ import type { MessageUserMovedInterface, MessageUserPositionInterface, OnConnectInterface, + PlayerDetailsUpdatedMessageInterface, PointInterface, PositionInterface, RoomJoinedMessageInterface, @@ -88,6 +89,7 @@ import Tileset = Phaser.Tilemaps.Tileset; import SpriteSheetFile = Phaser.Loader.FileTypes.SpriteSheetFile; import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR; import { MapStore } from "../../Stores/Utils/MapStore"; +import { SetPlayerDetailsMessage } from "../../Messages/generated/messages_pb"; export interface GameSceneInitInterface { initPosition: PointInterface | null; reconnecting: boolean; @@ -123,6 +125,11 @@ interface DeleteGroupEventInterface { groupId: number; } +interface PlayerDetailsUpdatedInterface { + type: "PlayerDetailsUpdated"; + details: PlayerDetailsUpdatedMessageInterface; +} + export class GameScene extends DirtyScene { Terrains: Array; CurrentPlayer!: Player; @@ -135,20 +142,14 @@ export class GameScene extends DirtyScene { groups: Map; circleTexture!: CanvasTexture; circleRedTexture!: CanvasTexture; - pendingEvents: Queue< - | InitUserPositionEventInterface - | AddPlayerEventInterface - | RemovePlayerEventInterface - | UserMovedEventInterface - | GroupCreatedUpdatedEventInterface - | DeleteGroupEventInterface - > = new Queue< + pendingEvents = new Queue< | InitUserPositionEventInterface | AddPlayerEventInterface | RemovePlayerEventInterface | UserMovedEventInterface | GroupCreatedUpdatedEventInterface | DeleteGroupEventInterface + | PlayerDetailsUpdatedInterface >(); private initPosition: PositionInterface | null = null; private playersPositionInterpolator = new PlayersPositionInterpolator(); @@ -735,6 +736,13 @@ export class GameScene extends DirtyScene { item.fire(message.event, message.state, message.parameters); }); + this.connection.onPlayerDetailsUpdated((message) => { + this.pendingEvents.enqueue({ + type: "PlayerDetailsUpdated", + details: message, + }); + }); + /** * Triggered when we receive the JWT token to connect to Jitsi */ @@ -1306,11 +1314,14 @@ ${escapedMessage} const red = normalizeColor(message.red); const green = normalizeColor(message.green); const blue = normalizeColor(message.blue); - this.CurrentPlayer.setOutlineColor(red, green, blue); + const color = (red << 16) | (green << 8) | blue; + this.CurrentPlayer.setOutlineColor(color); + this.connection?.emitPlayerOutlineColor(color); }); iframeListener.registerAnswerer("removePlayerOutline", (message) => { this.CurrentPlayer.removeOutlineColor(); + this.connection?.emitPlayerOutlineColor(null); }); } @@ -1689,6 +1700,11 @@ ${escapedMessage} case "DeleteGroupEvent": this.doDeleteGroup(event.groupId); break; + case "PlayerDetailsUpdated": + this.doUpdatePlayerDetails(event.details); + break; + default: + const tmp: never = event; } } // Let's move all users @@ -1865,6 +1881,23 @@ ${escapedMessage} this.groups.delete(groupId); } + doUpdatePlayerDetails(message: PlayerDetailsUpdatedMessageInterface): void { + const character = this.MapPlayersByKey.get(message.userId); + if (character === undefined) { + console.log( + "Could not set new details to character with ID ", + message.userId, + ". Did he/she left before te message was received?" + ); + return; + } + if (message.removeOutlineColor) { + character.removeOutlineColor(); + } else { + character.setOutlineColor(message.outlineColor); + } + } + /** * Sends to the server an event emitted by one of the ActionableItems. */ diff --git a/front/src/Stores/MediaStore.ts b/front/src/Stores/MediaStore.ts index 44c78ad2..a0f1a92b 100644 --- a/front/src/Stores/MediaStore.ts +++ b/front/src/Stores/MediaStore.ts @@ -365,7 +365,9 @@ function applyCameraConstraints(currentStream: MediaStream | null, constraints: return; } for (const track of currentStream.getVideoTracks()) { - toggleConstraints(track, constraints); + toggleConstraints(track, constraints).catch((e) => + console.error("Error while setting new camera constraints:", e) + ); } } @@ -380,19 +382,21 @@ function applyMicrophoneConstraints( return; } for (const track of currentStream.getAudioTracks()) { - toggleConstraints(track, constraints); + toggleConstraints(track, constraints).catch((e) => + console.error("Error while setting new audio constraints:", e) + ); } } -function toggleConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints | boolean): void { +async function toggleConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints | boolean): Promise { if (implementCorrectTrackBehavior) { track.enabled = constraints !== false; } else if (constraints === false) { track.stop(); } - // @ts-ignore + if (typeof constraints !== "boolean" && constraints !== true) { - track.applyConstraints(constraints); + return track.applyConstraints(constraints); } } @@ -484,7 +488,12 @@ export const localStreamStore = derived, LocalS type: "success", stream: null, }); - initStream(constraints); + initStream(constraints).catch((e) => { + set({ + type: "error", + error: e instanceof Error ? e : new Error("An unknown error happened"), + }); + }); } } else { //on bad navigators like chrome, we have to stop the tracks when we mute and reinstantiate the stream when we need to unmute @@ -496,7 +505,12 @@ export const localStreamStore = derived, LocalS }); } //we reemit the stream if it was muted just to be sure else if (constraints.audio /* && !oldConstraints.audio*/ || (!oldConstraints.video && constraints.video)) { - initStream(constraints); + initStream(constraints).catch((e) => { + set({ + type: "error", + error: e instanceof Error ? e : new Error("An unknown error happened"), + }); + }); } oldConstraints = { video: !!constraints.video, diff --git a/front/src/WebRtc/SimplePeer.ts b/front/src/WebRtc/SimplePeer.ts index 7c575867..ccbd0012 100644 --- a/front/src/WebRtc/SimplePeer.ts +++ b/front/src/WebRtc/SimplePeer.ts @@ -98,7 +98,7 @@ export class SimplePeer { private receiveWebrtcStart(user: UserSimplePeerInterface): void { this.Users.push(user); - // Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joints a group) + // Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joins a group) // So we can receive a request we already had before. (which will abort at the first line of createPeerConnection) // This would be symmetrical to the way we handle disconnection. diff --git a/messages/protos/messages.proto b/messages/protos/messages.proto index d210c42e..c53ec143 100644 --- a/messages/protos/messages.proto +++ b/messages/protos/messages.proto @@ -13,7 +13,6 @@ message PositionMessage { } Direction direction = 3; bool moving = 4; - uint32 outlineColor = 5; } message PointMessage { @@ -48,8 +47,12 @@ message PingMessage { } message SetPlayerDetailsMessage { - string name = 1; - repeated string characterLayers = 2; + //string name = 1; + //repeated string characterLayers = 2; + + // TODO: switch to google.protobuf.Int32Value when we migrate to ts-proto + int32 outlineColor = 3; + bool removeOutlineColor = 4; } message UserMovesMessage { @@ -151,6 +154,7 @@ message SubMessage { EmoteEventMessage emoteEventMessage = 7; VariableMessage variableMessage = 8; ErrorMessage errorMessage = 9; + PlayerDetailsUpdatedMessage playerDetailsUpdatedMessage = 10; } } @@ -333,6 +337,10 @@ message GroupLeftZoneMessage { Zone toZone = 2; } +message PlayerDetailsUpdatedMessage { + int32 userId = 1; + SetPlayerDetailsMessage details = 2; +} message Zone { int32 x = 1; @@ -385,6 +393,7 @@ message SubToPusherMessage { BanUserMessage banUserMessage = 8; EmoteEventMessage emoteEventMessage = 9; ErrorMessage errorMessage = 10; + PlayerDetailsUpdatedMessage playerDetailsUpdatedMessage = 11; } } diff --git a/pusher/src/Model/Zone.ts b/pusher/src/Model/Zone.ts index d5a6058f..e77741aa 100644 --- a/pusher/src/Model/Zone.ts +++ b/pusher/src/Model/Zone.ts @@ -16,6 +16,7 @@ import { EmoteEventMessage, CompanionMessage, ErrorMessage, + PlayerDetailsUpdatedMessage, } from "../Messages/generated/messages_pb"; import { ClientReadableStream } from "grpc"; import { PositionDispatcher } from "_Model/PositionDispatcher"; @@ -32,6 +33,7 @@ export interface ZoneEventListener { onGroupLeaves(groupId: number, listener: ExSocketInterface): void; onEmote(emoteMessage: EmoteEventMessage, listener: ExSocketInterface): void; onError(errorMessage: ErrorMessage, listener: ExSocketInterface): void; + onPlayerDetailsUpdated(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, listener: ExSocketInterface): void; } /*export type EntersCallback = (thing: Movable, listener: User) => void; @@ -219,6 +221,10 @@ export class Zone { } else if (message.hasEmoteeventmessage()) { const emoteEventMessage = message.getEmoteeventmessage() as EmoteEventMessage; this.notifyEmote(emoteEventMessage); + } else if (message.hasPlayerdetailsupdatedmessage()) { + const playerDetailsUpdatedMessage = + message.getPlayerdetailsupdatedmessage() as PlayerDetailsUpdatedMessage; + this.notifyPlayerDetailsUpdated(playerDetailsUpdatedMessage); } else if (message.hasErrormessage()) { const errorMessage = message.getErrormessage() as ErrorMessage; this.notifyError(errorMessage); @@ -308,6 +314,15 @@ export class Zone { } } + private notifyPlayerDetailsUpdated(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage) { + for (const listener of this.listeners) { + if (listener.userId === playerDetailsUpdatedMessage.getUserid()) { + continue; + } + this.socketListener.onPlayerDetailsUpdated(playerDetailsUpdatedMessage, listener); + } + } + private notifyError(errorMessage: ErrorMessage) { for (const listener of this.listeners) { this.socketListener.onError(errorMessage, listener); diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index 703b1cda..5cce5a6e 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -34,6 +34,7 @@ import { VariableMessage, ErrorMessage, WorldFullMessage, + PlayerDetailsUpdatedMessage, } from "../Messages/generated/messages_pb"; import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils"; import { ADMIN_API_URL, JITSI_ISS, JITSI_URL, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable"; @@ -55,6 +56,7 @@ const debug = Debug("socket"); interface AdminSocketRoomsList { [index: string]: number; } + interface AdminSocketUsersList { [index: string]: boolean; } @@ -276,6 +278,16 @@ export class SocketManager implements ZoneEventListener { emitInBatch(listener, subMessage); } + onPlayerDetailsUpdated( + playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, + listener: ExSocketInterface + ): void { + const subMessage = new SubMessage(); + subMessage.setPlayerdetailsupdatedmessage(playerDetailsUpdatedMessage); + + emitInBatch(listener, subMessage); + } + onError(errorMessage: ErrorMessage, listener: ExSocketInterface): void { const subMessage = new SubMessage(); subMessage.setErrormessage(errorMessage);