FEATURE: the connexion error an user can get when a world is full is now correctly traited. Also remove a redundant adminApi call
This commit is contained in:
parent
ad7e16c33b
commit
8abc34c631
@ -77,8 +77,10 @@ export class TypeMessageExt implements TypeMessageInterface{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class Ban extends TypeMessageExt {
|
|
||||||
}
|
export class Message extends TypeMessageExt {}
|
||||||
|
|
||||||
|
export class Ban extends TypeMessageExt {}
|
||||||
|
|
||||||
export class Banned extends TypeMessageExt {
|
export class Banned extends TypeMessageExt {
|
||||||
showMessage(message: string){
|
showMessage(message: string){
|
||||||
|
@ -6,11 +6,22 @@ import {GameConnexionTypes, urlManager} from "../Url/UrlManager";
|
|||||||
import {localUserStore} from "./LocalUserStore";
|
import {localUserStore} from "./LocalUserStore";
|
||||||
import {LocalUser} from "./LocalUser";
|
import {LocalUser} from "./LocalUser";
|
||||||
import {Room} from "./Room";
|
import {Room} from "./Room";
|
||||||
|
import {Subject} from "rxjs";
|
||||||
|
|
||||||
|
export enum ConnexionMessageEventTypes {
|
||||||
|
worldFull = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConnexionMessageEvent {
|
||||||
|
type: ConnexionMessageEventTypes,
|
||||||
|
}
|
||||||
|
|
||||||
class ConnectionManager {
|
class ConnectionManager {
|
||||||
private localUser!:LocalUser;
|
private localUser!:LocalUser;
|
||||||
|
|
||||||
private connexionType?: GameConnexionTypes
|
private connexionType?: GameConnexionTypes
|
||||||
|
|
||||||
|
public _connexionMessageStream:Subject<ConnexionMessageEvent> = new Subject();
|
||||||
/**
|
/**
|
||||||
* Tries to login to the node server and return the starting map url to be loaded
|
* Tries to login to the node server and return the starting map url to be loaded
|
||||||
*/
|
*/
|
||||||
|
@ -42,14 +42,6 @@ export interface PointInterface {
|
|||||||
moving: boolean;
|
moving: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Point implements PointInterface{
|
|
||||||
constructor(public x : number, public y : number, public direction : string = PlayerAnimationNames.WalkDown, public moving : boolean = false) {
|
|
||||||
if(x === null || y === null){
|
|
||||||
throw Error("position x and y cannot be null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MessageUserPositionInterface {
|
export interface MessageUserPositionInterface {
|
||||||
userId: number;
|
userId: number;
|
||||||
name: string;
|
name: string;
|
||||||
@ -80,20 +72,10 @@ export interface GroupCreatedUpdatedMessageInterface {
|
|||||||
groupSize: number
|
groupSize: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebRtcStartMessageInterface {
|
|
||||||
roomId: string,
|
|
||||||
clients: UserSimplePeerInterface[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebRtcDisconnectMessageInterface {
|
export interface WebRtcDisconnectMessageInterface {
|
||||||
userId: number
|
userId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebRtcSignalSentMessageInterface {
|
|
||||||
receiverId: number,
|
|
||||||
signal: SignalData
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebRtcSignalReceivedMessageInterface {
|
export interface WebRtcSignalReceivedMessageInterface {
|
||||||
userId: number,
|
userId: number,
|
||||||
signal: SignalData,
|
signal: SignalData,
|
||||||
@ -113,11 +95,6 @@ export interface ViewportInterface {
|
|||||||
bottom: number,
|
bottom: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BatchedMessageInterface {
|
|
||||||
event: string,
|
|
||||||
payload: unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ItemEventMessageInterface {
|
export interface ItemEventMessageInterface {
|
||||||
itemId: number,
|
itemId: number,
|
||||||
event: string,
|
event: string,
|
||||||
|
@ -43,6 +43,7 @@ import {
|
|||||||
} from "./ConnexionModels";
|
} from "./ConnexionModels";
|
||||||
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures";
|
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/PlayerTextures";
|
||||||
import {adminMessagesService} from "./AdminMessagesService";
|
import {adminMessagesService} from "./AdminMessagesService";
|
||||||
|
import {connectionManager, ConnexionMessageEventTypes} from "./ConnectionManager";
|
||||||
|
|
||||||
const manualPingDelay = 20000;
|
const manualPingDelay = 20000;
|
||||||
|
|
||||||
@ -101,7 +102,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we are not connected yet (if a JoinRoomMessage was not sent), we need to retry.
|
// If we are not connected yet (if a JoinRoomMessage was not sent), we need to retry.
|
||||||
if (this.userId === null) {
|
if (this.userId === null && !this.closed) {
|
||||||
this.dispatch(EventMessage.CONNECTING_ERROR, event);
|
this.dispatch(EventMessage.CONNECTING_ERROR, event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -156,7 +157,8 @@ export class RoomConnection implements RoomConnection {
|
|||||||
} as RoomJoinedMessageInterface
|
} as RoomJoinedMessageInterface
|
||||||
});
|
});
|
||||||
} else if (message.hasErrormessage()) {
|
} else if (message.hasErrormessage()) {
|
||||||
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage());
|
connectionManager._connexionMessageStream.next({type: ConnexionMessageEventTypes.worldFull}); //todo: generalize this behavior to all messages
|
||||||
|
this.closed = true;
|
||||||
} else if (message.hasWebrtcsignaltoclientmessage()) {
|
} else if (message.hasWebrtcsignaltoclientmessage()) {
|
||||||
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
|
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
|
||||||
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
|
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
|
||||||
|
@ -3,25 +3,15 @@ import {
|
|||||||
GroupCreatedUpdatedMessageInterface,
|
GroupCreatedUpdatedMessageInterface,
|
||||||
MessageUserJoined,
|
MessageUserJoined,
|
||||||
MessageUserMovedInterface,
|
MessageUserMovedInterface,
|
||||||
MessageUserPositionInterface, OnConnectInterface,
|
MessageUserPositionInterface,
|
||||||
|
OnConnectInterface,
|
||||||
PointInterface,
|
PointInterface,
|
||||||
PositionInterface,
|
PositionInterface,
|
||||||
RoomJoinedMessageInterface
|
RoomJoinedMessageInterface
|
||||||
} from "../../Connexion/ConnexionModels";
|
} from "../../Connexion/ConnexionModels";
|
||||||
import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
||||||
import {
|
import {DEBUG_MODE, JITSI_PRIVATE_MODE, POSITION_DELAY, RESOLUTION, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
|
||||||
DEBUG_MODE,
|
import {ITiledMap, ITiledMapLayer, ITiledMapLayerProperty, ITiledMapObject, ITiledTileSet} from "../Map/ITiledMap";
|
||||||
JITSI_PRIVATE_MODE,
|
|
||||||
POSITION_DELAY,
|
|
||||||
RESOLUTION,
|
|
||||||
ZOOM_LEVEL
|
|
||||||
} from "../../Enum/EnvironmentVariable";
|
|
||||||
import {
|
|
||||||
ITiledMap,
|
|
||||||
ITiledMapLayer,
|
|
||||||
ITiledMapLayerProperty, ITiledMapObject,
|
|
||||||
ITiledTileSet
|
|
||||||
} from "../Map/ITiledMap";
|
|
||||||
import {AddPlayerInterface} from "./AddPlayerInterface";
|
import {AddPlayerInterface} from "./AddPlayerInterface";
|
||||||
import {PlayerAnimationNames} from "../Player/Animation";
|
import {PlayerAnimationNames} from "../Player/Animation";
|
||||||
import {PlayerMovement} from "./PlayerMovement";
|
import {PlayerMovement} from "./PlayerMovement";
|
||||||
@ -41,11 +31,6 @@ import {
|
|||||||
TRIGGER_WEBSITE_PROPERTIES,
|
TRIGGER_WEBSITE_PROPERTIES,
|
||||||
WEBSITE_MESSAGE_PROPERTIES
|
WEBSITE_MESSAGE_PROPERTIES
|
||||||
} from "../../WebRtc/LayoutManager";
|
} from "../../WebRtc/LayoutManager";
|
||||||
import Texture = Phaser.Textures.Texture;
|
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
|
||||||
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
|
||||||
import GameObject = Phaser.GameObjects.GameObject;
|
|
||||||
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
|
||||||
import {GameMap} from "./GameMap";
|
import {GameMap} from "./GameMap";
|
||||||
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
||||||
import {mediaManager} from "../../WebRtc/MediaManager";
|
import {mediaManager} from "../../WebRtc/MediaManager";
|
||||||
@ -54,7 +39,7 @@ import {ActionableItem} from "../Items/ActionableItem";
|
|||||||
import {UserInputManager} from "../UserInput/UserInputManager";
|
import {UserInputManager} from "../UserInput/UserInputManager";
|
||||||
import {UserMovedMessage} from "../../Messages/generated/messages_pb";
|
import {UserMovedMessage} from "../../Messages/generated/messages_pb";
|
||||||
import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils";
|
import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils";
|
||||||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
import {connectionManager, ConnexionMessageEvent, ConnexionMessageEventTypes} from "../../Connexion/ConnectionManager";
|
||||||
import {RoomConnection} from "../../Connexion/RoomConnection";
|
import {RoomConnection} from "../../Connexion/RoomConnection";
|
||||||
import {GlobalMessageManager} from "../../Administration/GlobalMessageManager";
|
import {GlobalMessageManager} from "../../Administration/GlobalMessageManager";
|
||||||
import {userMessageManager} from "../../Administration/UserMessageManager";
|
import {userMessageManager} from "../../Administration/UserMessageManager";
|
||||||
@ -72,6 +57,12 @@ import {TextureError} from "../../Exception/TextureError";
|
|||||||
import {addLoader} from "../Components/Loader";
|
import {addLoader} from "../Components/Loader";
|
||||||
import {ErrorSceneName} from "../Reconnecting/ErrorScene";
|
import {ErrorSceneName} from "../Reconnecting/ErrorScene";
|
||||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
|
import Texture = Phaser.Textures.Texture;
|
||||||
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
|
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
||||||
|
import GameObject = Phaser.GameObjects.GameObject;
|
||||||
|
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
||||||
|
import {Subscription} from "rxjs";
|
||||||
|
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface|null,
|
initPosition: PointInterface|null,
|
||||||
@ -157,11 +148,12 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
// The item that can be selected by pressing the space key.
|
// The item that can be selected by pressing the space key.
|
||||||
private outlinedItem: ActionableItem|null = null;
|
private outlinedItem: ActionableItem|null = null;
|
||||||
public userInputManager!: UserInputManager;
|
public userInputManager!: UserInputManager;
|
||||||
private isReconnecting: boolean = false;
|
private isReconnecting: boolean|undefined = undefined;
|
||||||
private startLayerName!: string | null;
|
private startLayerName!: string | null;
|
||||||
private openChatIcon!: OpenChatIcon;
|
private openChatIcon!: OpenChatIcon;
|
||||||
private playerName!: string;
|
private playerName!: string;
|
||||||
private characterLayers!: string[];
|
private characterLayers!: string[];
|
||||||
|
private messageSubscription: Subscription|null = null;
|
||||||
|
|
||||||
constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) {
|
constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) {
|
||||||
super({
|
super({
|
||||||
@ -293,25 +285,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// import(/* webpackIgnore: true */ scriptUrl).then(result => {
|
|
||||||
//
|
|
||||||
// result.default.preload(this.load);
|
|
||||||
//
|
|
||||||
// this.load.start(); // Let's manually start the loader because the import might be over AFTER the loading ends.
|
|
||||||
// this.load.on('complete', () => {
|
|
||||||
// // FIXME: the factory might fail because the resources might not be loaded yet...
|
|
||||||
// // We would need to add a loader ended event in addition to the createPromise
|
|
||||||
// this.createPromise.then(() => {
|
|
||||||
// result.default.create(this);
|
|
||||||
//
|
|
||||||
// for (let object of objectsOfType) {
|
|
||||||
// // TODO: we should pass here a factory to create sprites (maybe?)
|
|
||||||
// let objectSprite = result.default.factory(this, object);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,6 +303,8 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
gameManager.gameSceneIsCreated(this);
|
gameManager.gameSceneIsCreated(this);
|
||||||
urlManager.pushRoomIdToUrl(this.room);
|
urlManager.pushRoomIdToUrl(this.room);
|
||||||
this.startLayerName = urlManager.getStartLayerNameFromUrl();
|
this.startLayerName = urlManager.getStartLayerNameFromUrl();
|
||||||
|
|
||||||
|
this.messageSubscription = connectionManager._connexionMessageStream.subscribe((event) => this.onConnexionMessage(event))
|
||||||
|
|
||||||
const playerName = gameManager.getPlayerName();
|
const playerName = gameManager.getPlayerName();
|
||||||
if (!playerName) {
|
if (!playerName) {
|
||||||
@ -401,13 +376,13 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
this.scene.launch(ReconnectingSceneName);
|
this.scene.launch(ReconnectingSceneName);
|
||||||
}, 0);
|
}, 0);
|
||||||
} else if (this.connection === undefined) {
|
} else if (this.connection === undefined) {
|
||||||
// Let's wait 0.5 seconds before printing the "connecting" screen to avoid blinking
|
// Let's wait 1 second before printing the "connecting" screen to avoid blinking
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.connection === undefined) {
|
if (this.connection === undefined) {
|
||||||
this.scene.sleep();
|
this.scene.sleep();
|
||||||
this.scene.launch(ReconnectingSceneName);
|
this.scene.launch(ReconnectingSceneName);
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createPromiseResolve();
|
this.createPromiseResolve();
|
||||||
@ -569,8 +544,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
|
|
||||||
//init user position and play trigger to check layers properties
|
//init user position and play trigger to check layers properties
|
||||||
this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
||||||
|
|
||||||
return this.connection;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,30 +580,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
contextRed.stroke();
|
contextRed.stroke();
|
||||||
this.circleRedTexture.refresh();
|
this.circleRedTexture.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private playAudio(url: string|number|boolean|undefined, loop=false): void {
|
|
||||||
if (url === undefined) {
|
|
||||||
audioManager.unloadAudio();
|
|
||||||
} else {
|
|
||||||
const audioPath = url as string;
|
|
||||||
let realAudioPath = '';
|
|
||||||
|
|
||||||
if (audioPath.indexOf('://') > 0) {
|
|
||||||
// remote file or stream
|
|
||||||
realAudioPath = audioPath;
|
|
||||||
} else {
|
|
||||||
// local file, include it relative to map directory
|
|
||||||
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
|
||||||
realAudioPath = mapDirUrl + '/' + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
audioManager.loadAudio(realAudioPath);
|
|
||||||
|
|
||||||
if (loop) {
|
|
||||||
audioManager.loop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private safeParseJSONstring(jsonString: string|undefined, propertyName: string) {
|
private safeParseJSONstring(jsonString: string|undefined, propertyName: string) {
|
||||||
try {
|
try {
|
||||||
@ -711,15 +661,19 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange('playAudio', (newValue, oldValue) => {
|
this.gameMap.onPropertyChange('playAudio', (newValue, oldValue) => {
|
||||||
this.playAudio(newValue);
|
newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl());
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => {
|
this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => {
|
||||||
this.playAudio(newValue, true);
|
newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl());
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getMapDirUrl(): string {
|
||||||
|
return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
||||||
|
}
|
||||||
|
|
||||||
private onMapExit(exitKey: string) {
|
private onMapExit(exitKey: string) {
|
||||||
const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance);
|
const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance);
|
||||||
if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey);
|
if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey);
|
||||||
@ -745,14 +699,11 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
// stop playing audio, close any open website, stop any open Jitsi
|
// stop playing audio, close any open website, stop any open Jitsi
|
||||||
coWebsiteManager.closeCoWebsite();
|
coWebsiteManager.closeCoWebsite();
|
||||||
this.stopJitsi();
|
this.stopJitsi();
|
||||||
this.playAudio(undefined);
|
audioManager.unloadAudio();
|
||||||
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
||||||
if(this.connection) {
|
this.connection?.closeConnection();
|
||||||
this.connection.closeConnection();
|
this.simplePeer?.unregister();
|
||||||
}
|
this.messageSubscription?.unsubscribe();
|
||||||
if(this.simplePeer) {
|
|
||||||
this.simplePeer.unregister();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeAllRemotePlayers(): void {
|
private removeAllRemotePlayers(): void {
|
||||||
@ -1267,21 +1218,34 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public stopJitsi(): void {
|
public stopJitsi(): void {
|
||||||
this.connection.setSilent(false);
|
this.connection?.setSilent(false);
|
||||||
jitsiFactory.stop();
|
jitsiFactory.stop();
|
||||||
mediaManager.showGameOverlay();
|
mediaManager.showGameOverlay();
|
||||||
|
|
||||||
mediaManager.removeTriggerCloseJitsiFrameButton('close-jisi');
|
mediaManager.removeTriggerCloseJitsiFrameButton('close-jisi');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo: into onConnexionMessage
|
||||||
private bannedUser(){
|
private bannedUser(){
|
||||||
this.cleanupClosingScene();
|
this.cleanupClosingScene();
|
||||||
this.userInputManager.clearAllKeys();
|
this.userInputManager.clearAllKeys();
|
||||||
this.scene.start(ErrorSceneName, {
|
this.scene.start(ErrorSceneName, {
|
||||||
title: 'Banned',
|
title: 'Banned',
|
||||||
subTitle: 'You was banned of WorkAdventure',
|
subTitle: 'You were banned from WorkAdventure',
|
||||||
message: 'If you want more information, you can contact us: workadventure@thecodingmachine.com'
|
message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onConnexionMessage(event: ConnexionMessageEvent) {
|
||||||
|
if (event.type === ConnexionMessageEventTypes.worldFull) {
|
||||||
|
this.cleanupClosingScene();
|
||||||
|
this.scene.stop(ReconnectingSceneName);
|
||||||
|
this.userInputManager.clearAllKeys();
|
||||||
|
this.scene.start(ErrorSceneName, {
|
||||||
|
title: 'Connection rejected',
|
||||||
|
subTitle: 'The world you are trying to join is full. Try again later.',
|
||||||
|
message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,25 @@ class AudioManager {
|
|||||||
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = '' + this.volume;
|
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = '' + this.volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public playAudio(url: string|number|boolean, mapDirUrl: string, loop=false): void {
|
||||||
|
const audioPath = url as string;
|
||||||
|
let realAudioPath = '';
|
||||||
|
|
||||||
|
if (audioPath.indexOf('://') > 0) {
|
||||||
|
// remote file or stream
|
||||||
|
realAudioPath = audioPath;
|
||||||
|
} else {
|
||||||
|
// local file, include it relative to map directory
|
||||||
|
realAudioPath = mapDirUrl + '/' + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadAudio(realAudioPath);
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
this.loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private close(): void {
|
private close(): void {
|
||||||
this.audioPlayerCtrl.classList.remove('loading');
|
this.audioPlayerCtrl.classList.remove('loading');
|
||||||
this.audioPlayerCtrl.classList.add('hidden');
|
this.audioPlayerCtrl.classList.add('hidden');
|
||||||
@ -75,7 +94,7 @@ class AudioManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public loadAudio(url: string): void {
|
private loadAudio(url: string): void {
|
||||||
this.load();
|
this.load();
|
||||||
|
|
||||||
/* Solution 1, remove whole audio player */
|
/* Solution 1, remove whole audio player */
|
||||||
@ -125,7 +144,7 @@ class AudioManager {
|
|||||||
this.open();
|
this.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
public loop(): void {
|
private loop(): void {
|
||||||
if (this.audioPlayerElem !== undefined) {
|
if (this.audioPlayerElem !== undefined) {
|
||||||
this.audioPlayerElem.loop = true;
|
this.audioPlayerElem.loop = true;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {CharacterLayer, ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
import {CharacterLayer, ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
||||||
import {GameRoomPolicyTypes} from "../Model/PusherRoom";
|
import {GameRoomPolicyTypes, PusherRoom} from "../Model/PusherRoom";
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
import {PointInterface} from "../Model/Websocket/PointInterface";
|
||||||
import {
|
import {
|
||||||
SetPlayerDetailsMessage,
|
SetPlayerDetailsMessage,
|
||||||
@ -20,7 +20,7 @@ import {parse} from "query-string";
|
|||||||
import {jwtTokenManager} from "../Services/JWTTokenManager";
|
import {jwtTokenManager} from "../Services/JWTTokenManager";
|
||||||
import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Services/AdminApi";
|
import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Services/AdminApi";
|
||||||
import {SocketManager, socketManager} from "../Services/SocketManager";
|
import {SocketManager, socketManager} from "../Services/SocketManager";
|
||||||
import {emitInBatch} from "../Services/IoSocketHelpers";
|
import {emitError, emitInBatch} from "../Services/IoSocketHelpers";
|
||||||
import {ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER} from "../Enum/EnvironmentVariable";
|
import {ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER} from "../Enum/EnvironmentVariable";
|
||||||
import {Zone} from "_Model/Zone";
|
import {Zone} from "_Model/Zone";
|
||||||
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
|
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
|
||||||
@ -108,7 +108,6 @@ export class IoSocketController {
|
|||||||
maxBackpressure: 65536, // Maximum 64kB of data in the buffer.
|
maxBackpressure: 65536, // Maximum 64kB of data in the buffer.
|
||||||
//idleTimeout: 10,
|
//idleTimeout: 10,
|
||||||
upgrade: (res, req, context) => {
|
upgrade: (res, req, context) => {
|
||||||
//console.log('An Http connection wants to become WebSocket, URL: ' + req.getUrl() + '!');
|
|
||||||
(async () => {
|
(async () => {
|
||||||
/* Keep track of abortions */
|
/* Keep track of abortions */
|
||||||
const upgradeAborted = {aborted: false};
|
const upgradeAborted = {aborted: false};
|
||||||
@ -156,12 +155,9 @@ export class IoSocketController {
|
|||||||
const userUuid = await jwtTokenManager.getUserUuidFromToken(token, IPAddress, roomId);
|
const userUuid = await jwtTokenManager.getUserUuidFromToken(token, IPAddress, roomId);
|
||||||
|
|
||||||
let memberTags: string[] = [];
|
let memberTags: string[] = [];
|
||||||
|
let memberMessages: unknown;
|
||||||
let memberTextures: CharacterTexture[] = [];
|
let memberTextures: CharacterTexture[] = [];
|
||||||
const room = await socketManager.getOrCreateRoom(roomId);
|
const room = await socketManager.getOrCreateRoom(roomId);
|
||||||
// TODO: make sure the room isFull is ported in the back part.
|
|
||||||
/*if(room.isFull){
|
|
||||||
throw new Error('Room is full');
|
|
||||||
}*/
|
|
||||||
if (ADMIN_API_URL) {
|
if (ADMIN_API_URL) {
|
||||||
try {
|
try {
|
||||||
let userData : FetchMemberDataByUuidResponse = {
|
let userData : FetchMemberDataByUuidResponse = {
|
||||||
@ -172,15 +168,26 @@ export class IoSocketController {
|
|||||||
anonymous: true
|
anonymous: true
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
userData = await adminApi.fetchMemberDataByUuid(userUuid, roomId);
|
||||||
}catch (err){
|
}catch (err){
|
||||||
if (err?.response?.status == 404) {
|
if (err?.response?.status == 404) {
|
||||||
// If we get an HTTP 404, the token is invalid. Let's perform an anonymous login!
|
// If we get an HTTP 404, the token is invalid. Let's perform an anonymous login!
|
||||||
console.warn('Cannot find user with uuid "'+userUuid+'". Performing an anonymous login instead.');
|
console.warn('Cannot find user with uuid "'+userUuid+'". Performing an anonymous login instead.');
|
||||||
|
} else if(err?.response?.status == 403) {
|
||||||
|
// If we get an HTTP 404, the world is full. We need to broadcast a special error to the client.
|
||||||
|
// we finish immediatly the upgrade then we will close the socket as soon as it starts opening.
|
||||||
|
res.upgrade({
|
||||||
|
rejected: true,
|
||||||
|
}, websocketKey,
|
||||||
|
websocketProtocol,
|
||||||
|
websocketExtensions,
|
||||||
|
context);
|
||||||
|
return;
|
||||||
}else{
|
}else{
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
memberMessages = userData.messages;
|
||||||
memberTags = userData.tags;
|
memberTags = userData.tags;
|
||||||
memberTextures = userData.textures;
|
memberTextures = userData.textures;
|
||||||
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && (userData.anonymous === true || !room.canAccess(memberTags))) {
|
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && (userData.anonymous === true || !room.canAccess(memberTags))) {
|
||||||
@ -215,6 +222,7 @@ export class IoSocketController {
|
|||||||
roomId,
|
roomId,
|
||||||
name,
|
name,
|
||||||
characterLayers: characterLayerObjs,
|
characterLayers: characterLayerObjs,
|
||||||
|
messages: memberMessages,
|
||||||
tags: memberTags,
|
tags: memberTags,
|
||||||
textures: memberTextures,
|
textures: memberTextures,
|
||||||
position: {
|
position: {
|
||||||
@ -241,7 +249,6 @@ export class IoSocketController {
|
|||||||
console.log(e.message);
|
console.log(e.message);
|
||||||
res.writeStatus("401 Unauthorized").end(e.message);
|
res.writeStatus("401 Unauthorized").end(e.message);
|
||||||
} else {
|
} else {
|
||||||
console.log(e);
|
|
||||||
res.writeStatus("500 Internal Server Error").end('An error occurred');
|
res.writeStatus("500 Internal Server Error").end('An error occurred');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -250,32 +257,30 @@ export class IoSocketController {
|
|||||||
},
|
},
|
||||||
/* Handlers */
|
/* Handlers */
|
||||||
open: (ws) => {
|
open: (ws) => {
|
||||||
|
if(ws.rejected === true) {
|
||||||
|
emitError(ws, 'World is full');
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
|
|
||||||
// Let's join the room
|
// Let's join the room
|
||||||
const client = this.initClient(ws); //todo: into the upgrade instead?
|
const client = this.initClient(ws); //todo: into the upgrade instead?
|
||||||
socketManager.handleJoinRoom(client);
|
socketManager.handleJoinRoom(client);
|
||||||
|
|
||||||
//get data information and show messages
|
//get data information and show messages
|
||||||
if (ADMIN_API_URL) {
|
if (client.messages && Array.isArray(client.messages)) {
|
||||||
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: FetchMemberDataByUuidResponse) => {
|
client.messages.forEach((c: unknown) => {
|
||||||
if (!res.messages) {
|
const messageToSend = c as { type: string, message: string };
|
||||||
return;
|
|
||||||
|
const sendUserMessage = new SendUserMessage();
|
||||||
|
sendUserMessage.setType(messageToSend.type);
|
||||||
|
sendUserMessage.setMessage(messageToSend.message);
|
||||||
|
|
||||||
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
|
serverToClientMessage.setSendusermessage(sendUserMessage);
|
||||||
|
|
||||||
|
if (!client.disconnecting) {
|
||||||
|
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
}
|
}
|
||||||
res.messages.forEach((c: unknown) => {
|
|
||||||
const messageToSend = c as { type: string, message: string };
|
|
||||||
|
|
||||||
const sendUserMessage = new SendUserMessage();
|
|
||||||
sendUserMessage.setType(messageToSend.type);
|
|
||||||
sendUserMessage.setMessage(messageToSend.message);
|
|
||||||
|
|
||||||
const serverToClientMessage = new ServerToClientMessage();
|
|
||||||
serverToClientMessage.setSendusermessage(sendUserMessage);
|
|
||||||
|
|
||||||
if (!client.disconnecting) {
|
|
||||||
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).catch((err) => {
|
|
||||||
console.error('fetchMemberDataByUuid => err', err);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -340,6 +345,7 @@ export class IoSocketController {
|
|||||||
}
|
}
|
||||||
client.disconnecting = false;
|
client.disconnecting = false;
|
||||||
|
|
||||||
|
client.messages = ws.messages;
|
||||||
client.name = ws.name;
|
client.name = ws.name;
|
||||||
client.tags = ws.tags;
|
client.tags = ws.tags;
|
||||||
client.textures = ws.textures;
|
client.textures = ws.textures;
|
||||||
|
@ -36,6 +36,7 @@ export interface ExSocketInterface extends WebSocket, Identificable {
|
|||||||
batchedMessages: BatchMessage;
|
batchedMessages: BatchMessage;
|
||||||
batchTimeout: NodeJS.Timeout|null;
|
batchTimeout: NodeJS.Timeout|null;
|
||||||
disconnecting: boolean,
|
disconnecting: boolean,
|
||||||
|
messages: unknown,
|
||||||
tags: string[],
|
tags: string[],
|
||||||
textures: CharacterTexture[],
|
textures: CharacterTexture[],
|
||||||
backConnection: BackConnection,
|
backConnection: BackConnection,
|
||||||
|
@ -58,12 +58,12 @@ class AdminApi {
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchMemberDataByUuid(uuid: string): Promise<FetchMemberDataByUuidResponse> {
|
async fetchMemberDataByUuid(uuid: string, roomId: string): Promise<FetchMemberDataByUuidResponse> {
|
||||||
if (!ADMIN_API_URL) {
|
if (!ADMIN_API_URL) {
|
||||||
return Promise.reject('No admin backoffice set!');
|
return Promise.reject('No admin backoffice set!');
|
||||||
}
|
}
|
||||||
const res = await Axios.get(ADMIN_API_URL+'/api/membership/'+uuid,
|
const res = await Axios.get(ADMIN_API_URL+'/api/room/access',
|
||||||
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
{ params: {uuid, roomId}, headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
||||||
)
|
)
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
||||||
import {BatchMessage, ErrorMessage, ServerToClientMessage, SubMessage} from "../Messages/generated/messages_pb";
|
import {BatchMessage, ErrorMessage, ServerToClientMessage, SubMessage} from "../Messages/generated/messages_pb";
|
||||||
|
import {WebSocket} from "uWebSockets.js";
|
||||||
|
|
||||||
export function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void {
|
export function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void {
|
||||||
socket.batchedMessages.addPayload(payload);
|
socket.batchedMessages.addPayload(payload);
|
||||||
@ -20,7 +21,7 @@ export function emitInBatch(socket: ExSocketInterface, payload: SubMessage): voi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function emitError(Client: ExSocketInterface, message: string): void {
|
export function emitError(Client: WebSocket, message: string): void {
|
||||||
const errorMessage = new ErrorMessage();
|
const errorMessage = new ErrorMessage();
|
||||||
errorMessage.setMessage(message);
|
errorMessage.setMessage(message);
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import {
|
|||||||
GroupDeleteMessage,
|
GroupDeleteMessage,
|
||||||
ItemEventMessage,
|
ItemEventMessage,
|
||||||
PlayGlobalMessage,
|
PlayGlobalMessage,
|
||||||
PositionMessage,
|
|
||||||
RoomJoinedMessage,
|
RoomJoinedMessage,
|
||||||
ServerToClientMessage,
|
ServerToClientMessage,
|
||||||
SetPlayerDetailsMessage,
|
SetPlayerDetailsMessage,
|
||||||
@ -25,21 +24,15 @@ import {
|
|||||||
SendUserMessage,
|
SendUserMessage,
|
||||||
BanUserMessage, UserJoinedRoomMessage, UserLeftRoomMessage
|
BanUserMessage, UserJoinedRoomMessage, UserLeftRoomMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
|
||||||
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
import {cpuTracker} from "./CpuTracker";
|
import {JITSI_ISS, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
|
||||||
import {GROUP_RADIUS, JITSI_ISS, MINIMUM_DISTANCE, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
|
|
||||||
import {Movable} from "../Model/Movable";
|
|
||||||
import {PositionInterface} from "../Model/PositionInterface";
|
|
||||||
import {adminApi, CharacterTexture} from "./AdminApi";
|
import {adminApi, CharacterTexture} from "./AdminApi";
|
||||||
import Direction = PositionMessage.Direction;
|
|
||||||
import {emitError, emitInBatch} from "./IoSocketHelpers";
|
import {emitError, emitInBatch} from "./IoSocketHelpers";
|
||||||
import Jwt from "jsonwebtoken";
|
import Jwt from "jsonwebtoken";
|
||||||
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
||||||
import {clientEventsEmitter} from "./ClientEventsEmitter";
|
import {clientEventsEmitter} from "./ClientEventsEmitter";
|
||||||
import {gaugeManager} from "./GaugeManager";
|
import {gaugeManager} from "./GaugeManager";
|
||||||
import {apiClientRepository} from "./ApiClientRepository";
|
import {apiClientRepository} from "./ApiClientRepository";
|
||||||
import {ServiceError} from "grpc";
|
|
||||||
import {GroupDescriptor, UserDescriptor, ZoneEventListener} from "_Model/Zone";
|
import {GroupDescriptor, UserDescriptor, ZoneEventListener} from "_Model/Zone";
|
||||||
import Debug from "debug";
|
import Debug from "debug";
|
||||||
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
|
import {ExAdminSocketInterface} from "_Model/Websocket/ExAdminSocketInterface";
|
||||||
@ -408,17 +401,7 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
//check and create new world for a room
|
//check and create new world for a room
|
||||||
let world = this.Worlds.get(roomId)
|
let world = this.Worlds.get(roomId)
|
||||||
if(world === undefined){
|
if(world === undefined){
|
||||||
world = new PusherRoom(
|
world = new PusherRoom(roomId, this);
|
||||||
roomId,
|
|
||||||
this
|
|
||||||
/* (user: User, group: Group) => this.joinWebRtcRoom(user, group),
|
|
||||||
(user: User, group: Group) => this.disConnectedUser(user, group),
|
|
||||||
MINIMUM_DISTANCE,
|
|
||||||
GROUP_RADIUS,
|
|
||||||
(thing: Movable, listener: User) => this.onRoomEnter(thing, listener),
|
|
||||||
(thing: Movable, position:PositionInterface, listener:User) => this.onClientMove(thing, position, listener),
|
|
||||||
(thing: Movable, listener:User) => this.onClientLeave(thing, listener)*/
|
|
||||||
);
|
|
||||||
if (!world.anonymous) {
|
if (!world.anonymous) {
|
||||||
const data = await adminApi.fetchMapDetails(world.organizationSlug, world.worldSlug, world.roomSlug)
|
const data = await adminApi.fetchMapDetails(world.organizationSlug, world.worldSlug, world.roomSlug)
|
||||||
world.tags = data.tags
|
world.tags = data.tags
|
||||||
@ -429,60 +412,6 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
return Promise.resolve(world)
|
return Promise.resolve(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* private joinRoom(client : ExSocketInterface, position: PointInterface): PusherRoom {
|
|
||||||
|
|
||||||
const roomId = client.roomId;
|
|
||||||
client.position = position;
|
|
||||||
|
|
||||||
const world = this.Worlds.get(roomId)
|
|
||||||
if(world === undefined){
|
|
||||||
throw new Error('Could not find room for ID: '+client.roomId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch groups position to newly connected user
|
|
||||||
world.getGroups().forEach((group: Group) => {
|
|
||||||
this.emitCreateUpdateGroupEvent(client, group);
|
|
||||||
});
|
|
||||||
//join world
|
|
||||||
world.join(client, client.position);
|
|
||||||
clientEventsEmitter.emitClientJoin(client.userUuid, client.roomId);
|
|
||||||
console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
|
|
||||||
private onClientMove(thing: Movable, position:PositionInterface, listener:User): void {
|
|
||||||
const clientListener = this.searchClientByIdOrFail(listener.id);
|
|
||||||
if (thing instanceof User) {
|
|
||||||
const clientUser = this.searchClientByIdOrFail(thing.id);
|
|
||||||
|
|
||||||
const userMovedMessage = new UserMovedMessage();
|
|
||||||
userMovedMessage.setUserid(clientUser.userId);
|
|
||||||
userMovedMessage.setPosition(ProtobufUtils.toPositionMessage(clientUser.position));
|
|
||||||
|
|
||||||
const subMessage = new SubMessage();
|
|
||||||
subMessage.setUsermovedmessage(userMovedMessage);
|
|
||||||
|
|
||||||
clientListener.emitInBatch(subMessage);
|
|
||||||
//console.log("Sending USER_MOVED event");
|
|
||||||
} else if (thing instanceof Group) {
|
|
||||||
this.emitCreateUpdateGroupEvent(clientListener, thing);
|
|
||||||
} else {
|
|
||||||
console.error('Unexpected type for Movable.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onClientLeave(thing: Movable, listener:User) {
|
|
||||||
const clientListener = this.searchClientByIdOrFail(listener.id);
|
|
||||||
if (thing instanceof User) {
|
|
||||||
const clientUser = this.searchClientByIdOrFail(thing.id);
|
|
||||||
this.emitUserLeftEvent(clientListener, clientUser.userId);
|
|
||||||
} else if (thing instanceof Group) {
|
|
||||||
this.emitDeleteGroupEvent(clientListener, thing.getId());
|
|
||||||
} else {
|
|
||||||
console.error('Unexpected type for Movable.');
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
emitPlayGlobalMessage(client: ExSocketInterface, playglobalmessage: PlayGlobalMessage) {
|
emitPlayGlobalMessage(client: ExSocketInterface, playglobalmessage: PlayGlobalMessage) {
|
||||||
const pusherToBackMessage = new PusherToBackMessage();
|
const pusherToBackMessage = new PusherToBackMessage();
|
||||||
pusherToBackMessage.setPlayglobalmessage(playglobalmessage);
|
pusherToBackMessage.setPlayglobalmessage(playglobalmessage);
|
||||||
|
Loading…
Reference in New Issue
Block a user