Adding an "alone" mode

In "alone" mode (or single-player mode), WorkAdventure does not connect to the server at all.
In order to enter the "alone" mode, you need to add "?alone=true" to the URL.

"alone" mode can be useful for tutorials (First Time User Experience) where you want to explain how WorkAdventure works without being disturbed by other users.
This commit is contained in:
David Négrier 2021-03-30 16:08:49 +02:00
parent ad4f8e892e
commit 559e15ebb6
4 changed files with 54 additions and 28 deletions

View File

@ -14,11 +14,11 @@ class ConnectionManager {
private connexionType?: GameConnexionTypes private connexionType?: GameConnexionTypes
private reconnectingTimeout: NodeJS.Timeout|null = null; private reconnectingTimeout: NodeJS.Timeout|null = null;
private _unloading:boolean = false; private _unloading:boolean = false;
get unloading () { get unloading () {
return this._unloading; return this._unloading;
} }
constructor() { constructor() {
window.addEventListener('beforeunload', () => { window.addEventListener('beforeunload', () => {
this._unloading = true; this._unloading = true;
@ -42,7 +42,7 @@ class ConnectionManager {
const worldSlug = data.worldSlug; const worldSlug = data.worldSlug;
const roomSlug = data.roomSlug; const roomSlug = data.roomSlug;
const room = new Room('/@/'+organizationSlug+'/'+worldSlug+'/'+roomSlug + window.location.hash); const room = new Room('/@/'+organizationSlug+'/'+worldSlug+'/'+roomSlug + window.location.search + window.location.hash);
urlManager.pushRoomIdToUrl(room); urlManager.pushRoomIdToUrl(room);
return Promise.resolve(room); return Promise.resolve(room);
} else if (connexionType === GameConnexionTypes.organization || connexionType === GameConnexionTypes.anonymous || connexionType === GameConnexionTypes.empty) { } else if (connexionType === GameConnexionTypes.organization || connexionType === GameConnexionTypes.anonymous || connexionType === GameConnexionTypes.empty) {
@ -64,7 +64,7 @@ class ConnectionManager {
if (connexionType === GameConnexionTypes.empty) { if (connexionType === GameConnexionTypes.empty) {
roomId = START_ROOM_URL; roomId = START_ROOM_URL;
} else { } else {
roomId = window.location.pathname + window.location.hash; roomId = window.location.pathname + window.location.search + window.location.hash;
} }
return Promise.resolve(new Room(roomId)); return Promise.resolve(new Room(roomId));
} }

View File

@ -6,24 +6,25 @@ export class Room {
public readonly isPublic: boolean; public readonly isPublic: boolean;
private mapUrl: string|undefined; private mapUrl: string|undefined;
private instance: string|undefined; private instance: string|undefined;
private _search: URLSearchParams;
constructor(id: string) { constructor(id: string) {
if (id.startsWith('/')) { const url = new URL(id, 'https://example.com');
id = id.substr(1);
this.id = url.pathname;
if (this.id.startsWith('/')) {
this.id = this.id.substr(1);
} }
this.id = id; if (this.id.startsWith('_/')) {
if (id.startsWith('_/')) {
this.isPublic = true; this.isPublic = true;
} else if (id.startsWith('@/')) { } else if (this.id.startsWith('@/')) {
this.isPublic = false; this.isPublic = false;
} else { } else {
throw new Error('Invalid room ID'); throw new Error('Invalid room ID');
} }
const indexOfHash = this.id.indexOf('#'); this._search = new URLSearchParams(url.search);
if (indexOfHash !== -1) {
this.id = this.id.substr(0, indexOfHash);
}
} }
public static getIdFromIdentifier(identifier: string, baseUrl: string, currentInstance: string): {roomId: string, hash: string} { public static getIdFromIdentifier(identifier: string, baseUrl: string, currentInstance: string): {roomId: string, hash: string} {
@ -117,4 +118,17 @@ export class Room {
} }
return results; return results;
} }
public isDisconnected(): boolean
{
const alone = this._search.get('alone');
if (alone && alone !== '0' && alone.toLowerCase() !== 'false') {
return true;
}
return false;
}
public get search(): URLSearchParams {
return this._search;
}
} }

View File

@ -306,7 +306,7 @@ 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 = worldFullMessageStream.stream.subscribe((message) => this.showWorldFullError()) this.messageSubscription = worldFullMessageStream.stream.subscribe((message) => this.showWorldFullError())
const playerName = gameManager.getPlayerName(); const playerName = gameManager.getPlayerName();
@ -373,19 +373,21 @@ export class GameScene extends ResizableScene implements CenterListener {
this.initCirclesCanvas(); this.initCirclesCanvas();
// Let's pause the scene if the connection is not established yet // Let's pause the scene if the connection is not established yet
if (this.isReconnecting) { if (!this.room.isDisconnected()) {
setTimeout(() => { if (this.isReconnecting) {
this.scene.sleep(); setTimeout(() => {
this.scene.launch(ReconnectingSceneName);
}, 0);
} else if (this.connection === undefined) {
// Let's wait 1 second before printing the "connecting" screen to avoid blinking
setTimeout(() => {
if (this.connection === undefined) {
this.scene.sleep(); this.scene.sleep();
this.scene.launch(ReconnectingSceneName); this.scene.launch(ReconnectingSceneName);
} }, 0);
}, 1000); } else if (this.connection === undefined) {
// Let's wait 1 second before printing the "connecting" screen to avoid blinking
setTimeout(() => {
if (this.connection === undefined) {
this.scene.sleep();
this.scene.launch(ReconnectingSceneName);
}
}, 1000);
}
} }
this.createPromiseResolve(); this.createPromiseResolve();
@ -411,6 +413,16 @@ export class GameScene extends ResizableScene implements CenterListener {
layoutManager.setListener(this); layoutManager.setListener(this);
this.triggerOnMapLayerPropertyChange(); this.triggerOnMapLayerPropertyChange();
if (!this.room.isDisconnected()) {
this.connect();
}
}
/**
* Initializes the connection to Pusher.
*/
private connect(): void {
const camera = this.cameras.main; const camera = this.cameras.main;
connectionManager.connectToRoomSocket( connectionManager.connectToRoomSocket(
@ -548,7 +560,6 @@ export class GameScene extends ResizableScene implements CenterListener {
}); });
} }
//todo: into dedicated classes //todo: into dedicated classes
private initCirclesCanvas(): void { private initCirclesCanvas(): void {
// Let's generate the circle for the group delimiter // Let's generate the circle for the group delimiter
@ -582,7 +593,7 @@ export class GameScene extends ResizableScene implements CenterListener {
contextRed.stroke(); contextRed.stroke();
this.circleRedTexture.refresh(); this.circleRedTexture.refresh();
} }
private safeParseJSONstring(jsonString: string|undefined, propertyName: string) { private safeParseJSONstring(jsonString: string|undefined, propertyName: string) {
try { try {

View File

@ -35,7 +35,8 @@ class UrlManager {
public pushRoomIdToUrl(room:Room): void { public pushRoomIdToUrl(room:Room): void {
if (window.location.pathname === room.id) return; if (window.location.pathname === room.id) return;
const hash = window.location.hash; const hash = window.location.hash;
history.pushState({}, 'WorkAdventure', room.id+hash); const search = room.search.toString();
history.pushState({}, 'WorkAdventure', room.id+(search?'?'+search:'')+hash);
} }
public getStartLayerNameFromUrl(): string|null { public getStartLayerNameFromUrl(): string|null {