Global voice-indicators (#2020)
* make use of well known types for PlayerDetailsUpdated message * show voice-chat indicator of people from other groups too * cleanup * check for outline value * do not send outline color if undefined * revert removing LocalVolumeStore * use auto-generated type instead Co-authored-by: Piotr 'pwh' Hanusiak <p.hanusiak@workadventu.re>
This commit is contained in:
parent
2ff7bf54ae
commit
7e84ac5454
@ -210,11 +210,7 @@ export class GameRoom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatePlayerDetails(user: User, playerDetailsMessage: SetPlayerDetailsMessage) {
|
updatePlayerDetails(user: User, playerDetailsMessage: SetPlayerDetailsMessage) {
|
||||||
if (playerDetailsMessage.getRemoveoutlinecolor()) {
|
user.updateDetails(playerDetailsMessage);
|
||||||
user.outlineColor = undefined;
|
|
||||||
} else {
|
|
||||||
user.outlineColor = playerDetailsMessage.getOutlinecolor();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateUserGroup(user: User): void {
|
private updateUserGroup(user: User): void {
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
SubMessage,
|
SubMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { CharacterLayer } from "_Model/Websocket/CharacterLayer";
|
import { CharacterLayer } from "_Model/Websocket/CharacterLayer";
|
||||||
|
import { BoolValue, UInt32Value } from "google-protobuf/google/protobuf/wrappers_pb";
|
||||||
|
|
||||||
export type UserSocket = ServerDuplexStream<PusherToBackMessage, ServerToClientMessage>;
|
export type UserSocket = ServerDuplexStream<PusherToBackMessage, ServerToClientMessage>;
|
||||||
|
|
||||||
@ -37,7 +38,8 @@ export class User implements Movable {
|
|||||||
public readonly name: string,
|
public readonly name: string,
|
||||||
public readonly characterLayers: CharacterLayer[],
|
public readonly characterLayers: CharacterLayer[],
|
||||||
public readonly companion?: CompanionMessage,
|
public readonly companion?: CompanionMessage,
|
||||||
private _outlineColor?: number | undefined
|
private outlineColor?: number,
|
||||||
|
private voiceIndicatorShown?: boolean
|
||||||
) {
|
) {
|
||||||
this.listenedZones = new Set<Zone>();
|
this.listenedZones = new Set<Zone>();
|
||||||
|
|
||||||
@ -83,6 +85,10 @@ export class User implements Movable {
|
|||||||
return this.followedBy.size !== 0;
|
return this.followedBy.size !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getOutlineColor(): number | undefined {
|
||||||
|
return this.outlineColor;
|
||||||
|
}
|
||||||
|
|
||||||
get following(): User | undefined {
|
get following(): User | undefined {
|
||||||
return this._following;
|
return this._following;
|
||||||
}
|
}
|
||||||
@ -115,14 +121,21 @@ export class User implements Movable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public set outlineColor(value: number | undefined) {
|
public updateDetails(details: SetPlayerDetailsMessage) {
|
||||||
this._outlineColor = value;
|
if (details.getRemoveoutlinecolor()) {
|
||||||
|
this.outlineColor = undefined;
|
||||||
|
} else if (details.getOutlinecolor()?.getValue() !== undefined) {
|
||||||
|
this.outlineColor = details.getOutlinecolor()?.getValue();
|
||||||
|
}
|
||||||
|
this.voiceIndicatorShown = details.getShowvoiceindicator()?.getValue();
|
||||||
|
|
||||||
const playerDetails = new SetPlayerDetailsMessage();
|
const playerDetails = new SetPlayerDetailsMessage();
|
||||||
if (value === undefined) {
|
|
||||||
playerDetails.setRemoveoutlinecolor(true);
|
if (this.outlineColor !== undefined) {
|
||||||
} else {
|
playerDetails.setOutlinecolor(new UInt32Value().setValue(this.outlineColor));
|
||||||
playerDetails.setOutlinecolor(value);
|
}
|
||||||
|
if (this.voiceIndicatorShown !== undefined) {
|
||||||
|
playerDetails.setShowvoiceindicator(new BoolValue().setValue(this.voiceIndicatorShown));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.positionNotifier.updatePlayerDetails(this, playerDetails);
|
this.positionNotifier.updatePlayerDetails(this, playerDetails);
|
||||||
|
@ -338,11 +338,12 @@ export class SocketManager {
|
|||||||
userJoinedZoneMessage.setVisitcardurl(thing.visitCardUrl);
|
userJoinedZoneMessage.setVisitcardurl(thing.visitCardUrl);
|
||||||
}
|
}
|
||||||
userJoinedZoneMessage.setCompanion(thing.companion);
|
userJoinedZoneMessage.setCompanion(thing.companion);
|
||||||
if (thing.outlineColor === undefined) {
|
const outlineColor = thing.getOutlineColor();
|
||||||
|
if (outlineColor === undefined) {
|
||||||
userJoinedZoneMessage.setHasoutline(false);
|
userJoinedZoneMessage.setHasoutline(false);
|
||||||
} else {
|
} else {
|
||||||
userJoinedZoneMessage.setHasoutline(true);
|
userJoinedZoneMessage.setHasoutline(true);
|
||||||
userJoinedZoneMessage.setOutlinecolor(thing.outlineColor);
|
userJoinedZoneMessage.setOutlinecolor(outlineColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
const subMessage = new SubToPusherMessage();
|
const subMessage = new SubToPusherMessage();
|
||||||
|
@ -77,12 +77,6 @@ export interface ItemEventMessageInterface {
|
|||||||
parameters: unknown;
|
parameters: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlayerDetailsUpdatedMessageInterface {
|
|
||||||
userId: number;
|
|
||||||
outlineColor: number;
|
|
||||||
removeOutlineColor: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RoomJoinedMessageInterface {
|
export interface RoomJoinedMessageInterface {
|
||||||
//users: MessageUserPositionInterface[],
|
//users: MessageUserPositionInterface[],
|
||||||
//groups: GroupCreatedUpdatedMessageInterface[],
|
//groups: GroupCreatedUpdatedMessageInterface[],
|
||||||
|
@ -504,6 +504,20 @@ export class RoomConnection implements RoomConnection {
|
|||||||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
public emitPlayerShowVoiceIndicator(show: boolean): void {
|
||||||
|
const message = SetPlayerDetailsMessageTsProto.fromPartial({
|
||||||
|
showVoiceIndicator: show,
|
||||||
|
});
|
||||||
|
const bytes = ClientToServerMessageTsProto.encode({
|
||||||
|
message: {
|
||||||
|
$case: "setPlayerDetailsMessage",
|
||||||
|
setPlayerDetailsMessage: message,
|
||||||
|
},
|
||||||
|
}).finish();
|
||||||
|
|
||||||
|
this.socket.send(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
public emitPlayerOutlineColor(color: number | null) {
|
public emitPlayerOutlineColor(color: number | null) {
|
||||||
let message: SetPlayerDetailsMessageTsProto;
|
let message: SetPlayerDetailsMessageTsProto;
|
||||||
if (color === null) {
|
if (color === null) {
|
||||||
|
@ -54,7 +54,6 @@ import type {
|
|||||||
MessageUserMovedInterface,
|
MessageUserMovedInterface,
|
||||||
MessageUserPositionInterface,
|
MessageUserPositionInterface,
|
||||||
OnConnectInterface,
|
OnConnectInterface,
|
||||||
PlayerDetailsUpdatedMessageInterface,
|
|
||||||
PointInterface,
|
PointInterface,
|
||||||
PositionInterface,
|
PositionInterface,
|
||||||
RoomJoinedMessageInterface,
|
RoomJoinedMessageInterface,
|
||||||
@ -102,6 +101,7 @@ import type { VideoPeer } from "../../WebRtc/VideoPeer";
|
|||||||
import CancelablePromise from "cancelable-promise";
|
import CancelablePromise from "cancelable-promise";
|
||||||
import { Deferred } from "ts-deferred";
|
import { Deferred } from "ts-deferred";
|
||||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||||
|
import { PlayerDetailsUpdatedMessage } from "../../Messages/ts-proto-generated/protos/messages";
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
reconnecting: boolean;
|
reconnecting: boolean;
|
||||||
@ -139,7 +139,7 @@ interface DeleteGroupEventInterface {
|
|||||||
|
|
||||||
interface PlayerDetailsUpdatedInterface {
|
interface PlayerDetailsUpdatedInterface {
|
||||||
type: "PlayerDetailsUpdated";
|
type: "PlayerDetailsUpdated";
|
||||||
details: PlayerDetailsUpdatedMessageInterface;
|
details: PlayerDetailsUpdatedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GameScene extends DirtyScene {
|
export class GameScene extends DirtyScene {
|
||||||
@ -175,7 +175,6 @@ export class GameScene extends DirtyScene {
|
|||||||
private emoteUnsubscribe!: Unsubscriber;
|
private emoteUnsubscribe!: Unsubscriber;
|
||||||
private emoteMenuUnsubscribe!: Unsubscriber;
|
private emoteMenuUnsubscribe!: Unsubscriber;
|
||||||
|
|
||||||
private volumeStoreUnsubscribers: Map<number, Unsubscriber> = new Map<number, Unsubscriber>();
|
|
||||||
private localVolumeStoreUnsubscriber: Unsubscriber | undefined;
|
private localVolumeStoreUnsubscriber: Unsubscriber | undefined;
|
||||||
private followUsersColorStoreUnsubscribe!: Unsubscriber;
|
private followUsersColorStoreUnsubscribe!: Unsubscriber;
|
||||||
private currentPlayerGroupIdStoreUnsubscribe!: Unsubscriber;
|
private currentPlayerGroupIdStoreUnsubscribe!: Unsubscriber;
|
||||||
@ -220,6 +219,7 @@ export class GameScene extends DirtyScene {
|
|||||||
private loader: Loader;
|
private loader: Loader;
|
||||||
private lastCameraEvent: WasCameraUpdatedEvent | undefined;
|
private lastCameraEvent: WasCameraUpdatedEvent | undefined;
|
||||||
private firstCameraUpdateSent: boolean = false;
|
private firstCameraUpdateSent: boolean = false;
|
||||||
|
private showVoiceIndicatorChangeMessageSent: boolean = false;
|
||||||
private currentPlayerGroupId?: number;
|
private currentPlayerGroupId?: number;
|
||||||
public readonly superLoad: SuperLoaderPlugin;
|
public readonly superLoad: SuperLoaderPlugin;
|
||||||
|
|
||||||
@ -634,55 +634,43 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const talkIconVolumeTreshold = 10;
|
const talkIconVolumeTreshold = 10;
|
||||||
const oldPeers = new Map<number, VideoPeer>();
|
let oldPeersNumber = 0;
|
||||||
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
||||||
this.volumeStoreUnsubscribers.forEach((unsubscribe) => unsubscribe());
|
|
||||||
this.volumeStoreUnsubscribers.clear();
|
|
||||||
|
|
||||||
for (const [key, videoStream] of peers) {
|
|
||||||
this.volumeStoreUnsubscribers.set(
|
|
||||||
key,
|
|
||||||
videoStream.volumeStore.subscribe((volume) => {
|
|
||||||
if (volume) {
|
|
||||||
this.MapPlayersByKey.get(key)?.showTalkIcon(volume > talkIconVolumeTreshold);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newPeerNumber = peers.size;
|
const newPeerNumber = peers.size;
|
||||||
if (newPeerNumber > oldPeers.size) {
|
if (newPeerNumber > oldPeersNumber) {
|
||||||
this.playSound("audio-webrtc-in");
|
this.playSound("audio-webrtc-in");
|
||||||
} else if (newPeerNumber < oldPeers.size) {
|
} else if (newPeerNumber < oldPeersNumber) {
|
||||||
this.playSound("audio-webrtc-out");
|
this.playSound("audio-webrtc-out");
|
||||||
const oldPeersKeys = oldPeers.keys();
|
|
||||||
const newPeersKeys = Array.from(peers.keys());
|
|
||||||
for (const oldKey of oldPeersKeys) {
|
|
||||||
if (!newPeersKeys.includes(oldKey)) {
|
|
||||||
this.MapPlayersByKey.get(oldKey)?.showTalkIcon(false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (newPeerNumber > 0) {
|
if (newPeerNumber > 0) {
|
||||||
if (!this.localVolumeStoreUnsubscriber) {
|
if (!this.localVolumeStoreUnsubscriber) {
|
||||||
this.localVolumeStoreUnsubscriber = localVolumeStore.subscribe((volume) => {
|
this.localVolumeStoreUnsubscriber = localVolumeStore.subscribe((volume) => {
|
||||||
if (volume) {
|
if (volume === undefined) {
|
||||||
this.CurrentPlayer.showTalkIcon(volume > talkIconVolumeTreshold);
|
return;
|
||||||
|
}
|
||||||
|
const aboveTreshold = volume > talkIconVolumeTreshold;
|
||||||
|
this.CurrentPlayer.showTalkIcon(aboveTreshold);
|
||||||
|
|
||||||
|
if (this.showVoiceIndicatorChangeMessageSent && !aboveTreshold) {
|
||||||
|
this.connection?.emitPlayerShowVoiceIndicator(false);
|
||||||
|
this.showVoiceIndicatorChangeMessageSent = false;
|
||||||
|
} else if (!this.showVoiceIndicatorChangeMessageSent && aboveTreshold) {
|
||||||
|
this.connection?.emitPlayerShowVoiceIndicator(true);
|
||||||
|
this.showVoiceIndicatorChangeMessageSent = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.CurrentPlayer.showTalkIcon(false, true);
|
this.CurrentPlayer.showTalkIcon(false, true);
|
||||||
|
this.connection?.emitPlayerShowVoiceIndicator(false);
|
||||||
|
this.showVoiceIndicatorChangeMessageSent = false;
|
||||||
this.MapPlayersByKey.forEach((remotePlayer) => remotePlayer.showTalkIcon(false, true));
|
this.MapPlayersByKey.forEach((remotePlayer) => remotePlayer.showTalkIcon(false, true));
|
||||||
if (this.localVolumeStoreUnsubscriber) {
|
if (this.localVolumeStoreUnsubscriber) {
|
||||||
this.localVolumeStoreUnsubscriber();
|
this.localVolumeStoreUnsubscriber();
|
||||||
this.localVolumeStoreUnsubscriber = undefined;
|
this.localVolumeStoreUnsubscriber = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oldPeers.clear();
|
oldPeersNumber = peers.size;
|
||||||
for (const [key, val] of peers) {
|
|
||||||
oldPeers.set(key, val);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emoteUnsubscribe = emoteStore.subscribe((emote) => {
|
this.emoteUnsubscribe = emoteStore.subscribe((emote) => {
|
||||||
@ -834,11 +822,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
this.pendingEvents.enqueue({
|
this.pendingEvents.enqueue({
|
||||||
type: "PlayerDetailsUpdated",
|
type: "PlayerDetailsUpdated",
|
||||||
details: {
|
details: message,
|
||||||
userId: message.userId,
|
|
||||||
outlineColor: message.details.outlineColor,
|
|
||||||
removeOutlineColor: message.details.removeOutlineColor,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2070,7 +2054,7 @@ ${escapedMessage}
|
|||||||
this.groups.delete(groupId);
|
this.groups.delete(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
doUpdatePlayerDetails(message: PlayerDetailsUpdatedMessageInterface): void {
|
doUpdatePlayerDetails(message: PlayerDetailsUpdatedMessage): void {
|
||||||
const character = this.MapPlayersByKey.get(message.userId);
|
const character = this.MapPlayersByKey.get(message.userId);
|
||||||
if (character === undefined) {
|
if (character === undefined) {
|
||||||
console.log(
|
console.log(
|
||||||
@ -2080,10 +2064,13 @@ ${escapedMessage}
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (message.removeOutlineColor) {
|
if (message.details?.removeOutlineColor) {
|
||||||
character.removeApiOutlineColor();
|
character.removeApiOutlineColor();
|
||||||
} else {
|
} else if (message.details?.outlineColor !== undefined) {
|
||||||
character.setApiOutlineColor(message.outlineColor);
|
character.setApiOutlineColor(message.details?.outlineColor);
|
||||||
|
}
|
||||||
|
if (message.details?.showVoiceIndicator !== undefined) {
|
||||||
|
character.showTalkIcon(message.details?.showVoiceIndicator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,12 +50,9 @@ message PingMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SetPlayerDetailsMessage {
|
message SetPlayerDetailsMessage {
|
||||||
//string name = 1;
|
google.protobuf.UInt32Value outlineColor = 3;
|
||||||
//repeated string characterLayers = 2;
|
google.protobuf.BoolValue removeOutlineColor = 4;
|
||||||
|
google.protobuf.BoolValue showVoiceIndicator = 5;
|
||||||
// TODO: switch to google.protobuf.Int32Value when we migrate to ts-proto
|
|
||||||
uint32 outlineColor = 3;
|
|
||||||
bool removeOutlineColor = 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message UserMovesMessage {
|
message UserMovesMessage {
|
||||||
|
@ -87,7 +87,7 @@ export class UserDescriptor {
|
|||||||
if (playerDetails.getRemoveoutlinecolor()) {
|
if (playerDetails.getRemoveoutlinecolor()) {
|
||||||
this.outlineColor = undefined;
|
this.outlineColor = undefined;
|
||||||
} else {
|
} else {
|
||||||
this.outlineColor = playerDetails.getOutlinecolor();
|
this.outlineColor = playerDetails.getOutlinecolor()?.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user