Merge branch 'develop' of github.com:thecodingmachine/workadventure into UpdateSetTiles

This commit is contained in:
GRL 2021-07-07 17:00:10 +02:00
commit 41c60579a6
19 changed files with 208 additions and 158 deletions

View file

@ -16,6 +16,7 @@
- Use `WA.room.getCurrentRoom(): Promise<Room>` to get the ID, JSON map file, url of the map of the current room and the layer where the current player started - Use `WA.room.getCurrentRoom(): Promise<Room>` to get the ID, JSON map file, url of the map of the current room and the layer where the current player started
- Use `WA.ui.registerMenuCommand(): void` to add a custom menu - Use `WA.ui.registerMenuCommand(): void` to add a custom menu
- Use `WA.room.setTiles(): void` to change an array of tiles - Use `WA.room.setTiles(): void` to change an array of tiles
- Users blocking now relies on UUID rather than ID. A blocked user that leaves a room and comes back will stay blocked.
## Version 1.4.3 - 1.4.4 - 1.4.5 ## Version 1.4.3 - 1.4.4 - 1.4.5

View file

@ -15,7 +15,7 @@ export class DebugController {
const query = parse(req.getQuery()); const query = parse(req.getQuery());
if (query.token !== ADMIN_API_TOKEN) { if (query.token !== ADMIN_API_TOKEN) {
return res.status(401).send("Invalid token sent!"); return res.writeStatus("401 Unauthorized").end("Invalid token sent!");
} }
return res return res

View file

@ -308,6 +308,7 @@ export class SocketManager {
throw new Error("clientUser.userId is not an integer " + thing.id); throw new Error("clientUser.userId is not an integer " + thing.id);
} }
userJoinedZoneMessage.setUserid(thing.id); userJoinedZoneMessage.setUserid(thing.id);
userJoinedZoneMessage.setUseruuid(thing.uuid);
userJoinedZoneMessage.setName(thing.name); userJoinedZoneMessage.setName(thing.name);
userJoinedZoneMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers)); userJoinedZoneMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers));
userJoinedZoneMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition())); userJoinedZoneMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition()));
@ -425,7 +426,6 @@ export class SocketManager {
// Let's send 2 messages: one to the user joining the group and one to the other user // Let's send 2 messages: one to the user joining the group and one to the other user
const webrtcStartMessage1 = new WebRtcStartMessage(); const webrtcStartMessage1 = new WebRtcStartMessage();
webrtcStartMessage1.setUserid(otherUser.id); webrtcStartMessage1.setUserid(otherUser.id);
webrtcStartMessage1.setName(otherUser.name);
webrtcStartMessage1.setInitiator(true); webrtcStartMessage1.setInitiator(true);
if (TURN_STATIC_AUTH_SECRET !== "") { if (TURN_STATIC_AUTH_SECRET !== "") {
const { username, password } = this.getTURNCredentials("" + otherUser.id, TURN_STATIC_AUTH_SECRET); const { username, password } = this.getTURNCredentials("" + otherUser.id, TURN_STATIC_AUTH_SECRET);
@ -443,7 +443,6 @@ export class SocketManager {
const webrtcStartMessage2 = new WebRtcStartMessage(); const webrtcStartMessage2 = new WebRtcStartMessage();
webrtcStartMessage2.setUserid(user.id); webrtcStartMessage2.setUserid(user.id);
webrtcStartMessage2.setName(user.name);
webrtcStartMessage2.setInitiator(false); webrtcStartMessage2.setInitiator(false);
if (TURN_STATIC_AUTH_SECRET !== "") { if (TURN_STATIC_AUTH_SECRET !== "") {
const { username, password } = this.getTURNCredentials("" + user.id, TURN_STATIC_AUTH_SECRET); const { username, password } = this.getTURNCredentials("" + user.id, TURN_STATIC_AUTH_SECRET);
@ -614,6 +613,7 @@ export class SocketManager {
if (thing instanceof User) { if (thing instanceof User) {
const userJoinedMessage = new UserJoinedZoneMessage(); const userJoinedMessage = new UserJoinedZoneMessage();
userJoinedMessage.setUserid(thing.id); userJoinedMessage.setUserid(thing.id);
userJoinedMessage.setUseruuid(thing.uuid);
userJoinedMessage.setName(thing.name); userJoinedMessage.setName(thing.name);
userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers)); userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers));
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition())); userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition()));

View file

@ -1,8 +1,8 @@
import type {SignalData} from "simple-peer"; import type { SignalData } from "simple-peer";
import type {RoomConnection} from "./RoomConnection"; import type { RoomConnection } from "./RoomConnection";
import type {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures"; import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTextures";
export enum EventMessage{ export enum EventMessage {
CONNECT = "connect", CONNECT = "connect",
WEBRTC_SIGNAL = "webrtc-signal", WEBRTC_SIGNAL = "webrtc-signal",
WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal", WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal",
@ -17,7 +17,7 @@ export enum EventMessage{
GROUP_CREATE_UPDATE = "group-create-update", GROUP_CREATE_UPDATE = "group-create-update",
GROUP_DELETE = "group-delete", GROUP_DELETE = "group-delete",
SET_PLAYER_DETAILS = "set-player-details", // Send the name and character to the server (on connect), receive back the id. SET_PLAYER_DETAILS = "set-player-details", // Send the name and character to the server (on connect), receive back the id.
ITEM_EVENT = 'item-event', ITEM_EVENT = "item-event",
CONNECT_ERROR = "connect_error", CONNECT_ERROR = "connect_error",
CONNECTING_ERROR = "connecting_error", CONNECTING_ERROR = "connecting_error",
@ -36,7 +36,7 @@ export enum EventMessage{
export interface PointInterface { export interface PointInterface {
x: number; x: number;
y: number; y: number;
direction : string; direction: string;
moving: boolean; moving: boolean;
} }
@ -45,8 +45,9 @@ export interface MessageUserPositionInterface {
name: string; name: string;
characterLayers: BodyResourceDescriptionInterface[]; characterLayers: BodyResourceDescriptionInterface[];
position: PointInterface; position: PointInterface;
visitCardUrl: string|null; visitCardUrl: string | null;
companion: string|null; companion: string | null;
userUuid: string;
} }
export interface MessageUserMovedInterface { export interface MessageUserMovedInterface {
@ -60,58 +61,59 @@ export interface MessageUserJoined {
characterLayers: BodyResourceDescriptionInterface[]; characterLayers: BodyResourceDescriptionInterface[];
position: PointInterface; position: PointInterface;
visitCardUrl: string | null; visitCardUrl: string | null;
companion: string|null; companion: string | null;
userUuid: string;
} }
export interface PositionInterface { export interface PositionInterface {
x: number, x: number;
y: number y: number;
} }
export interface GroupCreatedUpdatedMessageInterface { export interface GroupCreatedUpdatedMessageInterface {
position: PositionInterface, position: PositionInterface;
groupId: number, groupId: number;
groupSize: number groupSize: number;
} }
export interface WebRtcDisconnectMessageInterface { export interface WebRtcDisconnectMessageInterface {
userId: number userId: number;
} }
export interface WebRtcSignalReceivedMessageInterface { export interface WebRtcSignalReceivedMessageInterface {
userId: number, userId: number;
signal: SignalData, signal: SignalData;
webRtcUser: string | undefined, webRtcUser: string | undefined;
webRtcPassword: string | undefined webRtcPassword: string | undefined;
} }
export interface ViewportInterface { export interface ViewportInterface {
left: number, left: number;
top: number, top: number;
right: number, right: number;
bottom: number, bottom: number;
} }
export interface ItemEventMessageInterface { export interface ItemEventMessageInterface {
itemId: number, itemId: number;
event: string, event: string;
state: unknown, state: unknown;
parameters: unknown parameters: unknown;
} }
export interface RoomJoinedMessageInterface { export interface RoomJoinedMessageInterface {
//users: MessageUserPositionInterface[], //users: MessageUserPositionInterface[],
//groups: GroupCreatedUpdatedMessageInterface[], //groups: GroupCreatedUpdatedMessageInterface[],
items: { [itemId: number] : unknown } items: { [itemId: number]: unknown };
} }
export interface PlayGlobalMessageInterface { export interface PlayGlobalMessageInterface {
id: string id: string;
type: string type: string;
message: string message: string;
} }
export interface OnConnectInterface { export interface OnConnectInterface {
connection: RoomConnection, connection: RoomConnection;
room: RoomJoinedMessageInterface room: RoomJoinedMessageInterface;
} }

View file

@ -365,6 +365,7 @@ export class RoomConnection implements RoomConnection {
visitCardUrl: message.getVisitcardurl(), visitCardUrl: message.getVisitcardurl(),
position: ProtobufClientUtils.toPointInterface(position), position: ProtobufClientUtils.toPointInterface(position),
companion: companion ? companion.getName() : null, companion: companion ? companion.getName() : null,
userUuid: message.getUseruuid(),
}; };
} }
@ -466,7 +467,6 @@ export class RoomConnection implements RoomConnection {
this.onMessage(EventMessage.WEBRTC_START, (message: WebRtcStartMessage) => { this.onMessage(EventMessage.WEBRTC_START, (message: WebRtcStartMessage) => {
callback({ callback({
userId: message.getUserid(), userId: message.getUserid(),
name: message.getName(),
initiator: message.getInitiator(), initiator: message.getInitiator(),
webRtcUser: message.getWebrtcusername() ?? undefined, webRtcUser: message.getWebrtcusername() ?? undefined,
webRtcPassword: message.getWebrtcpassword() ?? undefined, webRtcPassword: message.getWebrtcpassword() ?? undefined,
@ -592,9 +592,9 @@ export class RoomConnection implements RoomConnection {
this.socket.send(clientToServerMessage.serializeBinary().buffer); this.socket.send(clientToServerMessage.serializeBinary().buffer);
} }
public emitReportPlayerMessage(reportedUserId: number, reportComment: string): void { public emitReportPlayerMessage(reportedUserUuid: string, reportComment: string): void {
const reportPlayerMessage = new ReportPlayerMessage(); const reportPlayerMessage = new ReportPlayerMessage();
reportPlayerMessage.setReporteduserid(reportedUserId); reportPlayerMessage.setReporteduseruuid(reportedUserUuid);
reportPlayerMessage.setReportcomment(reportComment); reportPlayerMessage.setReportcomment(reportComment);
const clientToServerMessage = new ClientToServerMessage(); const clientToServerMessage = new ClientToServerMessage();

View file

@ -1,11 +1,6 @@
import type {PointInterface} from "../../Connexion/ConnexionModels"; import type {PointInterface} from "../../Connexion/ConnexionModels";
import type {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures"; import type {PlayerInterface} from "./PlayerInterface";
export interface AddPlayerInterface { export interface AddPlayerInterface extends PlayerInterface {
userId: number;
name: string;
characterLayers: BodyResourceDescriptionInterface[];
position: PointInterface; position: PointInterface;
visitCardUrl: string|null;
companion: string|null;
} }

View file

@ -91,6 +91,7 @@ import { soundManager } from "./SoundManager";
import { peerStore, screenSharingPeerStore } from "../../Stores/PeerStore"; import { peerStore, screenSharingPeerStore } from "../../Stores/PeerStore";
import { videoFocusStore } from "../../Stores/VideoFocusStore"; import { videoFocusStore } from "../../Stores/VideoFocusStore";
import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStore"; import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStore";
import { playersStore } from "../../Stores/PlayersStore";
export interface GameSceneInitInterface { export interface GameSceneInitInterface {
initPosition: PointInterface | null; initPosition: PointInterface | null;
@ -597,6 +598,8 @@ export class GameScene extends DirtyScene {
.then((onConnect: OnConnectInterface) => { .then((onConnect: OnConnectInterface) => {
this.connection = onConnect.connection; this.connection = onConnect.connection;
playersStore.connectToRoomConnection(this.connection);
this.connection.onUserJoins((message: MessageUserJoined) => { this.connection.onUserJoins((message: MessageUserJoined) => {
const userMessage: AddPlayerInterface = { const userMessage: AddPlayerInterface = {
userId: message.userId, userId: message.userId,
@ -605,6 +608,7 @@ export class GameScene extends DirtyScene {
position: message.position, position: message.position,
visitCardUrl: message.visitCardUrl, visitCardUrl: message.visitCardUrl,
companion: message.companion, companion: message.companion,
userUuid: message.userUuid,
}; };
this.addPlayer(userMessage); this.addPlayer(userMessage);
}); });
@ -1044,7 +1048,7 @@ ${escapedMessage}
}) })
); );
iframeListener.registerAnswerer('getState', () => { iframeListener.registerAnswerer("getState", () => {
return { return {
mapUrl: this.MapUrlFile, mapUrl: this.MapUrlFile,
startLayerName: this.startPositionCalculator.startLayerName, startLayerName: this.startPositionCalculator.startLayerName,
@ -1073,14 +1077,24 @@ ${escapedMessage}
console.warn('Could not find layer "' + layerName + '" when calling setProperty'); console.warn('Could not find layer "' + layerName + '" when calling setProperty');
return; return;
} }
if (propertyName === "exitUrl" && typeof propertyValue === "string") {
this.loadNextGame(propertyValue);
}
if (layer.properties === undefined) { if (layer.properties === undefined) {
layer.properties = []; layer.properties = [];
} }
const property = layer.properties.find((property) => property.name === propertyName); const property = layer.properties.find((property) => property.name === propertyName);
if (property === undefined) { if (property === undefined) {
if (propertyValue === undefined) {
return;
}
layer.properties.push({ name: propertyName, type: typeof propertyValue, value: propertyValue }); layer.properties.push({ name: propertyName, type: typeof propertyValue, value: propertyValue });
return; return;
} }
if (propertyValue === undefined) {
const index = layer.properties.indexOf(property);
layer.properties.splice(index, 1);
}
property.value = propertyValue; property.value = propertyValue;
} }
@ -1147,7 +1161,7 @@ ${escapedMessage}
this.emoteManager.destroy(); this.emoteManager.destroy();
this.peerStoreUnsubscribe(); this.peerStoreUnsubscribe();
this.biggestAvailableAreaStoreUnsubscribe(); this.biggestAvailableAreaStoreUnsubscribe();
iframeListener.unregisterAnswerer('getState'); iframeListener.unregisterAnswerer("getState");
mediaManager.hideGameOverlay(); mediaManager.hideGameOverlay();

View file

@ -0,0 +1,10 @@
import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
export interface PlayerInterface {
userId: number;
name: string;
characterLayers: BodyResourceDescriptionInterface[];
visitCardUrl: string | null;
companion: string | null;
userUuid: string;
}

View file

@ -18,6 +18,7 @@ import { registerMenuCommandStream } from "../../Api/Events/ui/MenuItemRegisterE
import { sendMenuClickedEvent } from "../../Api/iframe/Ui/MenuItem"; import { sendMenuClickedEvent } from "../../Api/iframe/Ui/MenuItem";
import { consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore"; import { consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { playersStore } from "../../Stores/PlayersStore";
export const MenuSceneName = "MenuScene"; export const MenuSceneName = "MenuScene";
const gameMenuKey = "gameMenu"; const gameMenuKey = "gameMenu";
@ -120,7 +121,11 @@ export class MenuScene extends Phaser.Scene {
showReportScreenStore.subscribe((user) => { showReportScreenStore.subscribe((user) => {
if (user !== null) { if (user !== null) {
this.closeAll(); this.closeAll();
this.gameReportElement.open(user.userId, user.userName); const uuid = playersStore.getPlayerById(user.userId)?.userUuid;
if (uuid === undefined) {
throw new Error("Could not find UUID for user with ID " + user.userId);
}
this.gameReportElement.open(uuid, user.userName);
} }
}); });

View file

@ -1,15 +1,16 @@
import {MenuScene} from "./MenuScene"; import { MenuScene } from "./MenuScene";
import {gameManager} from "../Game/GameManager"; import { gameManager } from "../Game/GameManager";
import {blackListManager} from "../../WebRtc/BlackListManager"; import { blackListManager } from "../../WebRtc/BlackListManager";
import { playersStore } from "../../Stores/PlayersStore";
export const gameReportKey = 'gameReport'; export const gameReportKey = "gameReport";
export const gameReportRessource = 'resources/html/gameReport.html'; export const gameReportRessource = "resources/html/gameReport.html";
export class ReportMenu extends Phaser.GameObjects.DOMElement { export class ReportMenu extends Phaser.GameObjects.DOMElement {
private opened: boolean = false; private opened: boolean = false;
private userId!: number; private userUuid!: string;
private userName!: string|undefined; private userName!: string | undefined;
private anonymous: boolean; private anonymous: boolean;
constructor(scene: Phaser.Scene, anonymous: boolean) { constructor(scene: Phaser.Scene, anonymous: boolean) {
@ -18,46 +19,46 @@ export class ReportMenu extends Phaser.GameObjects.DOMElement {
this.createFromCache(gameReportKey); this.createFromCache(gameReportKey);
if (this.anonymous) { if (this.anonymous) {
const divToHide = this.getChildByID('reportSection') as HTMLElement; const divToHide = this.getChildByID("reportSection") as HTMLElement;
divToHide.hidden = true; divToHide.hidden = true;
const textToHide = this.getChildByID('askActionP') as HTMLElement; const textToHide = this.getChildByID("askActionP") as HTMLElement;
textToHide.hidden = true; textToHide.hidden = true;
} }
scene.add.existing(this); scene.add.existing(this);
MenuScene.revealMenusAfterInit(this, gameReportKey); MenuScene.revealMenusAfterInit(this, gameReportKey);
this.addListener('click'); this.addListener("click");
this.on('click', (event:MouseEvent) => { this.on("click", (event: MouseEvent) => {
event.preventDefault(); event.preventDefault();
if ((event?.target as HTMLInputElement).id === 'gameReportFormSubmit') { if ((event?.target as HTMLInputElement).id === "gameReportFormSubmit") {
this.submitReport(); this.submitReport();
} else if((event?.target as HTMLInputElement).id === 'gameReportFormCancel') { } else if ((event?.target as HTMLInputElement).id === "gameReportFormCancel") {
this.close(); this.close();
} else if((event?.target as HTMLInputElement).id === 'toggleBlockButton') { } else if ((event?.target as HTMLInputElement).id === "toggleBlockButton") {
this.toggleBlock(); this.toggleBlock();
} }
}); });
} }
public open(userId: number, userName: string|undefined): void { public open(userUuid: string, userName: string | undefined): void {
if (this.opened) { if (this.opened) {
this.close(); this.close();
return; return;
} }
this.userId = userId; this.userUuid = userUuid;
this.userName = userName; this.userName = userName;
const mainEl = this.getChildByID('gameReport') as HTMLElement; const mainEl = this.getChildByID("gameReport") as HTMLElement;
this.x = this.getCenteredX(mainEl); this.x = this.getCenteredX(mainEl);
this.y = this.getHiddenY(mainEl); this.y = this.getHiddenY(mainEl);
const gameTitleReport = this.getChildByID('nameReported') as HTMLElement; const gameTitleReport = this.getChildByID("nameReported") as HTMLElement;
gameTitleReport.innerText = userName || ''; gameTitleReport.innerText = userName || "";
const blockButton = this.getChildByID('toggleBlockButton') as HTMLElement; const blockButton = this.getChildByID("toggleBlockButton") as HTMLElement;
blockButton.innerText = blackListManager.isBlackListed(this.userId) ? 'Unblock this user' : 'Block this user'; blockButton.innerText = blackListManager.isBlackListed(this.userUuid) ? "Unblock this user" : "Block this user";
this.opened = true; this.opened = true;
@ -67,19 +68,19 @@ export class ReportMenu extends Phaser.GameObjects.DOMElement {
targets: this, targets: this,
y: this.getCenteredY(mainEl), y: this.getCenteredY(mainEl),
duration: 1000, duration: 1000,
ease: 'Power3' ease: "Power3",
}); });
} }
public close(): void { public close(): void {
gameManager.getCurrentGameScene(this.scene).userInputManager.restoreControls(); gameManager.getCurrentGameScene(this.scene).userInputManager.restoreControls();
this.opened = false; this.opened = false;
const mainEl = this.getChildByID('gameReport') as HTMLElement; const mainEl = this.getChildByID("gameReport") as HTMLElement;
this.scene.tweens.add({ this.scene.tweens.add({
targets: this, targets: this,
y: this.getHiddenY(mainEl), y: this.getHiddenY(mainEl),
duration: 1000, duration: 1000,
ease: 'Power3' ease: "Power3",
}); });
} }
@ -88,31 +89,32 @@ export class ReportMenu extends Phaser.GameObjects.DOMElement {
return window.innerWidth / 4 - mainEl.clientWidth / 2; return window.innerWidth / 4 - mainEl.clientWidth / 2;
} }
private getHiddenY(mainEl: HTMLElement): number { private getHiddenY(mainEl: HTMLElement): number {
return - mainEl.clientHeight - 50; return -mainEl.clientHeight - 50;
} }
private getCenteredY(mainEl: HTMLElement): number { private getCenteredY(mainEl: HTMLElement): number {
return window.innerHeight / 4 - mainEl.clientHeight / 2; return window.innerHeight / 4 - mainEl.clientHeight / 2;
} }
private toggleBlock(): void { private toggleBlock(): void {
!blackListManager.isBlackListed(this.userId) ? blackListManager.blackList(this.userId) : blackListManager.cancelBlackList(this.userId); !blackListManager.isBlackListed(this.userUuid)
? blackListManager.blackList(this.userUuid)
: blackListManager.cancelBlackList(this.userUuid);
this.close(); this.close();
} }
private submitReport(): void{ private submitReport(): void {
const gamePError = this.getChildByID('gameReportErr') as HTMLParagraphElement; const gamePError = this.getChildByID("gameReportErr") as HTMLParagraphElement;
gamePError.innerText = ''; gamePError.innerText = "";
gamePError.style.display = 'none'; gamePError.style.display = "none";
const gameTextArea = this.getChildByID('gameReportInput') as HTMLInputElement; const gameTextArea = this.getChildByID("gameReportInput") as HTMLInputElement;
if(!gameTextArea || !gameTextArea.value){ if (!gameTextArea || !gameTextArea.value) {
gamePError.innerText = 'Report message cannot to be empty.'; gamePError.innerText = "Report message cannot to be empty.";
gamePError.style.display = 'block'; gamePError.style.display = "block";
return; return;
} }
gameManager.getCurrentGameScene(this.scene).connection?.emitReportPlayerMessage( gameManager
this.userId, .getCurrentGameScene(this.scene)
gameTextArea.value .connection?.emitReportPlayerMessage(this.userUuid, gameTextArea.value);
);
this.close(); this.close();
} }
} }

View file

@ -0,0 +1,44 @@
import { writable } from "svelte/store";
import type { PlayerInterface } from "../Phaser/Game/PlayerInterface";
import type { RoomConnection } from "../Connexion/RoomConnection";
/**
* A store that contains the list of players currently known.
*/
function createPlayersStore() {
let players = new Map<number, PlayerInterface>();
const { subscribe, set, update } = writable(players);
return {
subscribe,
connectToRoomConnection: (roomConnection: RoomConnection) => {
players = new Map<number, PlayerInterface>();
set(players);
roomConnection.onUserJoins((message) => {
update((users) => {
users.set(message.userId, {
userId: message.userId,
name: message.name,
characterLayers: message.characterLayers,
visitCardUrl: message.visitCardUrl,
companion: message.companion,
userUuid: message.userUuid,
});
return users;
});
});
roomConnection.onUserLeft((userId) => {
update((users) => {
users.delete(userId);
return users;
});
});
},
getPlayerById(userId: number): PlayerInterface | undefined {
return players.get(userId);
},
};
}
export const playersStore = createPlayersStore();

View file

@ -1,24 +1,27 @@
import {Subject} from 'rxjs'; import { Subject } from "rxjs";
class BlackListManager { class BlackListManager {
private list: number[] = []; private list: string[] = [];
public onBlockStream: Subject<number> = new Subject(); public onBlockStream: Subject<string> = new Subject();
public onUnBlockStream: Subject<number> = new Subject(); public onUnBlockStream: Subject<string> = new Subject();
isBlackListed(userId: number): boolean { isBlackListed(userUuid: string): boolean {
return this.list.find((data) => data === userId) !== undefined; return this.list.find((data) => data === userUuid) !== undefined;
}
blackList(userId: number): void {
if (this.isBlackListed(userId)) return;
this.list.push(userId);
this.onBlockStream.next(userId);
} }
cancelBlackList(userId: number): void { blackList(userUuid: string): void {
this.list.splice(this.list.findIndex(data => data === userId), 1); if (this.isBlackListed(userUuid)) return;
this.onUnBlockStream.next(userId); this.list.push(userUuid);
this.onBlockStream.next(userUuid);
}
cancelBlackList(userUuid: string): void {
this.list.splice(
this.list.findIndex((data) => data === userUuid),
1
);
this.onUnBlockStream.next(userUuid);
} }
} }
export const blackListManager = new BlackListManager(); export const blackListManager = new BlackListManager();

View file

@ -25,7 +25,7 @@ export class HtmlUtils {
} }
public static escapeHtml(html: string): string { public static escapeHtml(html: string): string {
const text = document.createTextNode(html); const text = document.createTextNode(html.replace(/(\r\n|\r|\n)/g,'<br/>'));
const p = document.createElement('p'); const p = document.createElement('p');
p.appendChild(text); p.appendChild(text);
return p.innerHTML; return p.innerHTML;

View file

@ -11,10 +11,10 @@ import { get } from "svelte/store";
import { localStreamStore, LocalStreamStoreValue, obtainedMediaConstraintStore } from "../Stores/MediaStore"; import { localStreamStore, LocalStreamStoreValue, obtainedMediaConstraintStore } from "../Stores/MediaStore";
import { screenSharingLocalStreamStore } from "../Stores/ScreenSharingStore"; import { screenSharingLocalStreamStore } from "../Stores/ScreenSharingStore";
import { discussionManager } from "./DiscussionManager"; import { discussionManager } from "./DiscussionManager";
import { playersStore } from "../Stores/PlayersStore";
export interface UserSimplePeerInterface { export interface UserSimplePeerInterface {
userId: number; userId: number;
name?: string;
initiator?: boolean; initiator?: boolean;
webRtcUser?: string | undefined; webRtcUser?: string | undefined;
webRtcPassword?: string | undefined; webRtcPassword?: string | undefined;
@ -153,10 +153,7 @@ export class SimplePeer {
} }
} }
let name = user.name; const name = this.getName(user.userId);
if (!name) {
name = this.getName(user.userId);
}
discussionManager.removeParticipant(user.userId); discussionManager.removeParticipant(user.userId);
@ -191,7 +188,7 @@ export class SimplePeer {
//Create a notification for first user in circle discussion //Create a notification for first user in circle discussion
if (this.PeerConnectionArray.size === 0) { if (this.PeerConnectionArray.size === 0) {
mediaManager.createNotification(user.name ?? ""); mediaManager.createNotification(name);
} }
this.PeerConnectionArray.set(user.userId, peer); this.PeerConnectionArray.set(user.userId, peer);
@ -202,12 +199,7 @@ export class SimplePeer {
} }
private getName(userId: number): string { private getName(userId: number): string {
const userSearch = this.Users.find((userSearch: UserSimplePeerInterface) => userSearch.userId === userId); return playersStore.getPlayerById(userId)?.name || "";
if (userSearch) {
return userSearch.name || "";
} else {
return "";
}
} }
/** /**
@ -372,7 +364,8 @@ export class SimplePeer {
} }
private receiveWebrtcScreenSharingSignal(data: WebRtcSignalReceivedMessageInterface) { private receiveWebrtcScreenSharingSignal(data: WebRtcSignalReceivedMessageInterface) {
if (blackListManager.isBlackListed(data.userId)) return; const uuid = playersStore.getPlayerById(data.userId)?.userUuid || "";
if (blackListManager.isBlackListed(uuid)) return;
console.log("receiveWebrtcScreenSharingSignal", data); console.log("receiveWebrtcScreenSharingSignal", data);
const streamResult = get(screenSharingLocalStreamStore); const streamResult = get(screenSharingLocalStreamStore);
let stream: MediaStream | null = null; let stream: MediaStream | null = null;
@ -473,7 +466,8 @@ export class SimplePeer {
} }
private sendLocalScreenSharingStreamToUser(userId: number, localScreenCapture: MediaStream): void { private sendLocalScreenSharingStreamToUser(userId: number, localScreenCapture: MediaStream): void {
if (blackListManager.isBlackListed(userId)) return; const uuid = playersStore.getPlayerById(userId)?.userUuid || "";
if (blackListManager.isBlackListed(uuid)) return;
// If a connection already exists with user (because it is already sharing a screen with us... let's use this connection) // If a connection already exists with user (because it is already sharing a screen with us... let's use this connection)
if (this.PeerScreenSharingConnectionArray.has(userId)) { if (this.PeerScreenSharingConnectionArray.has(userId)) {
this.pushScreenSharingToRemoteUser(userId, localScreenCapture); this.pushScreenSharingToRemoteUser(userId, localScreenCapture);

View file

@ -8,6 +8,7 @@ import type { UserSimplePeerInterface } from "./SimplePeer";
import { get, readable, Readable } from "svelte/store"; import { get, readable, Readable } from "svelte/store";
import { obtainedMediaConstraintStore } from "../Stores/MediaStore"; import { obtainedMediaConstraintStore } from "../Stores/MediaStore";
import { discussionManager } from "./DiscussionManager"; import { discussionManager } from "./DiscussionManager";
import { playersStore } from "../Stores/PlayersStore";
const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer"); const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer");
@ -26,6 +27,7 @@ export class VideoPeer extends Peer {
private remoteStream!: MediaStream; private remoteStream!: MediaStream;
private blocked: boolean = false; private blocked: boolean = false;
public readonly userId: number; public readonly userId: number;
public readonly userUuid: string;
public readonly uniqueId: string; public readonly uniqueId: string;
private onBlockSubscribe: Subscription; private onBlockSubscribe: Subscription;
private onUnBlockSubscribe: Subscription; private onUnBlockSubscribe: Subscription;
@ -60,6 +62,7 @@ export class VideoPeer extends Peer {
}); });
this.userId = user.userId; this.userId = user.userId;
this.userUuid = playersStore.getPlayerById(this.userId)?.userUuid || "";
this.uniqueId = "video_" + this.userId; this.uniqueId = "video_" + this.userId;
this.streamStore = readable<MediaStream | null>(null, (set) => { this.streamStore = readable<MediaStream | null>(null, (set) => {
@ -181,20 +184,20 @@ export class VideoPeer extends Peer {
}); });
this.pushVideoToRemoteUser(localStream); this.pushVideoToRemoteUser(localStream);
this.onBlockSubscribe = blackListManager.onBlockStream.subscribe((userId) => { this.onBlockSubscribe = blackListManager.onBlockStream.subscribe((userUuid) => {
if (userId === this.userId) { if (userUuid === this.userUuid) {
this.toggleRemoteStream(false); this.toggleRemoteStream(false);
this.sendBlockMessage(true); this.sendBlockMessage(true);
} }
}); });
this.onUnBlockSubscribe = blackListManager.onUnBlockStream.subscribe((userId) => { this.onUnBlockSubscribe = blackListManager.onUnBlockStream.subscribe((userUuid) => {
if (userId === this.userId) { if (userUuid === this.userUuid) {
this.toggleRemoteStream(true); this.toggleRemoteStream(true);
this.sendBlockMessage(false); this.sendBlockMessage(false);
} }
}); });
if (blackListManager.isBlackListed(this.userId)) { if (blackListManager.isBlackListed(this.userUuid)) {
this.sendBlockMessage(true); this.sendBlockMessage(true);
} }
} }
@ -231,7 +234,7 @@ export class VideoPeer extends Peer {
private stream(stream: MediaStream) { private stream(stream: MediaStream) {
try { try {
this.remoteStream = stream; this.remoteStream = stream;
if (blackListManager.isBlackListed(this.userId) || this.blocked) { if (blackListManager.isBlackListed(this.userUuid) || this.blocked) {
this.toggleRemoteStream(false); this.toggleRemoteStream(false);
} }
} catch (err) { } catch (err) {

View file

@ -62,7 +62,7 @@ message WebRtcSignalToServerMessage {
} }
message ReportPlayerMessage { message ReportPlayerMessage {
int32 reportedUserId = 1; string reportedUserUuid = 1;
string reportComment = 2; string reportComment = 2;
} }
@ -158,6 +158,7 @@ message UserJoinedMessage {
PositionMessage position = 4; PositionMessage position = 4;
CompanionMessage companion = 5; CompanionMessage companion = 5;
string visitCardUrl = 6; string visitCardUrl = 6;
string userUuid = 7;
} }
message UserLeftMessage { message UserLeftMessage {
@ -183,7 +184,6 @@ message RoomJoinedMessage {
message WebRtcStartMessage { message WebRtcStartMessage {
int32 userId = 1; int32 userId = 1;
string name = 2;
bool initiator = 3; bool initiator = 3;
string webrtcUserName = 4; string webrtcUserName = 4;
string webrtcPassword = 5; string webrtcPassword = 5;
@ -257,7 +257,7 @@ message ServerToClientMessage {
AdminRoomMessage adminRoomMessage = 14; AdminRoomMessage adminRoomMessage = 14;
WorldFullWarningMessage worldFullWarningMessage = 15; WorldFullWarningMessage worldFullWarningMessage = 15;
WorldFullMessage worldFullMessage = 16; WorldFullMessage worldFullMessage = 16;
RefreshRoomMessage refreshRoomMessage = 17; RefreshRoomMessage refreshRoomMessage = 17;
WorldConnexionMessage worldConnexionMessage = 18; WorldConnexionMessage worldConnexionMessage = 18;
EmoteEventMessage emoteEventMessage = 19; EmoteEventMessage emoteEventMessage = 19;
} }
@ -286,6 +286,7 @@ message UserJoinedZoneMessage {
Zone fromZone = 5; Zone fromZone = 5;
CompanionMessage companion = 6; CompanionMessage companion = 6;
string visitCardUrl = 7; string visitCardUrl = 7;
string userUuid = 8;
} }
message UserLeftZoneMessage { message UserLeftZoneMessage {

View file

@ -16,7 +16,7 @@ export class DebugController {
const query = parse(req.getQuery()); const query = parse(req.getQuery());
if (query.token !== ADMIN_API_TOKEN) { if (query.token !== ADMIN_API_TOKEN) {
return res.status(401).send("Invalid token sent!"); return res.writeStatus("401 Unauthorized").end("Invalid token sent!");
} }
return res return res

View file

@ -39,6 +39,7 @@ export type LeavesCallback = (thing: Movable, listener: User) => void;*/
export class UserDescriptor { export class UserDescriptor {
private constructor( private constructor(
public readonly userId: number, public readonly userId: number,
private userUuid: string,
private name: string, private name: string,
private characterLayers: CharacterLayerMessage[], private characterLayers: CharacterLayerMessage[],
private position: PositionMessage, private position: PositionMessage,
@ -57,6 +58,7 @@ export class UserDescriptor {
} }
return new UserDescriptor( return new UserDescriptor(
message.getUserid(), message.getUserid(),
message.getUseruuid(),
message.getName(), message.getName(),
message.getCharacterlayersList(), message.getCharacterlayersList(),
position, position,
@ -84,6 +86,7 @@ export class UserDescriptor {
userJoinedMessage.setVisitcardurl(this.visitCardUrl); userJoinedMessage.setVisitcardurl(this.visitCardUrl);
} }
userJoinedMessage.setCompanion(this.companion); userJoinedMessage.setCompanion(this.companion);
userJoinedMessage.setUseruuid(this.userUuid);
return userJoinedMessage; return userJoinedMessage;
} }

View file

@ -61,7 +61,6 @@ export interface AdminSocketData {
export class SocketManager implements ZoneEventListener { export class SocketManager implements ZoneEventListener {
private rooms: Map<string, PusherRoom> = new Map<string, PusherRoom>(); private rooms: Map<string, PusherRoom> = new Map<string, PusherRoom>();
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
constructor() { constructor() {
clientEventsEmitter.registerToClientJoin((clientUUid: string, roomId: string) => { clientEventsEmitter.registerToClientJoin((clientUUid: string, roomId: string) => {
@ -191,8 +190,6 @@ export class SocketManager implements ZoneEventListener {
.on("data", (message: ServerToClientMessage) => { .on("data", (message: ServerToClientMessage) => {
if (message.hasRoomjoinedmessage()) { if (message.hasRoomjoinedmessage()) {
client.userId = (message.getRoomjoinedmessage() as RoomJoinedMessage).getCurrentuserid(); client.userId = (message.getRoomjoinedmessage() as RoomJoinedMessage).getCurrentuserid();
// TODO: do we need this.sockets anymore?
this.sockets.set(client.userId, client);
// If this is the first message sent, send back the viewport. // If this is the first message sent, send back the viewport.
this.handleViewport(client, viewport); this.handleViewport(client, viewport);
@ -302,14 +299,8 @@ export class SocketManager implements ZoneEventListener {
async handleReportMessage(client: ExSocketInterface, reportPlayerMessage: ReportPlayerMessage) { async handleReportMessage(client: ExSocketInterface, reportPlayerMessage: ReportPlayerMessage) {
try { try {
const reportedSocket = this.sockets.get(reportPlayerMessage.getReporteduserid());
if (!reportedSocket) {
throw "reported socket user not found";
}
//TODO report user on admin application
//todo: move to back because this fail if the reported player is in another pusher.
await adminApi.reportPlayer( await adminApi.reportPlayer(
reportedSocket.userUuid, reportPlayerMessage.getReporteduseruuid(),
reportPlayerMessage.getReportcomment(), reportPlayerMessage.getReportcomment(),
client.userUuid, client.userUuid,
client.roomId.split("/")[2] client.roomId.split("/")[2]
@ -334,14 +325,6 @@ export class SocketManager implements ZoneEventListener {
socket.backConnection.write(pusherToBackMessage); socket.backConnection.write(pusherToBackMessage);
} }
private searchClientByIdOrFail(userId: number): ExSocketInterface {
const client: ExSocketInterface | undefined = this.sockets.get(userId);
if (client === undefined) {
throw new Error("Could not find user with id " + userId);
}
return client;
}
leaveRoom(socket: ExSocketInterface) { leaveRoom(socket: ExSocketInterface) {
// leave previous room and world // leave previous room and world
try { try {
@ -364,9 +347,8 @@ export class SocketManager implements ZoneEventListener {
//Client.leave(Client.roomId); //Client.leave(Client.roomId);
} finally { } finally {
//delete Client.roomId; //delete Client.roomId;
this.sockets.delete(socket.userId);
clientEventsEmitter.emitClientLeave(socket.userUuid, socket.roomId); clientEventsEmitter.emitClientLeave(socket.userUuid, socket.roomId);
console.log("A user left (", this.sockets.size, " connected users)"); console.log("A user left");
} }
} }
} finally { } finally {
@ -410,15 +392,6 @@ export class SocketManager implements ZoneEventListener {
return this.rooms; return this.rooms;
} }
searchClientByUuid(uuid: string): ExSocketInterface | null {
for (const socket of this.sockets.values()) {
if (socket.userUuid === uuid) {
return socket;
}
}
return null;
}
public handleQueryJitsiJwtMessage(client: ExSocketInterface, queryJitsiJwtMessage: QueryJitsiJwtMessage) { public handleQueryJitsiJwtMessage(client: ExSocketInterface, queryJitsiJwtMessage: QueryJitsiJwtMessage) {
try { try {
const room = queryJitsiJwtMessage.getJitsiroom(); const room = queryJitsiJwtMessage.getJitsiroom();