Merge branch 'develop' of github.com:thecodingmachine/workadventure into twemojiEmoteMenu
This commit is contained in:
commit
83bd19c8dc
163 changed files with 5252 additions and 3394 deletions
|
@ -38,11 +38,9 @@ class ConnectionManager {
|
|||
this.localUser = new LocalUser(data.userUuid, data.authToken, data.textures);
|
||||
localUserStore.saveUser(this.localUser);
|
||||
|
||||
const organizationSlug = data.organizationSlug;
|
||||
const worldSlug = data.worldSlug;
|
||||
const roomSlug = data.roomSlug;
|
||||
const roomUrl = data.roomUrl;
|
||||
|
||||
const room = new Room('/@/'+organizationSlug+'/'+worldSlug+'/'+roomSlug + window.location.search + window.location.hash);
|
||||
const room = await Room.createRoom(new URL(window.location.protocol + '//' + window.location.host + roomUrl + window.location.search + window.location.hash));
|
||||
urlManager.pushRoomIdToUrl(room);
|
||||
return Promise.resolve(room);
|
||||
} else if (connexionType === GameConnexionTypes.organization || connexionType === GameConnexionTypes.anonymous || connexionType === GameConnexionTypes.empty) {
|
||||
|
@ -66,22 +64,21 @@ class ConnectionManager {
|
|||
throw "Error to store local user data";
|
||||
}
|
||||
|
||||
let roomId: string;
|
||||
let roomPath: string;
|
||||
if (connexionType === GameConnexionTypes.empty) {
|
||||
roomId = START_ROOM_URL;
|
||||
roomPath = window.location.protocol + '//' + window.location.host + START_ROOM_URL;
|
||||
} else {
|
||||
roomId = window.location.pathname + window.location.search + window.location.hash;
|
||||
roomPath = window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search + window.location.hash;
|
||||
}
|
||||
|
||||
//get detail map for anonymous login and set texture in local storage
|
||||
const room = new Room(roomId);
|
||||
const mapDetail = await room.getMapDetail();
|
||||
if(mapDetail.textures != undefined && mapDetail.textures.length > 0) {
|
||||
const room = await Room.createRoom(new URL(roomPath));
|
||||
if(room.textures != undefined && room.textures.length > 0) {
|
||||
//check if texture was changed
|
||||
if(localUser.textures.length === 0){
|
||||
localUser.textures = mapDetail.textures;
|
||||
localUser.textures = room.textures;
|
||||
}else{
|
||||
mapDetail.textures.forEach((newTexture) => {
|
||||
room.textures.forEach((newTexture) => {
|
||||
const alreadyExistTexture = localUser?.textures.find((c) => newTexture.id === c.id);
|
||||
if(localUser?.textures.findIndex((c) => newTexture.id === c.id) !== -1){
|
||||
return;
|
||||
|
@ -114,9 +111,9 @@ class ConnectionManager {
|
|||
this.localUser = new LocalUser('', 'test', []);
|
||||
}
|
||||
|
||||
public connectToRoomSocket(roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface, companion: string|null): Promise<OnConnectInterface> {
|
||||
public connectToRoomSocket(roomUrl: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface, companion: string|null): Promise<OnConnectInterface> {
|
||||
return new Promise<OnConnectInterface>((resolve, reject) => {
|
||||
const connection = new RoomConnection(this.localUser.jwtToken, roomId, name, characterLayers, position, viewport, companion);
|
||||
const connection = new RoomConnection(this.localUser.jwtToken, roomUrl, name, characterLayers, position, viewport, companion);
|
||||
connection.onConnectError((error: object) => {
|
||||
console.log('An error occurred while connecting to socket server. Retrying');
|
||||
reject(error);
|
||||
|
@ -137,7 +134,7 @@ class ConnectionManager {
|
|||
this.reconnectingTimeout = setTimeout(() => {
|
||||
//todo: allow a way to break recursion?
|
||||
//todo: find a way to avoid recursive function. Otherwise, the call stack will grow indefinitely.
|
||||
this.connectToRoomSocket(roomId, name, characterLayers, position, viewport, companion).then((connection) => resolve(connection));
|
||||
this.connectToRoomSocket(roomUrl, name, characterLayers, position, viewport, companion).then((connection) => resolve(connection));
|
||||
}, 4000 + Math.floor(Math.random() * 2000) );
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type {SignalData} from "simple-peer";
|
||||
import type {RoomConnection} from "./RoomConnection";
|
||||
import type {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures";
|
||||
import type { SignalData } from "simple-peer";
|
||||
import type { RoomConnection } from "./RoomConnection";
|
||||
import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTextures";
|
||||
|
||||
export enum EventMessage{
|
||||
export enum EventMessage {
|
||||
CONNECT = "connect",
|
||||
WEBRTC_SIGNAL = "webrtc-signal",
|
||||
WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal",
|
||||
|
@ -17,7 +17,7 @@ export enum EventMessage{
|
|||
GROUP_CREATE_UPDATE = "group-create-update",
|
||||
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',
|
||||
ITEM_EVENT = "item-event",
|
||||
|
||||
CONNECT_ERROR = "connect_error",
|
||||
CONNECTING_ERROR = "connecting_error",
|
||||
|
@ -36,7 +36,7 @@ export enum EventMessage{
|
|||
export interface PointInterface {
|
||||
x: number;
|
||||
y: number;
|
||||
direction : string;
|
||||
direction: string;
|
||||
moving: boolean;
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,9 @@ export interface MessageUserPositionInterface {
|
|||
name: string;
|
||||
characterLayers: BodyResourceDescriptionInterface[];
|
||||
position: PointInterface;
|
||||
visitCardUrl: string|null;
|
||||
companion: string|null;
|
||||
visitCardUrl: string | null;
|
||||
companion: string | null;
|
||||
userUuid: string;
|
||||
}
|
||||
|
||||
export interface MessageUserMovedInterface {
|
||||
|
@ -60,58 +61,59 @@ export interface MessageUserJoined {
|
|||
characterLayers: BodyResourceDescriptionInterface[];
|
||||
position: PointInterface;
|
||||
visitCardUrl: string | null;
|
||||
companion: string|null;
|
||||
companion: string | null;
|
||||
userUuid: string;
|
||||
}
|
||||
|
||||
export interface PositionInterface {
|
||||
x: number,
|
||||
y: number
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface GroupCreatedUpdatedMessageInterface {
|
||||
position: PositionInterface,
|
||||
groupId: number,
|
||||
groupSize: number
|
||||
position: PositionInterface;
|
||||
groupId: number;
|
||||
groupSize: number;
|
||||
}
|
||||
|
||||
export interface WebRtcDisconnectMessageInterface {
|
||||
userId: number
|
||||
userId: number;
|
||||
}
|
||||
|
||||
export interface WebRtcSignalReceivedMessageInterface {
|
||||
userId: number,
|
||||
signal: SignalData,
|
||||
webRtcUser: string | undefined,
|
||||
webRtcPassword: string | undefined
|
||||
userId: number;
|
||||
signal: SignalData;
|
||||
webRtcUser: string | undefined;
|
||||
webRtcPassword: string | undefined;
|
||||
}
|
||||
|
||||
export interface ViewportInterface {
|
||||
left: number,
|
||||
top: number,
|
||||
right: number,
|
||||
bottom: number,
|
||||
left: number;
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
}
|
||||
|
||||
export interface ItemEventMessageInterface {
|
||||
itemId: number,
|
||||
event: string,
|
||||
state: unknown,
|
||||
parameters: unknown
|
||||
itemId: number;
|
||||
event: string;
|
||||
state: unknown;
|
||||
parameters: unknown;
|
||||
}
|
||||
|
||||
export interface RoomJoinedMessageInterface {
|
||||
//users: MessageUserPositionInterface[],
|
||||
//groups: GroupCreatedUpdatedMessageInterface[],
|
||||
items: { [itemId: number] : unknown }
|
||||
items: { [itemId: number]: unknown };
|
||||
}
|
||||
|
||||
export interface PlayGlobalMessageInterface {
|
||||
id: string
|
||||
type: string
|
||||
message: string
|
||||
id: string;
|
||||
type: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface OnConnectInterface {
|
||||
connection: RoomConnection,
|
||||
room: RoomJoinedMessageInterface
|
||||
connection: RoomConnection;
|
||||
room: RoomJoinedMessageInterface;
|
||||
}
|
||||
|
|
|
@ -1,90 +1,105 @@
|
|||
import Axios from "axios";
|
||||
import {PUSHER_URL} from "../Enum/EnvironmentVariable";
|
||||
import type {CharacterTexture} from "./LocalUser";
|
||||
import { PUSHER_URL } from "../Enum/EnvironmentVariable";
|
||||
import type { CharacterTexture } from "./LocalUser";
|
||||
|
||||
export class MapDetail{
|
||||
constructor(public readonly mapUrl: string, public readonly textures : CharacterTexture[]|undefined) {
|
||||
}
|
||||
export class MapDetail {
|
||||
constructor(public readonly mapUrl: string, public readonly textures: CharacterTexture[] | undefined) {}
|
||||
}
|
||||
|
||||
export interface RoomRedirect {
|
||||
redirectUrl: string;
|
||||
}
|
||||
|
||||
export class Room {
|
||||
public readonly id: string;
|
||||
public readonly isPublic: boolean;
|
||||
private mapUrl: string|undefined;
|
||||
private textures: CharacterTexture[]|undefined;
|
||||
private instance: string|undefined;
|
||||
private _search: URLSearchParams;
|
||||
private _mapUrl: string | undefined;
|
||||
private _textures: CharacterTexture[] | undefined;
|
||||
private instance: string | undefined;
|
||||
private readonly _search: URLSearchParams;
|
||||
|
||||
constructor(id: string) {
|
||||
const url = new URL(id, 'https://example.com');
|
||||
private constructor(private roomUrl: URL) {
|
||||
this.id = roomUrl.pathname;
|
||||
|
||||
this.id = url.pathname;
|
||||
|
||||
if (this.id.startsWith('/')) {
|
||||
if (this.id.startsWith("/")) {
|
||||
this.id = this.id.substr(1);
|
||||
}
|
||||
if (this.id.startsWith('_/')) {
|
||||
if (this.id.startsWith("_/")) {
|
||||
this.isPublic = true;
|
||||
} else if (this.id.startsWith('@/')) {
|
||||
} else if (this.id.startsWith("@/")) {
|
||||
this.isPublic = false;
|
||||
} else {
|
||||
throw new Error('Invalid room ID');
|
||||
throw new Error("Invalid room ID");
|
||||
}
|
||||
|
||||
this._search = new URLSearchParams(url.search);
|
||||
this._search = new URLSearchParams(roomUrl.search);
|
||||
}
|
||||
|
||||
public static getIdFromIdentifier(identifier: string, baseUrl: string, currentInstance: string): {roomId: string, hash: string} {
|
||||
let roomId = '';
|
||||
let hash = '';
|
||||
if (!identifier.startsWith('/_/') && !identifier.startsWith('/@/')) { //relative file link
|
||||
//Relative identifier can be deep enough to rewrite the base domain, so we cannot use the variable 'baseUrl' as the actual base url for the URL objects.
|
||||
//We instead use 'workadventure' as a dummy base value.
|
||||
const baseUrlObject = new URL(baseUrl);
|
||||
const absoluteExitSceneUrl = new URL(identifier, 'http://workadventure/_/'+currentInstance+'/'+baseUrlObject.hostname+baseUrlObject.pathname);
|
||||
roomId = absoluteExitSceneUrl.pathname; //in case of a relative url, we need to create a public roomId
|
||||
roomId = roomId.substring(1); //remove the leading slash
|
||||
hash = absoluteExitSceneUrl.hash;
|
||||
hash = hash.substring(1); //remove the leading diese
|
||||
} else { //absolute room Id
|
||||
const parts = identifier.split('#');
|
||||
roomId = parts[0];
|
||||
roomId = roomId.substring(1); //remove the leading slash
|
||||
if (parts.length > 1) {
|
||||
hash = parts[1]
|
||||
/**
|
||||
* Creates a "Room" object representing the room.
|
||||
* This method will follow room redirects if necessary, so the instance returned is a "real" room.
|
||||
*/
|
||||
public static async createRoom(roomUrl: URL): Promise<Room> {
|
||||
let redirectCount = 0;
|
||||
while (redirectCount < 32) {
|
||||
const room = new Room(roomUrl);
|
||||
const result = await room.getMapDetail();
|
||||
if (result instanceof MapDetail) {
|
||||
return room;
|
||||
}
|
||||
redirectCount++;
|
||||
roomUrl = new URL(result.redirectUrl);
|
||||
}
|
||||
return {roomId, hash}
|
||||
throw new Error("Room resolving seems stuck in a redirect loop after 32 redirect attempts");
|
||||
}
|
||||
|
||||
public async getMapDetail(): Promise<MapDetail> {
|
||||
return new Promise<MapDetail>((resolve, reject) => {
|
||||
if (this.mapUrl !== undefined && this.textures != undefined) {
|
||||
resolve(new MapDetail(this.mapUrl, this.textures));
|
||||
return;
|
||||
}
|
||||
public static getRoomPathFromExitUrl(exitUrl: string, currentRoomUrl: string): URL {
|
||||
const url = new URL(exitUrl, currentRoomUrl);
|
||||
return url;
|
||||
}
|
||||
|
||||
if (this.isPublic) {
|
||||
const match = /_\/[^/]+\/(.+)/.exec(this.id);
|
||||
if (!match) throw new Error('Could not extract url from "'+this.id+'"');
|
||||
this.mapUrl = window.location.protocol+'//'+match[1];
|
||||
resolve(new MapDetail(this.mapUrl, this.textures));
|
||||
return;
|
||||
} else {
|
||||
// We have a private ID, we need to query the map URL from the server.
|
||||
const urlParts = this.parsePrivateUrl(this.id);
|
||||
/**
|
||||
* @deprecated USage of exitSceneUrl is deprecated and therefore, this method is deprecated too.
|
||||
*/
|
||||
public static getRoomPathFromExitSceneUrl(
|
||||
exitSceneUrl: string,
|
||||
currentRoomUrl: string,
|
||||
currentMapUrl: string
|
||||
): URL {
|
||||
const absoluteExitSceneUrl = new URL(exitSceneUrl, currentMapUrl);
|
||||
const baseUrl = new URL(currentRoomUrl);
|
||||
|
||||
Axios.get(`${PUSHER_URL}/map`, {
|
||||
params: urlParts
|
||||
}).then(({data}) => {
|
||||
console.log('Map ', this.id, ' resolves to URL ', data.mapUrl);
|
||||
resolve(data);
|
||||
return;
|
||||
}).catch((reason) => {
|
||||
reject(reason);
|
||||
});
|
||||
}
|
||||
const currentRoom = new Room(baseUrl);
|
||||
let instance: string = "global";
|
||||
if (currentRoom.isPublic) {
|
||||
instance = currentRoom.instance as string;
|
||||
}
|
||||
|
||||
baseUrl.pathname = "/_/" + instance + "/" + absoluteExitSceneUrl.host + absoluteExitSceneUrl.pathname;
|
||||
if (absoluteExitSceneUrl.hash) {
|
||||
baseUrl.hash = absoluteExitSceneUrl.hash;
|
||||
}
|
||||
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
private async getMapDetail(): Promise<MapDetail | RoomRedirect> {
|
||||
const result = await Axios.get(`${PUSHER_URL}/map`, {
|
||||
params: {
|
||||
playUri: this.roomUrl.toString(),
|
||||
},
|
||||
});
|
||||
|
||||
const data = result.data;
|
||||
if (data.redirectUrl) {
|
||||
return {
|
||||
redirectUrl: data.redirectUrl as string,
|
||||
};
|
||||
}
|
||||
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
|
||||
this._mapUrl = data.mapUrl;
|
||||
this._textures = data.textures;
|
||||
return new MapDetail(data.mapUrl, data.textures);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,37 +114,39 @@ export class Room {
|
|||
|
||||
if (this.isPublic) {
|
||||
const match = /_\/([^/]+)\/.+/.exec(this.id);
|
||||
if (!match) throw new Error('Could not extract instance from "'+this.id+'"');
|
||||
if (!match) throw new Error('Could not extract instance from "' + this.id + '"');
|
||||
this.instance = match[1];
|
||||
return this.instance;
|
||||
} else {
|
||||
const match = /@\/([^/]+)\/([^/]+)\/.+/.exec(this.id);
|
||||
if (!match) throw new Error('Could not extract instance from "'+this.id+'"');
|
||||
this.instance = match[1]+'/'+match[2];
|
||||
if (!match) throw new Error('Could not extract instance from "' + this.id + '"');
|
||||
this.instance = match[1] + "/" + match[2];
|
||||
return this.instance;
|
||||
}
|
||||
}
|
||||
|
||||
private parsePrivateUrl(url: string): { organizationSlug: string, worldSlug: string, roomSlug?: string } {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
private parsePrivateUrl(url: string): { organizationSlug: string; worldSlug: string; roomSlug?: string } {
|
||||
const regex = /@\/([^/]+)\/([^/]+)(?:\/([^/]*))?/gm;
|
||||
const match = regex.exec(url);
|
||||
if (!match) {
|
||||
throw new Error('Invalid URL '+url);
|
||||
throw new Error("Invalid URL " + url);
|
||||
}
|
||||
const results: { organizationSlug: string, worldSlug: string, roomSlug?: string } = {
|
||||
const results: { organizationSlug: string; worldSlug: string; roomSlug?: string } = {
|
||||
organizationSlug: match[1],
|
||||
worldSlug: match[2],
|
||||
}
|
||||
};
|
||||
if (match[3] !== undefined) {
|
||||
results.roomSlug = match[3];
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public isDisconnected(): boolean
|
||||
{
|
||||
const alone = this._search.get('alone');
|
||||
if (alone && alone !== '0' && alone.toLowerCase() !== 'false') {
|
||||
public isDisconnected(): boolean {
|
||||
const alone = this._search.get("alone");
|
||||
if (alone && alone !== "0" && alone.toLowerCase() !== "false") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -138,4 +155,32 @@ export class Room {
|
|||
public get search(): URLSearchParams {
|
||||
return this._search;
|
||||
}
|
||||
|
||||
/**
|
||||
* 2 rooms are equal if they share the same path (but not necessarily the same hash)
|
||||
* @param room
|
||||
*/
|
||||
public isEqual(room: Room): boolean {
|
||||
return room.key === this.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* A key representing this room
|
||||
*/
|
||||
public get key(): string {
|
||||
const newUrl = new URL(this.roomUrl.toString());
|
||||
newUrl.hash = "";
|
||||
return newUrl.toString();
|
||||
}
|
||||
|
||||
get textures(): CharacterTexture[] | undefined {
|
||||
return this._textures;
|
||||
}
|
||||
|
||||
get mapUrl(): string {
|
||||
if (!this._mapUrl) {
|
||||
throw new Error("Map URL not fetched yet");
|
||||
}
|
||||
return this._mapUrl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ import {
|
|||
RoomJoinedMessage,
|
||||
ServerToClientMessage,
|
||||
SetPlayerDetailsMessage,
|
||||
SilentMessage, StopGlobalMessage,
|
||||
SilentMessage,
|
||||
StopGlobalMessage,
|
||||
UserJoinedMessage,
|
||||
UserLeftMessage,
|
||||
UserMovedMessage,
|
||||
|
@ -31,17 +32,22 @@ import {
|
|||
EmotePromptMessage,
|
||||
SendUserMessage,
|
||||
BanUserMessage,
|
||||
} from "../Messages/generated/messages_pb"
|
||||
} from "../Messages/generated/messages_pb";
|
||||
|
||||
import type { UserSimplePeerInterface } from "../WebRtc/SimplePeer";
|
||||
import Direction = PositionMessage.Direction;
|
||||
import { ProtobufClientUtils } from "../Network/ProtobufClientUtils";
|
||||
import {
|
||||
EventMessage,
|
||||
GroupCreatedUpdatedMessageInterface, ItemEventMessageInterface,
|
||||
MessageUserJoined, OnConnectInterface, PlayGlobalMessageInterface, PositionInterface,
|
||||
GroupCreatedUpdatedMessageInterface,
|
||||
ItemEventMessageInterface,
|
||||
MessageUserJoined,
|
||||
OnConnectInterface,
|
||||
PlayGlobalMessageInterface,
|
||||
PositionInterface,
|
||||
RoomJoinedMessageInterface,
|
||||
ViewportInterface, WebRtcDisconnectMessageInterface,
|
||||
ViewportInterface,
|
||||
WebRtcDisconnectMessageInterface,
|
||||
WebRtcSignalReceivedMessageInterface,
|
||||
} from "./ConnexionModels";
|
||||
import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTextures";
|
||||
|
@ -61,36 +67,45 @@ export class RoomConnection implements RoomConnection {
|
|||
private closed: boolean = false;
|
||||
private tags: string[] = [];
|
||||
|
||||
public static setWebsocketFactory(websocketFactory: (url: string) => any): void { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public static setWebsocketFactory(websocketFactory: (url: string) => any): void {
|
||||
RoomConnection.websocketFactory = websocketFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param token A JWT token containing the UUID of the user
|
||||
* @param roomId The ID of the room in the form "_/[instance]/[map_url]" or "@/[org]/[event]/[map]"
|
||||
* @param roomUrl The URL of the room in the form "https://example.com/_/[instance]/[map_url]" or "https://example.com/@/[org]/[event]/[map]"
|
||||
*/
|
||||
public constructor(token: string | null, roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface, companion: string | null) {
|
||||
public constructor(
|
||||
token: string | null,
|
||||
roomUrl: string,
|
||||
name: string,
|
||||
characterLayers: string[],
|
||||
position: PositionInterface,
|
||||
viewport: ViewportInterface,
|
||||
companion: string | null
|
||||
) {
|
||||
let url = new URL(PUSHER_URL, window.location.toString()).toString();
|
||||
url = url.replace('http://', 'ws://').replace('https://', 'wss://');
|
||||
if (!url.endsWith('/')) {
|
||||
url += '/';
|
||||
url = url.replace("http://", "ws://").replace("https://", "wss://");
|
||||
if (!url.endsWith("/")) {
|
||||
url += "/";
|
||||
}
|
||||
url += 'room';
|
||||
url += '?roomId=' + (roomId ? encodeURIComponent(roomId) : '');
|
||||
url += '&token=' + (token ? encodeURIComponent(token) : '');
|
||||
url += '&name=' + encodeURIComponent(name);
|
||||
url += "room";
|
||||
url += "?roomId=" + encodeURIComponent(roomUrl);
|
||||
url += "&token=" + (token ? encodeURIComponent(token) : "");
|
||||
url += "&name=" + encodeURIComponent(name);
|
||||
for (const layer of characterLayers) {
|
||||
url += '&characterLayers=' + encodeURIComponent(layer);
|
||||
url += "&characterLayers=" + encodeURIComponent(layer);
|
||||
}
|
||||
url += '&x=' + Math.floor(position.x);
|
||||
url += '&y=' + Math.floor(position.y);
|
||||
url += '&top=' + Math.floor(viewport.top);
|
||||
url += '&bottom=' + Math.floor(viewport.bottom);
|
||||
url += '&left=' + Math.floor(viewport.left);
|
||||
url += '&right=' + Math.floor(viewport.right);
|
||||
if (typeof companion === 'string') {
|
||||
url += '&companion=' + encodeURIComponent(companion);
|
||||
url += "&x=" + Math.floor(position.x);
|
||||
url += "&y=" + Math.floor(position.y);
|
||||
url += "&top=" + Math.floor(viewport.top);
|
||||
url += "&bottom=" + Math.floor(viewport.bottom);
|
||||
url += "&left=" + Math.floor(viewport.left);
|
||||
url += "&right=" + Math.floor(viewport.right);
|
||||
if (typeof companion === "string") {
|
||||
url += "&companion=" + encodeURIComponent(companion);
|
||||
}
|
||||
|
||||
if (RoomConnection.websocketFactory) {
|
||||
|
@ -99,7 +114,7 @@ export class RoomConnection implements RoomConnection {
|
|||
this.socket = new WebSocket(url);
|
||||
}
|
||||
|
||||
this.socket.binaryType = 'arraybuffer';
|
||||
this.socket.binaryType = "arraybuffer";
|
||||
|
||||
let interval: ReturnType<typeof setInterval> | undefined = undefined;
|
||||
|
||||
|
@ -109,7 +124,7 @@ export class RoomConnection implements RoomConnection {
|
|||
interval = setInterval(() => this.socket.send(pingMessage.serializeBinary().buffer), manualPingDelay);
|
||||
};
|
||||
|
||||
this.socket.addEventListener('close', (event) => {
|
||||
this.socket.addEventListener("close", (event) => {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
|
@ -126,7 +141,7 @@ export class RoomConnection implements RoomConnection {
|
|||
|
||||
if (message.hasBatchmessage()) {
|
||||
for (const subMessage of (message.getBatchmessage() as BatchMessage).getPayloadList()) {
|
||||
let event: string|null = null;
|
||||
let event: string | null = null;
|
||||
let payload;
|
||||
if (subMessage.hasUsermovedmessage()) {
|
||||
event = EventMessage.USER_MOVED;
|
||||
|
@ -150,7 +165,7 @@ export class RoomConnection implements RoomConnection {
|
|||
const emoteMessage = subMessage.getEmoteeventmessage() as EmoteEventMessage;
|
||||
emoteEventStream.fire(emoteMessage.getActoruserid(), emoteMessage.getEmote());
|
||||
} else {
|
||||
throw new Error('Unexpected batch message type');
|
||||
throw new Error("Unexpected batch message type");
|
||||
}
|
||||
|
||||
if (event) {
|
||||
|
@ -171,8 +186,8 @@ export class RoomConnection implements RoomConnection {
|
|||
this.dispatch(EventMessage.CONNECT, {
|
||||
connection: this,
|
||||
room: {
|
||||
items
|
||||
} as RoomJoinedMessageInterface
|
||||
items,
|
||||
} as RoomJoinedMessageInterface,
|
||||
});
|
||||
} else if (message.hasWorldfullmessage()) {
|
||||
worldFullMessageStream.onMessage();
|
||||
|
@ -183,7 +198,10 @@ export class RoomConnection implements RoomConnection {
|
|||
} else if (message.hasWebrtcsignaltoclientmessage()) {
|
||||
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
|
||||
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
|
||||
this.dispatch(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, message.getWebrtcscreensharingsignaltoclientmessage());
|
||||
this.dispatch(
|
||||
EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL,
|
||||
message.getWebrtcscreensharingsignaltoclientmessage()
|
||||
);
|
||||
} else if (message.hasWebrtcstartmessage()) {
|
||||
this.dispatch(EventMessage.WEBRTC_START, message.getWebrtcstartmessage());
|
||||
} else if (message.hasWebrtcdisconnectmessage()) {
|
||||
|
@ -205,10 +223,9 @@ export class RoomConnection implements RoomConnection {
|
|||
} else if (message.hasRefreshroommessage()) {
|
||||
//todo: implement a way to notify the user the room was refreshed.
|
||||
} else {
|
||||
throw new Error('Unknown message received');
|
||||
throw new Error("Unknown message received");
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private dispatch(event: string, payload: unknown): void {
|
||||
|
@ -243,16 +260,16 @@ export class RoomConnection implements RoomConnection {
|
|||
positionMessage.setY(Math.floor(y));
|
||||
let directionEnum: Direction;
|
||||
switch (direction) {
|
||||
case 'up':
|
||||
case "up":
|
||||
directionEnum = Direction.UP;
|
||||
break;
|
||||
case 'down':
|
||||
case "down":
|
||||
directionEnum = Direction.DOWN;
|
||||
break;
|
||||
case 'left':
|
||||
case "left":
|
||||
directionEnum = Direction.LEFT;
|
||||
break;
|
||||
case 'right':
|
||||
case "right":
|
||||
directionEnum = Direction.RIGHT;
|
||||
break;
|
||||
default:
|
||||
|
@ -327,15 +344,17 @@ export class RoomConnection implements RoomConnection {
|
|||
private toMessageUserJoined(message: UserJoinedMessage): MessageUserJoined {
|
||||
const position = message.getPosition();
|
||||
if (position === undefined) {
|
||||
throw new Error('Invalid JOIN_ROOM message');
|
||||
throw new Error("Invalid JOIN_ROOM message");
|
||||
}
|
||||
|
||||
const characterLayers = message.getCharacterlayersList().map((characterLayer: CharacterLayerMessage): BodyResourceDescriptionInterface => {
|
||||
return {
|
||||
name: characterLayer.getName(),
|
||||
img: characterLayer.getUrl()
|
||||
}
|
||||
})
|
||||
const characterLayers = message
|
||||
.getCharacterlayersList()
|
||||
.map((characterLayer: CharacterLayerMessage): BodyResourceDescriptionInterface => {
|
||||
return {
|
||||
name: characterLayer.getName(),
|
||||
img: characterLayer.getUrl(),
|
||||
};
|
||||
});
|
||||
|
||||
const companion = message.getCompanion();
|
||||
|
||||
|
@ -345,8 +364,9 @@ export class RoomConnection implements RoomConnection {
|
|||
characterLayers,
|
||||
visitCardUrl: message.getVisitcardurl(),
|
||||
position: ProtobufClientUtils.toPointInterface(position),
|
||||
companion: companion ? companion.getName() : null
|
||||
}
|
||||
companion: companion ? companion.getName() : null,
|
||||
userUuid: message.getUseruuid(),
|
||||
};
|
||||
}
|
||||
|
||||
public onUserMoved(callback: (message: UserMovedMessage) => void): void {
|
||||
|
@ -372,7 +392,9 @@ export class RoomConnection implements RoomConnection {
|
|||
});
|
||||
}
|
||||
|
||||
public onGroupUpdatedOrCreated(callback: (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => void): void {
|
||||
public onGroupUpdatedOrCreated(
|
||||
callback: (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => void
|
||||
): void {
|
||||
this.onMessage(EventMessage.GROUP_CREATE_UPDATE, (message: GroupUpdateMessage) => {
|
||||
callback(this.toGroupCreatedUpdatedMessage(message));
|
||||
});
|
||||
|
@ -381,14 +403,14 @@ export class RoomConnection implements RoomConnection {
|
|||
private toGroupCreatedUpdatedMessage(message: GroupUpdateMessage): GroupCreatedUpdatedMessageInterface {
|
||||
const position = message.getPosition();
|
||||
if (position === undefined) {
|
||||
throw new Error('Missing position in GROUP_CREATE_UPDATE');
|
||||
throw new Error("Missing position in GROUP_CREATE_UPDATE");
|
||||
}
|
||||
|
||||
return {
|
||||
groupId: message.getGroupid(),
|
||||
position: position.toObject(),
|
||||
groupSize: message.getGroupsize()
|
||||
}
|
||||
groupSize: message.getGroupsize(),
|
||||
};
|
||||
}
|
||||
|
||||
public onGroupDeleted(callback: (groupId: number) => void): void {
|
||||
|
@ -404,7 +426,7 @@ export class RoomConnection implements RoomConnection {
|
|||
}
|
||||
|
||||
public onConnectError(callback: (error: Event) => void): void {
|
||||
this.socket.addEventListener('error', callback)
|
||||
this.socket.addEventListener("error", callback);
|
||||
}
|
||||
|
||||
public onConnect(callback: (roomConnection: OnConnectInterface) => void): void {
|
||||
|
@ -445,7 +467,6 @@ export class RoomConnection implements RoomConnection {
|
|||
this.onMessage(EventMessage.WEBRTC_START, (message: WebRtcStartMessage) => {
|
||||
callback({
|
||||
userId: message.getUserid(),
|
||||
name: message.getName(),
|
||||
initiator: message.getInitiator(),
|
||||
webRtcUser: message.getWebrtcusername() ?? undefined,
|
||||
webRtcPassword: message.getWebrtcpassword() ?? undefined,
|
||||
|
@ -476,11 +497,11 @@ export class RoomConnection implements RoomConnection {
|
|||
}
|
||||
|
||||
public onServerDisconnected(callback: () => void): void {
|
||||
this.socket.addEventListener('close', (event) => {
|
||||
this.socket.addEventListener("close", (event) => {
|
||||
if (this.closed === true || connectionManager.unloading) {
|
||||
return;
|
||||
}
|
||||
console.log('Socket closed with code ' + event.code + ". Reason: " + event.reason);
|
||||
console.log("Socket closed with code " + event.code + ". Reason: " + event.reason);
|
||||
if (event.code === 1000) {
|
||||
// Normal closure case
|
||||
return;
|
||||
|
@ -490,14 +511,14 @@ export class RoomConnection implements RoomConnection {
|
|||
}
|
||||
|
||||
public getUserId(): number {
|
||||
if (this.userId === null) throw 'UserId cannot be null!'
|
||||
if (this.userId === null) throw "UserId cannot be null!";
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
disconnectMessage(callback: (message: WebRtcDisconnectMessageInterface) => void): void {
|
||||
this.onMessage(EventMessage.WEBRTC_DISCONNECT, (message: WebRtcDisconnectMessage) => {
|
||||
callback({
|
||||
userId: message.getUserid()
|
||||
userId: message.getUserid(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -521,21 +542,22 @@ export class RoomConnection implements RoomConnection {
|
|||
itemId: message.getItemid(),
|
||||
event: message.getEvent(),
|
||||
parameters: JSON.parse(message.getParametersjson()),
|
||||
state: JSON.parse(message.getStatejson())
|
||||
state: JSON.parse(message.getStatejson()),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public uploadAudio(file: FormData) {
|
||||
return Axios.post(`${UPLOADER_URL}/upload-audio-message`, file).then((res: { data: {} }) => {
|
||||
return res.data;
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
throw err;
|
||||
});
|
||||
return Axios.post(`${UPLOADER_URL}/upload-audio-message`, file)
|
||||
.then((res: { data: {} }) => {
|
||||
return res.data;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public receivePlayGlobalMessage(callback: (message: PlayGlobalMessageInterface) => void) {
|
||||
return this.onMessage(EventMessage.PLAY_GLOBAL_MESSAGE, (message: PlayGlobalMessage) => {
|
||||
callback({
|
||||
|
@ -570,9 +592,9 @@ export class RoomConnection implements RoomConnection {
|
|||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||
}
|
||||
|
||||
public emitReportPlayerMessage(reportedUserId: number, reportComment: string): void {
|
||||
public emitReportPlayerMessage(reportedUserUuid: string, reportComment: string): void {
|
||||
const reportPlayerMessage = new ReportPlayerMessage();
|
||||
reportPlayerMessage.setReporteduserid(reportedUserId);
|
||||
reportPlayerMessage.setReporteduseruuid(reportedUserUuid);
|
||||
reportPlayerMessage.setReportcomment(reportComment);
|
||||
|
||||
const clientToServerMessage = new ClientToServerMessage();
|
||||
|
@ -605,12 +627,12 @@ export class RoomConnection implements RoomConnection {
|
|||
}
|
||||
|
||||
public isAdmin(): boolean {
|
||||
return this.hasTag('admin');
|
||||
return this.hasTag("admin");
|
||||
}
|
||||
|
||||
public emitEmoteEvent(emoteName: string): void {
|
||||
const emoteMessage = new EmotePromptMessage();
|
||||
emoteMessage.setEmote(emoteName)
|
||||
emoteMessage.setEmote(emoteName);
|
||||
|
||||
const clientToServerMessage = new ClientToServerMessage();
|
||||
clientToServerMessage.setEmotepromptmessage(emoteMessage);
|
||||
|
@ -618,7 +640,7 @@ export class RoomConnection implements RoomConnection {
|
|||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||
}
|
||||
|
||||
public getAllTags() : string[] {
|
||||
public getAllTags(): string[] {
|
||||
return this.tags;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue