Merge branch 'develop' of github.com:thecodingmachine/workadventure into windows-focus-blur-camera
This commit is contained in:
commit
00b83ae349
12
.github/workflows/build-and-deploy.yml
vendored
12
.github/workflows/build-and-deploy.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
# Create a slugified value of the branch
|
# Create a slugified value of the branch
|
||||||
- uses: rlespinasse/github-slug-action@master
|
- uses: rlespinasse/github-slug-action@1.1.1
|
||||||
|
|
||||||
- name: "Build and push front image"
|
- name: "Build and push front image"
|
||||||
uses: docker/build-push-action@v1
|
uses: docker/build-push-action@v1
|
||||||
@ -43,7 +43,7 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
# Create a slugified value of the branch
|
# Create a slugified value of the branch
|
||||||
- uses: rlespinasse/github-slug-action@master
|
- uses: rlespinasse/github-slug-action@1.1.1
|
||||||
|
|
||||||
- name: "Build and push back image"
|
- name: "Build and push back image"
|
||||||
uses: docker/build-push-action@v1
|
uses: docker/build-push-action@v1
|
||||||
@ -66,7 +66,7 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
# Create a slugified value of the branch
|
# Create a slugified value of the branch
|
||||||
- uses: rlespinasse/github-slug-action@master
|
- uses: rlespinasse/github-slug-action@1.1.1
|
||||||
|
|
||||||
- name: "Build and push back image"
|
- name: "Build and push back image"
|
||||||
uses: docker/build-push-action@v1
|
uses: docker/build-push-action@v1
|
||||||
@ -90,7 +90,7 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
# Create a slugified value of the branch
|
# Create a slugified value of the branch
|
||||||
- uses: rlespinasse/github-slug-action@master
|
- uses: rlespinasse/github-slug-action@1.1.1
|
||||||
|
|
||||||
- name: "Build and push front image"
|
- name: "Build and push front image"
|
||||||
uses: docker/build-push-action@v1
|
uses: docker/build-push-action@v1
|
||||||
@ -137,7 +137,7 @@ jobs:
|
|||||||
check_for_duplicate_msg: true
|
check_for_duplicate_msg: true
|
||||||
|
|
||||||
- name: Run Cypress tests
|
- name: Run Cypress tests
|
||||||
uses: cypress-io/github-action@v1
|
uses: cypress-io/github-action@v2
|
||||||
if: ${{ env.GITHUB_REF_SLUG != 'master' }}
|
if: ${{ env.GITHUB_REF_SLUG != 'master' }}
|
||||||
env:
|
env:
|
||||||
CYPRESS_BASE_URL: https://play.${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com
|
CYPRESS_BASE_URL: https://play.${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com
|
||||||
@ -148,7 +148,7 @@ jobs:
|
|||||||
working-directory: e2e
|
working-directory: e2e
|
||||||
|
|
||||||
- name: Run Cypress tests in prod
|
- name: Run Cypress tests in prod
|
||||||
uses: cypress-io/github-action@v1
|
uses: cypress-io/github-action@v2
|
||||||
if: ${{ env.GITHUB_REF_SLUG == 'master' }}
|
if: ${{ env.GITHUB_REF_SLUG == 'master' }}
|
||||||
env:
|
env:
|
||||||
CYPRESS_BASE_URL: https://play.workadventu.re
|
CYPRESS_BASE_URL: https://play.workadventu.re
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
"multer": "^1.4.2",
|
"multer": "^1.4.2",
|
||||||
"prom-client": "^12.0.0",
|
"prom-client": "^12.0.0",
|
||||||
"query-string": "^6.13.3",
|
"query-string": "^6.13.3",
|
||||||
"systeminformation": "^4.26.5",
|
"systeminformation": "^4.27.11",
|
||||||
"ts-node-dev": "^1.0.0-pre.44",
|
"ts-node-dev": "^1.0.0-pre.44",
|
||||||
"typescript": "^3.8.3",
|
"typescript": "^3.8.3",
|
||||||
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
|
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
|
||||||
|
@ -22,7 +22,7 @@ import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Serv
|
|||||||
import {SocketManager, socketManager} from "../Services/SocketManager";
|
import {SocketManager, socketManager} from "../Services/SocketManager";
|
||||||
import {emitInBatch, resetPing} from "../Services/IoSocketHelpers";
|
import {emitInBatch, resetPing} from "../Services/IoSocketHelpers";
|
||||||
import {clientEventsEmitter} from "../Services/ClientEventsEmitter";
|
import {clientEventsEmitter} from "../Services/ClientEventsEmitter";
|
||||||
import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable";
|
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
export class IoSocketController {
|
export class IoSocketController {
|
||||||
private nextUserId: number = 1;
|
private nextUserId: number = 1;
|
||||||
@ -166,18 +166,21 @@ export class IoSocketController {
|
|||||||
if(room.isFull){
|
if(room.isFull){
|
||||||
throw new Error('Room is full');
|
throw new Error('Room is full');
|
||||||
}
|
}
|
||||||
try {
|
if (ADMIN_API_URL) {
|
||||||
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
try {
|
||||||
//console.log('USERDATA', userData)
|
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
||||||
memberTags = userData.tags;
|
//console.log('USERDATA', userData)
|
||||||
memberTextures = userData.textures;
|
memberTags = userData.tags;
|
||||||
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && !room.canAccess(memberTags)) {
|
memberTextures = userData.textures;
|
||||||
throw new Error('No correct tags')
|
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && !room.canAccess(memberTags)) {
|
||||||
|
throw new Error('No correct tags')
|
||||||
|
}
|
||||||
|
//console.log('access granted for user '+userUuid+' and room '+roomId);
|
||||||
|
} catch (e) {
|
||||||
|
console.log('access not granted for user '+userUuid+' and room '+roomId);
|
||||||
|
console.error(e);
|
||||||
|
throw new Error('Client cannot acces this ressource.')
|
||||||
}
|
}
|
||||||
//console.log('access granted for user '+userUuid+' and room '+roomId);
|
|
||||||
} catch (e) {
|
|
||||||
console.log('access not granted for user '+userUuid+' and room '+roomId);
|
|
||||||
throw new Error('Client cannot acces this ressource.')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate characterLayers objects from characterLayers string[]
|
// Generate characterLayers objects from characterLayers string[]
|
||||||
@ -238,22 +241,24 @@ export class IoSocketController {
|
|||||||
socketManager.handleJoinRoom(client);
|
socketManager.handleJoinRoom(client);
|
||||||
resetPing(client);
|
resetPing(client);
|
||||||
|
|
||||||
//get data information and shwo messages
|
//get data information and show messages
|
||||||
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: FetchMemberDataByUuidResponse) => {
|
if (ADMIN_API_URL) {
|
||||||
if (!res.messages) {
|
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: FetchMemberDataByUuidResponse) => {
|
||||||
return;
|
if (!res.messages) {
|
||||||
}
|
return;
|
||||||
res.messages.forEach((c: unknown) => {
|
}
|
||||||
const messageToSend = c as { type: string, message: string };
|
res.messages.forEach((c: unknown) => {
|
||||||
socketManager.emitSendUserMessage({
|
const messageToSend = c as { type: string, message: string };
|
||||||
userUuid: client.userUuid,
|
socketManager.emitSendUserMessage({
|
||||||
type: messageToSend.type,
|
userUuid: client.userUuid,
|
||||||
message: messageToSend.message
|
type: messageToSend.type,
|
||||||
})
|
message: messageToSend.message
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error('fetchMemberDataByUuid => err', err);
|
||||||
});
|
});
|
||||||
}).catch((err) => {
|
}
|
||||||
console.error('fetchMemberDataByUuid => err', err);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
message: (ws, arrayBuffer, isBinary): void => {
|
message: (ws, arrayBuffer, isBinary): void => {
|
||||||
const client = ws as ExSocketInterface;
|
const client = ws as ExSocketInterface;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {App} from "../Server/sifrr.server";
|
import {App} from "../Server/sifrr.server";
|
||||||
import {IoSocketController} from "_Controller/IoSocketController";
|
|
||||||
import {HttpRequest, HttpResponse} from "uWebSockets.js";
|
import {HttpRequest, HttpResponse} from "uWebSockets.js";
|
||||||
const register = require('prom-client').register;
|
const register = require('prom-client').register;
|
||||||
const collectDefaultMetrics = require('prom-client').collectDefaultMetrics;
|
const collectDefaultMetrics = require('prom-client').collectDefaultMetrics;
|
||||||
|
@ -3,7 +3,7 @@ const URL_ROOM_STARTED = "/Floor0/floor0.json";
|
|||||||
const MINIMUM_DISTANCE = process.env.MINIMUM_DISTANCE ? Number(process.env.MINIMUM_DISTANCE) : 64;
|
const MINIMUM_DISTANCE = process.env.MINIMUM_DISTANCE ? Number(process.env.MINIMUM_DISTANCE) : 64;
|
||||||
const GROUP_RADIUS = process.env.GROUP_RADIUS ? Number(process.env.GROUP_RADIUS) : 48;
|
const GROUP_RADIUS = process.env.GROUP_RADIUS ? Number(process.env.GROUP_RADIUS) : 48;
|
||||||
const ALLOW_ARTILLERY = process.env.ALLOW_ARTILLERY ? process.env.ALLOW_ARTILLERY == 'true' : false;
|
const ALLOW_ARTILLERY = process.env.ALLOW_ARTILLERY ? process.env.ALLOW_ARTILLERY == 'true' : false;
|
||||||
const ADMIN_API_URL = process.env.ADMIN_API_URL || 'http://admin';
|
const ADMIN_API_URL = process.env.ADMIN_API_URL || '';
|
||||||
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || 'myapitoken';
|
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || 'myapitoken';
|
||||||
const MAX_USERS_PER_ROOM = parseInt(process.env.MAX_USERS_PER_ROOM || '') || 600;
|
const MAX_USERS_PER_ROOM = parseInt(process.env.MAX_USERS_PER_ROOM || '') || 600;
|
||||||
const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80;
|
const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80;
|
||||||
|
@ -152,7 +152,7 @@ export class GameRoom {
|
|||||||
closestItem.join(user);
|
closestItem.join(user);
|
||||||
} else {
|
} else {
|
||||||
const closestUser : User = closestItem;
|
const closestUser : User = closestItem;
|
||||||
const group: Group = new Group([
|
const group: Group = new Group(this.roomId,[
|
||||||
user,
|
user,
|
||||||
closestUser
|
closestUser
|
||||||
], this.connectCallback, this.disconnectCallback, this.positionNotifier);
|
], this.connectCallback, this.disconnectCallback, this.positionNotifier);
|
||||||
@ -200,7 +200,6 @@ export class GameRoom {
|
|||||||
if (group === undefined) {
|
if (group === undefined) {
|
||||||
throw new Error("The user is part of no group");
|
throw new Error("The user is part of no group");
|
||||||
}
|
}
|
||||||
const oldPosition = group.getPosition();
|
|
||||||
group.leave(user);
|
group.leave(user);
|
||||||
if (group.isEmpty()) {
|
if (group.isEmpty()) {
|
||||||
this.positionNotifier.leave(group);
|
this.positionNotifier.leave(group);
|
||||||
@ -209,6 +208,7 @@ export class GameRoom {
|
|||||||
throw new Error("Could not find group "+group.getId()+" referenced by user "+user.id+" in World.");
|
throw new Error("Could not find group "+group.getId()+" referenced by user "+user.id+" in World.");
|
||||||
}
|
}
|
||||||
this.groups.delete(group);
|
this.groups.delete(group);
|
||||||
|
//todo: is the group garbage collected?
|
||||||
} else {
|
} else {
|
||||||
group.updatePosition();
|
group.updatePosition();
|
||||||
//this.positionNotifier.updatePosition(group, group.getPosition(), oldPosition);
|
//this.positionNotifier.updatePosition(group, group.getPosition(), oldPosition);
|
||||||
|
@ -3,6 +3,7 @@ import { User } from "./User";
|
|||||||
import {PositionInterface} from "_Model/PositionInterface";
|
import {PositionInterface} from "_Model/PositionInterface";
|
||||||
import {Movable} from "_Model/Movable";
|
import {Movable} from "_Model/Movable";
|
||||||
import {PositionNotifier} from "_Model/PositionNotifier";
|
import {PositionNotifier} from "_Model/PositionNotifier";
|
||||||
|
import {gaugeManager} from "../Services/GaugeManager";
|
||||||
|
|
||||||
export class Group implements Movable {
|
export class Group implements Movable {
|
||||||
static readonly MAX_PER_GROUP = 4;
|
static readonly MAX_PER_GROUP = 4;
|
||||||
@ -13,12 +14,23 @@ export class Group implements Movable {
|
|||||||
private users: Set<User>;
|
private users: Set<User>;
|
||||||
private x!: number;
|
private x!: number;
|
||||||
private y!: number;
|
private y!: number;
|
||||||
|
private hasEditedGauge: boolean = false;
|
||||||
|
private wasDestroyed: boolean = false;
|
||||||
|
private roomId: string;
|
||||||
|
|
||||||
|
|
||||||
constructor(users: User[], private connectCallback: ConnectCallback, private disconnectCallback: DisconnectCallback, private positionNotifier: PositionNotifier) {
|
constructor(roomId: string, users: User[], private connectCallback: ConnectCallback, private disconnectCallback: DisconnectCallback, private positionNotifier: PositionNotifier) {
|
||||||
|
this.roomId = roomId;
|
||||||
this.users = new Set<User>();
|
this.users = new Set<User>();
|
||||||
this.id = Group.nextId;
|
this.id = Group.nextId;
|
||||||
Group.nextId++;
|
Group.nextId++;
|
||||||
|
//we only send a event for prometheus metrics if the group lives more than 5 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.wasDestroyed) {
|
||||||
|
this.hasEditedGauge = true;
|
||||||
|
gaugeManager.incNbGroupsPerRoomGauge(roomId);
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
users.forEach((user: User) => {
|
users.forEach((user: User) => {
|
||||||
this.join(user);
|
this.join(user);
|
||||||
@ -113,9 +125,11 @@ export class Group implements Movable {
|
|||||||
*/
|
*/
|
||||||
destroy(): void
|
destroy(): void
|
||||||
{
|
{
|
||||||
|
if (this.hasEditedGauge) gaugeManager.decNbGroupsPerRoomGauge(this.roomId);
|
||||||
for (const user of this.users) {
|
for (const user of this.users) {
|
||||||
this.leave(user);
|
this.leave(user);
|
||||||
}
|
}
|
||||||
|
this.wasDestroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
get getSize(){
|
get getSize(){
|
||||||
|
54
back/src/Services/GaugeManager.ts
Normal file
54
back/src/Services/GaugeManager.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import {Counter, Gauge} from "prom-client";
|
||||||
|
|
||||||
|
//this class should manage all the custom metrics used by prometheus
|
||||||
|
class GaugeManager {
|
||||||
|
private nbClientsGauge: Gauge<string>;
|
||||||
|
private nbClientsPerRoomGauge: Gauge<string>;
|
||||||
|
private nbGroupsPerRoomGauge: Gauge<string>;
|
||||||
|
private nbGroupsPerRoomCounter: Counter<string>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.nbClientsGauge = new Gauge({
|
||||||
|
name: 'workadventure_nb_sockets',
|
||||||
|
help: 'Number of connected sockets',
|
||||||
|
labelNames: [ ]
|
||||||
|
});
|
||||||
|
this.nbClientsPerRoomGauge = new Gauge({
|
||||||
|
name: 'workadventure_nb_clients_per_room',
|
||||||
|
help: 'Number of clients per room',
|
||||||
|
labelNames: [ 'room' ]
|
||||||
|
});
|
||||||
|
|
||||||
|
this.nbGroupsPerRoomCounter = new Counter({
|
||||||
|
name: 'workadventure_counter_groups_per_room',
|
||||||
|
help: 'Counter of groups per room',
|
||||||
|
labelNames: [ 'room' ]
|
||||||
|
});
|
||||||
|
this.nbGroupsPerRoomGauge = new Gauge({
|
||||||
|
name: 'workadventure_nb_groups_per_room',
|
||||||
|
help: 'Number of groups per room',
|
||||||
|
labelNames: [ 'room' ]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
incNbClientPerRoomGauge(roomId: string): void {
|
||||||
|
this.nbClientsGauge.inc();
|
||||||
|
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
||||||
|
}
|
||||||
|
|
||||||
|
decNbClientPerRoomGauge(roomId: string): void {
|
||||||
|
this.nbClientsGauge.dec();
|
||||||
|
this.nbClientsPerRoomGauge.dec({ room: roomId });
|
||||||
|
}
|
||||||
|
|
||||||
|
incNbGroupsPerRoomGauge(roomId: string): void {
|
||||||
|
this.nbGroupsPerRoomCounter.inc({ room: roomId })
|
||||||
|
this.nbGroupsPerRoomGauge.inc({ room: roomId })
|
||||||
|
}
|
||||||
|
|
||||||
|
decNbGroupsPerRoomGauge(roomId: string): void {
|
||||||
|
this.nbGroupsPerRoomGauge.dec({ room: roomId })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const gaugeManager = new GaugeManager();
|
@ -1,4 +1,4 @@
|
|||||||
import {ALLOW_ARTILLERY, SECRET_KEY} from "../Enum/EnvironmentVariable";
|
import {ADMIN_API_URL, ALLOW_ARTILLERY, SECRET_KEY} from "../Enum/EnvironmentVariable";
|
||||||
import {uuid} from "uuidv4";
|
import {uuid} from "uuidv4";
|
||||||
import Jwt from "jsonwebtoken";
|
import Jwt from "jsonwebtoken";
|
||||||
import {TokenInterface} from "../Controller/AuthenticateController";
|
import {TokenInterface} from "../Controller/AuthenticateController";
|
||||||
@ -48,17 +48,21 @@ class JWTTokenManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//verify user in admin
|
if (ADMIN_API_URL) {
|
||||||
adminApi.fetchCheckUserByToken(tokenInterface.userUuid).then(() => {
|
//verify user in admin
|
||||||
resolve(tokenInterface.userUuid);
|
adminApi.fetchCheckUserByToken(tokenInterface.userUuid).then(() => {
|
||||||
}).catch((err) => {
|
|
||||||
//anonymous user
|
|
||||||
if(err.response && err.response.status && err.response.status === 404){
|
|
||||||
resolve(tokenInterface.userUuid);
|
resolve(tokenInterface.userUuid);
|
||||||
return;
|
}).catch((err) => {
|
||||||
}
|
//anonymous user
|
||||||
reject(new Error('Authentication error, invalid token structure. ' + err));
|
if(err.response && err.response.status && err.response.status === 404){
|
||||||
});
|
resolve(tokenInterface.userUuid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve(tokenInterface.userUuid);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ import {
|
|||||||
WebRtcStartMessage,
|
WebRtcStartMessage,
|
||||||
QueryJitsiJwtMessage,
|
QueryJitsiJwtMessage,
|
||||||
SendJitsiJwtMessage,
|
SendJitsiJwtMessage,
|
||||||
CharacterLayerMessage,
|
|
||||||
SendUserMessage
|
SendUserMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
import {PointInterface} from "../Model/Websocket/PointInterface";
|
||||||
@ -37,11 +36,11 @@ import {Movable} from "../Model/Movable";
|
|||||||
import {PositionInterface} from "../Model/PositionInterface";
|
import {PositionInterface} from "../Model/PositionInterface";
|
||||||
import {adminApi, CharacterTexture} from "./AdminApi";
|
import {adminApi, CharacterTexture} from "./AdminApi";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {Gauge} from "prom-client";
|
|
||||||
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";
|
||||||
|
|
||||||
interface AdminSocketRoomsList {
|
interface AdminSocketRoomsList {
|
||||||
[index: string]: number;
|
[index: string]: number;
|
||||||
@ -58,30 +57,13 @@ export interface AdminSocketData {
|
|||||||
export class SocketManager {
|
export class SocketManager {
|
||||||
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
||||||
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
||||||
private nbClientsGauge: Gauge<string>;
|
|
||||||
private nbClientsPerRoomGauge: Gauge<string>;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.nbClientsGauge = new Gauge({
|
clientEventsEmitter.registerToClientJoin((clientUUid: string, roomId: string) => {
|
||||||
name: 'workadventure_nb_sockets',
|
gaugeManager.incNbClientPerRoomGauge(roomId);
|
||||||
help: 'Number of connected sockets',
|
|
||||||
labelNames: [ ]
|
|
||||||
});
|
});
|
||||||
this.nbClientsPerRoomGauge = new Gauge({
|
clientEventsEmitter.registerToClientLeave((clientUUid: string, roomId: string) => {
|
||||||
name: 'workadventure_nb_clients_per_room',
|
gaugeManager.decNbClientPerRoomGauge(roomId);
|
||||||
help: 'Number of clients per room',
|
|
||||||
labelNames: [ 'room' ]
|
|
||||||
});
|
|
||||||
|
|
||||||
clientEventsEmitter.registerToClientJoin((clientUUid, roomId) => {
|
|
||||||
this.nbClientsGauge.inc();
|
|
||||||
// Let's log server load when a user joins
|
|
||||||
console.log(new Date().toISOString() + ' A user joined (', this.sockets.size, ' connected users)');
|
|
||||||
});
|
|
||||||
clientEventsEmitter.registerToClientLeave((clientUUid, roomId) => {
|
|
||||||
this.nbClientsGauge.dec();
|
|
||||||
// Let's log server load when a user leaves
|
|
||||||
console.log('A user left (', this.sockets.size, ' connected users)');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +89,6 @@ export class SocketManager {
|
|||||||
const viewport = client.viewport;
|
const viewport = client.viewport;
|
||||||
try {
|
try {
|
||||||
this.sockets.set(client.userId, client); //todo: should this be at the end of the function?
|
this.sockets.set(client.userId, client); //todo: should this be at the end of the function?
|
||||||
clientEventsEmitter.emitClientJoin(client.userUuid, client.roomId);
|
|
||||||
//join new previous room
|
//join new previous room
|
||||||
const gameRoom = this.joinRoom(client, position);
|
const gameRoom = this.joinRoom(client, position);
|
||||||
|
|
||||||
@ -377,8 +358,8 @@ export class SocketManager {
|
|||||||
} finally {
|
} finally {
|
||||||
//delete Client.roomId;
|
//delete Client.roomId;
|
||||||
this.sockets.delete(Client.userId);
|
this.sockets.delete(Client.userId);
|
||||||
this.nbClientsPerRoomGauge.dec({ room: Client.roomId });
|
|
||||||
clientEventsEmitter.emitClientLeave(Client.userUuid, Client.roomId);
|
clientEventsEmitter.emitClientLeave(Client.userUuid, Client.roomId);
|
||||||
|
console.log('A user left (', this.sockets.size, ' connected users)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -410,8 +391,6 @@ export class SocketManager {
|
|||||||
private joinRoom(client : ExSocketInterface, position: PointInterface): GameRoom {
|
private joinRoom(client : ExSocketInterface, position: PointInterface): GameRoom {
|
||||||
|
|
||||||
const roomId = client.roomId;
|
const roomId = client.roomId;
|
||||||
//join user in room
|
|
||||||
this.nbClientsPerRoomGauge.inc({ room: roomId });
|
|
||||||
client.position = position;
|
client.position = position;
|
||||||
|
|
||||||
const world = this.Worlds.get(roomId)
|
const world = this.Worlds.get(roomId)
|
||||||
@ -425,6 +404,8 @@ export class SocketManager {
|
|||||||
});
|
});
|
||||||
//join world
|
//join world
|
||||||
world.join(client, client.position);
|
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;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2345,10 +2345,10 @@ supports-color@^7.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
systeminformation@^4.26.5:
|
systeminformation@^4.27.11:
|
||||||
version "4.27.5"
|
version "4.27.11"
|
||||||
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.27.5.tgz#af304fbfd0e7ba51c87512333691b58b4ad90e43"
|
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.27.11.tgz#6dbe96e48091444f80dab6c05ee1901286826b60"
|
||||||
integrity sha512-EysogxKqREk54ZYDEFcsCODv8GymKZcyiSfegYit8dKhPjzuQr+KX4GFHjssWjYrWFEIM2bYNsFrZX5eufeAXg==
|
integrity sha512-U7bigXbOnsB8k1vNHS0Y13RCsRz5/UohiUmND+3mMUL6vfzrpbe/h4ZqewowB+B+tJNnmGFDj08Z8xGfYo45dQ==
|
||||||
|
|
||||||
table@^5.2.3:
|
table@^5.2.3:
|
||||||
version "5.4.6"
|
version "5.4.6"
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
local namespace = env.GITHUB_REF_SLUG,
|
local namespace = env.GITHUB_REF_SLUG,
|
||||||
local tag = namespace,
|
local tag = namespace,
|
||||||
local url = if namespace == "master" then "workadventu.re" else namespace+".workadventure.test.thecodingmachine.com",
|
local url = if namespace == "master" then "workadventu.re" else namespace+".workadventure.test.thecodingmachine.com",
|
||||||
|
local adminUrl = if namespace == "master" || namespace == "develop" || std.startsWith(namespace, "admin") then "https://admin."+url else null,
|
||||||
"$schema": "https://raw.githubusercontent.com/thecodingmachine/deeployer/master/deeployer.schema.json",
|
"$schema": "https://raw.githubusercontent.com/thecodingmachine/deeployer/master/deeployer.schema.json",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"containers": {
|
"containers": {
|
||||||
@ -16,11 +17,12 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"SECRET_KEY": "tempSecretKeyNeedsToChange",
|
"SECRET_KEY": "tempSecretKeyNeedsToChange",
|
||||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||||
"ADMIN_API_URL": "https://admin."+url,
|
|
||||||
"JITSI_ISS": env.JITSI_ISS,
|
"JITSI_ISS": env.JITSI_ISS,
|
||||||
"JITSI_URL": env.JITSI_URL,
|
"JITSI_URL": env.JITSI_URL,
|
||||||
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||||
}
|
} + if adminUrl != null then {
|
||||||
|
"ADMIN_API_URL": adminUrl,
|
||||||
|
} else {}
|
||||||
},
|
},
|
||||||
"front": {
|
"front": {
|
||||||
"image": "thecodingmachine/workadventure-front:"+tag,
|
"image": "thecodingmachine/workadventure-front:"+tag,
|
||||||
|
22
front/dist/index.html
vendored
22
front/dist/index.html
vendored
@ -42,30 +42,14 @@
|
|||||||
<body id="body" style="margin: 0">
|
<body id="body" style="margin: 0">
|
||||||
<div class="main-container" id="main-container">
|
<div class="main-container" id="main-container">
|
||||||
<!-- Create the editor container -->
|
<!-- Create the editor container -->
|
||||||
<div id="game" class="game" style="/*background: red;*/">
|
<div id="game" class="game">
|
||||||
<div id="game-overlay" class="game-overlay" style="/*background: violet*/;">
|
<div id="game-overlay" class="game-overlay">
|
||||||
<div id="main-section" class="main-section">
|
<div id="main-section" class="main-section">
|
||||||
<!--<div style="background: lightpink;">a</div>
|
|
||||||
<div style="background: lightpink;">a</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<aside id="sidebar" class="sidebar">
|
<aside id="sidebar" class="sidebar">
|
||||||
<!--<div style="background: lightgreen;">a</div>
|
|
||||||
<div style="background: green;">b</div>
|
|
||||||
<div style="background: darkgreen;">c</div>
|
|
||||||
<div style="background: darkgreen;">d</div>-->
|
|
||||||
</aside>
|
</aside>
|
||||||
<div id="chat-mode" class="chat-mode three-col" style="display: none;">
|
<div id="chat-mode" class="chat-mode three-col" style="display: none;">
|
||||||
<!--<div style="background: lightgreen;">a</div>
|
|
||||||
<div style="background: green;">b</div>
|
|
||||||
<div style="background: darkgreen;">c</div>
|
|
||||||
<div style="background: darkolivegreen;">d</div>
|
|
||||||
<div style="background: darkolivegreen;">d</div>
|
|
||||||
<div style="background: darkgreen;">c</div>
|
|
||||||
<div style="background: green;">b</div>
|
|
||||||
<div style="background: lightgreen;">last elem for game</div>-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div id="activeCam" class="activeCam">
|
<div id="activeCam" class="activeCam">
|
||||||
<div id="div-myCamVideo" class="video-container">
|
<div id="div-myCamVideo" class="video-container">
|
||||||
<video id="myCamVideo" autoplay muted></video>
|
<video id="myCamVideo" autoplay muted></video>
|
||||||
@ -88,7 +72,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="cowebsite" class="cowebsite"></div>
|
<div id="cowebsite" class="cowebsite hidden"></div>
|
||||||
<div class="audio-playing">
|
<div class="audio-playing">
|
||||||
<img src="/resources/logos/megaphone.svg"/>
|
<img src="/resources/logos/megaphone.svg"/>
|
||||||
</div>
|
</div>
|
||||||
|
56
front/dist/resources/style/style.css
vendored
56
front/dist/resources/style/style.css
vendored
@ -242,15 +242,10 @@ body {
|
|||||||
.main-container {
|
.main-container {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
display: flex;
|
position: absolute;
|
||||||
align-items: stretch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-aspect-ratio: 1/1) {
|
@media (min-aspect-ratio: 1/1) {
|
||||||
.main-container {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-overlay {
|
.game-overlay {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
@ -266,12 +261,21 @@ body {
|
|||||||
.sidebar > div:hover {
|
.sidebar > div:hover {
|
||||||
max-height: 25%;
|
max-height: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cowebsite {
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 50%;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
#cowebsite.loading {
|
||||||
|
transform: translateX(90%);
|
||||||
|
}
|
||||||
|
#cowebsite.hidden {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media (max-aspect-ratio: 1/1) {
|
@media (max-aspect-ratio: 1/1) {
|
||||||
.main-container {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-overlay {
|
.game-overlay {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@ -288,24 +292,36 @@ body {
|
|||||||
.sidebar > div:hover {
|
.sidebar > div:hover {
|
||||||
max-width: 25%;
|
max-width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cowebsite {
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
#cowebsite.loading {
|
||||||
|
transform: translateY(90%);
|
||||||
|
}
|
||||||
|
#cowebsite.hidden {
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.game {
|
#game {
|
||||||
flex-basis: 100%;
|
width: 100%;
|
||||||
position: relative; /* Position relative is needed for the game-overlay. */
|
position: relative; /* Position relative is needed for the game-overlay. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A potentially shared website could appear in an iframe in the cowebsite space. */
|
/* A potentially shared website could appear in an iframe in the cowebsite space. */
|
||||||
.cowebsite {
|
#cowebsite {
|
||||||
flex-basis: 100%;
|
position: fixed;
|
||||||
transition: flex-basis 0.5s;
|
transition: transform 0.5s;
|
||||||
|
}
|
||||||
|
#cowebsite.loading {
|
||||||
|
background-color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*.cowebsite:hover {
|
#cowebsite > iframe {
|
||||||
flex-basis: 100%;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
.cowebsite > iframe {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ import CanvasTexture = Phaser.Textures.CanvasTexture;
|
|||||||
import GameObject = Phaser.GameObjects.GameObject;
|
import GameObject = Phaser.GameObjects.GameObject;
|
||||||
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
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";
|
||||||
import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
|
import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
|
||||||
import {ItemFactoryInterface} from "../Items/ItemFactoryInterface";
|
import {ItemFactoryInterface} from "../Items/ItemFactoryInterface";
|
||||||
@ -292,13 +292,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST: let's load a module dynamically!
|
|
||||||
/*let foo = "http://maps.workadventure.localhost/computer.js";
|
|
||||||
import(/* webpackIgnore: true * / foo).then(result => {
|
|
||||||
console.log(result);
|
|
||||||
|
|
||||||
});*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//hook initialisation
|
//hook initialisation
|
||||||
@ -476,9 +469,9 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
|
|
||||||
this.gameMap.onPropertyChange('openWebsite', (newValue, oldValue) => {
|
this.gameMap.onPropertyChange('openWebsite', (newValue, oldValue) => {
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
CoWebsiteManager.closeCoWebsite();
|
coWebsiteManager.closeCoWebsite();
|
||||||
} else {
|
} else {
|
||||||
CoWebsiteManager.loadCoWebsite(newValue as string);
|
coWebsiteManager.loadCoWebsite(newValue as string);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange('jitsiRoom', (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange('jitsiRoom', (newValue, oldValue, allProps) => {
|
||||||
|
@ -2,47 +2,90 @@ import {HtmlUtils} from "./HtmlUtils";
|
|||||||
|
|
||||||
export type CoWebsiteStateChangedCallback = () => void;
|
export type CoWebsiteStateChangedCallback = () => void;
|
||||||
|
|
||||||
export class CoWebsiteManager {
|
enum iframeStates {
|
||||||
|
closed = 1,
|
||||||
|
loading, // loading an iframe can be slow, so we show some placeholder until it is ready
|
||||||
|
opened,
|
||||||
|
}
|
||||||
|
|
||||||
private static observers = new Array<CoWebsiteStateChangedCallback>();
|
const cowebsiteDivId = "cowebsite"; // the id of the parent div of the iframe.
|
||||||
|
const animationTime = 500; //time used by the css transitions, in ms.
|
||||||
|
|
||||||
public static loadCoWebsite(url: string): void {
|
class CoWebsiteManager {
|
||||||
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite");
|
|
||||||
|
private opened: iframeStates = iframeStates.closed;
|
||||||
|
|
||||||
|
private observers = new Array<CoWebsiteStateChangedCallback>();
|
||||||
|
|
||||||
|
private close(): HTMLDivElement {
|
||||||
|
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId);
|
||||||
|
cowebsiteDiv.classList.remove('loaded'); //edit the css class to trigger the transition
|
||||||
|
cowebsiteDiv.classList.add('hidden');
|
||||||
|
this.opened = iframeStates.closed;
|
||||||
|
return cowebsiteDiv;
|
||||||
|
}
|
||||||
|
private load(): HTMLDivElement {
|
||||||
|
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId);
|
||||||
|
cowebsiteDiv.classList.remove('hidden'); //edit the css class to trigger the transition
|
||||||
|
cowebsiteDiv.classList.add('loading');
|
||||||
|
this.opened = iframeStates.loading;
|
||||||
|
return cowebsiteDiv;
|
||||||
|
}
|
||||||
|
private open(): HTMLDivElement {
|
||||||
|
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(cowebsiteDivId);
|
||||||
|
cowebsiteDiv.classList.remove('loading', 'hidden'); //edit the css class to trigger the transition
|
||||||
|
this.opened = iframeStates.opened;
|
||||||
|
return cowebsiteDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadCoWebsite(url: string): void {
|
||||||
|
const cowebsiteDiv = this.load();
|
||||||
cowebsiteDiv.innerHTML = '';
|
cowebsiteDiv.innerHTML = '';
|
||||||
|
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
iframe.id = 'cowebsite-iframe';
|
iframe.id = 'cowebsite-iframe';
|
||||||
iframe.src = url;
|
iframe.src = url;
|
||||||
|
const onloadPromise = new Promise((resolve) => {
|
||||||
|
iframe.onload = () => resolve();
|
||||||
|
});
|
||||||
cowebsiteDiv.appendChild(iframe);
|
cowebsiteDiv.appendChild(iframe);
|
||||||
//iframe.onload = () => {
|
const onTimeoutPromise = new Promise((resolve) => {
|
||||||
// onload can be long to trigger. Maybe we should display the website, whatever happens, after 1 second?
|
setTimeout(() => resolve(), 2000);
|
||||||
CoWebsiteManager.fire();
|
});
|
||||||
//}
|
Promise.race([onloadPromise, onTimeoutPromise]).then(() => {
|
||||||
|
this.open();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.fire();
|
||||||
|
}, animationTime)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Just like loadCoWebsite but the div can be filled by the user.
|
* Just like loadCoWebsite but the div can be filled by the user.
|
||||||
*/
|
*/
|
||||||
public static insertCoWebsite(callback: (cowebsite: HTMLDivElement) => void): void {
|
public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise<void>): void {
|
||||||
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite");
|
const cowebsiteDiv = this.load();
|
||||||
cowebsiteDiv.innerHTML = '';
|
callback(cowebsiteDiv).then(() => {
|
||||||
|
this.open();
|
||||||
callback(cowebsiteDiv);
|
setTimeout(() => {
|
||||||
//iframe.onload = () => {
|
this.fire();
|
||||||
// onload can be long to trigger. Maybe we should display the website, whatever happens, after 1 second?
|
}, animationTime)
|
||||||
CoWebsiteManager.fire();
|
});
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static closeCoWebsite(): void {
|
public closeCoWebsite(): Promise<void> {
|
||||||
const cowebsiteDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite");
|
return new Promise((resolve, reject) => {
|
||||||
cowebsiteDiv.innerHTML = '';
|
const cowebsiteDiv = this.close();
|
||||||
CoWebsiteManager.fire();
|
this.fire();
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
setTimeout(() => cowebsiteDiv.innerHTML = '', 500)
|
||||||
|
}, animationTime)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getGameSize(): {width: number, height: number} {
|
public getGameSize(): {width: number, height: number} {
|
||||||
const hasChildren = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("cowebsite").children.length > 0;
|
if (this.opened !== iframeStates.opened) {
|
||||||
if (hasChildren === false) {
|
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight
|
height: window.innerHeight
|
||||||
@ -61,13 +104,15 @@ export class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static onStateChange(observer: CoWebsiteStateChangedCallback) {
|
public onStateChange(observer: CoWebsiteStateChangedCallback) {
|
||||||
CoWebsiteManager.observers.push(observer);
|
this.observers.push(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static fire(): void {
|
private fire(): void {
|
||||||
for (const callback of CoWebsiteManager.observers) {
|
for (const callback of this.observers) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const coWebsiteManager = new CoWebsiteManager();
|
@ -1,6 +1,6 @@
|
|||||||
import {CoWebsiteManager} from "./CoWebsiteManager";
|
|
||||||
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
||||||
import {mediaManager} from "./MediaManager";
|
import {mediaManager} from "./MediaManager";
|
||||||
|
import {coWebsiteManager} from "./CoWebsiteManager";
|
||||||
declare const window:any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
declare const window:any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
|
||||||
const interfaceConfig = {
|
const interfaceConfig = {
|
||||||
@ -31,9 +31,9 @@ class JitsiFactory {
|
|||||||
private videoCallback = this.onVideoChange.bind(this);
|
private videoCallback = this.onVideoChange.bind(this);
|
||||||
|
|
||||||
public start(roomName: string, playerName:string, jwt?: string): void {
|
public start(roomName: string, playerName:string, jwt?: string): void {
|
||||||
CoWebsiteManager.insertCoWebsite((cowebsiteDiv => {
|
coWebsiteManager.insertCoWebsite((cowebsiteDiv => {
|
||||||
const domain = JITSI_URL;
|
const domain = JITSI_URL;
|
||||||
const options = {
|
const options: any = { // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
roomName: roomName,
|
roomName: roomName,
|
||||||
jwt: jwt,
|
jwt: jwt,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@ -49,19 +49,23 @@ class JitsiFactory {
|
|||||||
if (!options.jwt) {
|
if (!options.jwt) {
|
||||||
delete options.jwt;
|
delete options.jwt;
|
||||||
}
|
}
|
||||||
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
|
||||||
this.jitsiApi.executeCommand('displayName', playerName);
|
|
||||||
|
|
||||||
this.jitsiApi.addListener('audioMuteStatusChanged', this.audioCallback);
|
return new Promise((resolve) => {
|
||||||
this.jitsiApi.addListener('videoMuteStatusChanged', this.videoCallback);
|
options.onload = () => resolve(); //we want for the iframe to be loaded before triggering animations.
|
||||||
|
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
||||||
|
this.jitsiApi.executeCommand('displayName', playerName);
|
||||||
|
|
||||||
|
this.jitsiApi.addListener('audioMuteStatusChanged', this.audioCallback);
|
||||||
|
this.jitsiApi.addListener('videoMuteStatusChanged', this.videoCallback);
|
||||||
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public stop(): void {
|
public async stop(): Promise<void> {
|
||||||
|
await coWebsiteManager.closeCoWebsite();
|
||||||
this.jitsiApi.removeListener('audioMuteStatusChanged', this.audioCallback);
|
this.jitsiApi.removeListener('audioMuteStatusChanged', this.audioCallback);
|
||||||
this.jitsiApi.removeListener('videoMuteStatusChanged', this.videoCallback);
|
this.jitsiApi.removeListener('videoMuteStatusChanged', this.videoCallback);
|
||||||
this.jitsiApi?.dispose();
|
this.jitsiApi?.dispose();
|
||||||
CoWebsiteManager.closeCoWebsite();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onAudioChange({muted}: {muted: boolean}): void {
|
private onAudioChange({muted}: {muted: boolean}): void {
|
||||||
|
@ -10,12 +10,9 @@ import {FourOFourScene} from "./Phaser/Reconnecting/FourOFourScene";
|
|||||||
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
|
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
|
||||||
import {OutlinePipeline} from "./Phaser/Shaders/OutlinePipeline";
|
import {OutlinePipeline} from "./Phaser/Shaders/OutlinePipeline";
|
||||||
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
|
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
|
||||||
import {CoWebsiteManager} from "./WebRtc/CoWebsiteManager";
|
|
||||||
import {gameManager} from "./Phaser/Game/GameManager";
|
|
||||||
import {ResizableScene} from "./Phaser/Login/ResizableScene";
|
import {ResizableScene} from "./Phaser/Login/ResizableScene";
|
||||||
import {EntryScene} from "./Phaser/Login/EntryScene";
|
import {EntryScene} from "./Phaser/Login/EntryScene";
|
||||||
|
import {coWebsiteManager} from "./WebRtc/CoWebsiteManager";
|
||||||
//CoWebsiteManager.loadCoWebsite('https://thecodingmachine.com');
|
|
||||||
|
|
||||||
// Load Jitsi if the environment variable is set.
|
// Load Jitsi if the environment variable is set.
|
||||||
if (JITSI_URL) {
|
if (JITSI_URL) {
|
||||||
@ -24,7 +21,7 @@ if (JITSI_URL) {
|
|||||||
document.head.appendChild(jitsiScript);
|
document.head.appendChild(jitsiScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {width, height} = CoWebsiteManager.getGameSize();
|
const {width, height} = coWebsiteManager.getGameSize();
|
||||||
|
|
||||||
const config: GameConfig = {
|
const config: GameConfig = {
|
||||||
title: "WorkAdventure",
|
title: "WorkAdventure",
|
||||||
@ -53,8 +50,7 @@ cypressAsserter.gameStarted();
|
|||||||
const game = new Phaser.Game(config);
|
const game = new Phaser.Game(config);
|
||||||
|
|
||||||
window.addEventListener('resize', function (event) {
|
window.addEventListener('resize', function (event) {
|
||||||
const {width, height} = CoWebsiteManager.getGameSize();
|
const {width, height} = coWebsiteManager.getGameSize();
|
||||||
|
|
||||||
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
||||||
|
|
||||||
// Let's trigger the onResize method of any active scene that is a ResizableScene
|
// Let's trigger the onResize method of any active scene that is a ResizableScene
|
||||||
@ -64,8 +60,7 @@ window.addEventListener('resize', function (event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
CoWebsiteManager.onStateChange(() => {
|
coWebsiteManager.onStateChange(() => {
|
||||||
const {width, height} = CoWebsiteManager.getGameSize();
|
const {width, height} = coWebsiteManager.getGameSize();
|
||||||
|
|
||||||
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
||||||
});
|
});
|
||||||
|
9
website/dist/choose-map.html
vendored
9
website/dist/choose-map.html
vendored
@ -36,6 +36,15 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="choose-map">
|
<body class="choose-map">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<a href="/" class="d-block mt-3 pixel-text">
|
||||||
|
<< BACK TO HOMEPAGE
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="container-fluid container-lg section pt-5">
|
<div class="container-fluid container-lg section pt-5">
|
||||||
<h1 class="text-center pixel-title">CHOOSE YOUR MAP !</h1>
|
<h1 class="text-center pixel-title">CHOOSE YOUR MAP !</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
11
website/dist/create-map.html
vendored
11
website/dist/create-map.html
vendored
@ -36,6 +36,15 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="create-map">
|
<body class="create-map">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<a href="/" class="d-block mt-3 pixel-text">
|
||||||
|
<< BACK TO HOMEPAGE
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="container-fluid container-lg section pt-5">
|
<div class="container-fluid container-lg section pt-5">
|
||||||
<h1 class="text-center pixel-title">CREATE YOUR MAP !</h1>
|
<h1 class="text-center pixel-title">CREATE YOUR MAP !</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -44,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
< class="col">
|
<div class="col">
|
||||||
<h2 id="tools-you-will-need" class="pixel-title">Tools you will need</h2>
|
<h2 id="tools-you-will-need" class="pixel-title">Tools you will need</h2>
|
||||||
<p>In order to build your own map for WorkAdventure, you need:</p>
|
<p>In order to build your own map for WorkAdventure, you need:</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
41
website/dist/index.html
vendored
41
website/dist/index.html
vendored
@ -33,12 +33,12 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||||
<meta name="title" content="Workadventure" />
|
<meta name="title" content="Workadventure" />
|
||||||
<meta name="description" content="You are impatient to discover this new world? Click on 'Play online' and meet new people or share this adventure with your colleagues and friends by clicking on 'Private mode'" />
|
<meta name="description" content="You are impatient to discover this new world? Click on 'Work online' and meet new people or share this adventure with your colleagues and friends by clicking on 'Work in private'" />
|
||||||
<!-- Open Graph / Facebook -->
|
<!-- Open Graph / Facebook -->
|
||||||
<meta property="og:url" content="https://workadventu.re/" />
|
<meta property="og:url" content="https://workadventu.re/" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:title" content="Workadventure" />
|
<meta property="og:title" content="Workadventure" />
|
||||||
<meta property="og:description" content="You are impatient to discover this new world? Click on 'Play online' and meet new people or share this adventure with your colleagues and friends by clicking on 'Private mode'" />
|
<meta property="og:description" content="You are impatient to discover this new world? Click on 'Work online' and meet new people or share this adventure with your colleagues and friends by clicking on 'Work in private'" />
|
||||||
<meta property="og:image" content="https://workadventu.re/static/images/meta-tags-image.jpg" />
|
<meta property="og:image" content="https://workadventu.re/static/images/meta-tags-image.jpg" />
|
||||||
<meta property="og:image:type" content="image/jpeg" />
|
<meta property="og:image:type" content="image/jpeg" />
|
||||||
<meta property="og:image:alt" content="workadventure" />
|
<meta property="og:image:alt" content="workadventure" />
|
||||||
@ -46,7 +46,7 @@
|
|||||||
<meta name="twitter:site" content="@coding_machine">
|
<meta name="twitter:site" content="@coding_machine">
|
||||||
<meta name="twitter:url" content="https://workadventu.re/" />
|
<meta name="twitter:url" content="https://workadventu.re/" />
|
||||||
<meta name="twitter:title" content="Workadventure" />
|
<meta name="twitter:title" content="Workadventure" />
|
||||||
<meta name="twitter:description" content="You are impatient to discover this new world? Click on 'Play online' and meet new people or share this adventure with your colleagues and friends by clicking on 'Private mode'" />
|
<meta name="twitter:description" content="You are impatient to discover this new world? Click on 'Work online' and meet new people or share this adventure with your colleagues and friends by clicking on 'Work in private'" />
|
||||||
<meta name="twitter:image" content="https://workadventu.re/static/images/meta-tags-image.jpg" />
|
<meta name="twitter:image" content="https://workadventu.re/static/images/meta-tags-image.jpg" />
|
||||||
<link rel="stylesheet" href="main.css">
|
<link rel="stylesheet" href="main.css">
|
||||||
<script src="bundle.js"></script>
|
<script src="bundle.js"></script>
|
||||||
@ -97,17 +97,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="title title-main text-center">
|
<div class="title title-main text-center">
|
||||||
<h1>Your workplace<br/>but better</h1>
|
<h1>Your workplace<br/>but better</h1>
|
||||||
<h3>You are impatient to discover this new world? Click on "Play online" and meet new people or share this adventure with your colleagues and friends by clicking on "Private mode"</h3>
|
<h3>You are impatient to discover this new world? Click on "Work online" and meet new people or share this adventure with your colleagues and friends by clicking on "Work in private"</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="row buttons-row justify-content-md-center pt-5">
|
<div class="row buttons-row justify-content-md-center pt-5">
|
||||||
<div class="col col-lg-3">
|
<div class="col col-lg-3">
|
||||||
<a class="custom-link start" href="/choose-map.html" title="PRIVATE MODE">
|
<a class="custom-link start" href="/choose-map.html" title="WORK IN PRIVATE">
|
||||||
PRIVATE MODE
|
WORK IN PRIVATE
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-lg-3">
|
<div class="col col-lg-3">
|
||||||
<a class="custom-link play" target="_BLANK" onclick="startGame()" title="PLAY ONLINE">
|
<a class="custom-link play" target="_BLANK" onclick="startGame()" title="WORK ONLINE">
|
||||||
PLAY ONLINE
|
WORK ONLINE
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -165,10 +165,10 @@
|
|||||||
<div class="bubble bubble-4 b-revert" style="height: 254px;">
|
<div class="bubble bubble-4 b-revert" style="height: 254px;">
|
||||||
<div>
|
<div>
|
||||||
<p>You can also create a private room with your friends or your team ! </p>
|
<p>You can also create a private room with your friends or your team ! </p>
|
||||||
<p class="bubble-legend">To try, press button private mode</p>
|
<p class="bubble-legend">To try, press button work in private</p>
|
||||||
<p class="bubble-action"><a href="/choose-map.html">
|
<p class="bubble-action"><a href="/choose-map.html">
|
||||||
<img src="static/images/playicon.png" />
|
<img src="static/images/playicon.png" />
|
||||||
START IN PRIVATE MODE
|
START WORKING IN PRIVATE
|
||||||
</a></p>
|
</a></p>
|
||||||
<p>
|
<p>
|
||||||
Don’t forget to activate your mic and camera, let’s play
|
Don’t forget to activate your mic and camera, let’s play
|
||||||
@ -287,23 +287,23 @@
|
|||||||
<div class="container-fluid container-lg">
|
<div class="container-fluid container-lg">
|
||||||
<div class="row justify-content-md-center">
|
<div class="row justify-content-md-center">
|
||||||
<div class="col-12 col-md-12 text-center">
|
<div class="col-12 col-md-12 text-center">
|
||||||
<h3>How to play</h3>
|
<h3>HOW IT WORKS</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 text-center my-3 my-md-0">
|
<div class="col-12 col-md-4 text-center my-3 my-md-0">
|
||||||
<div class="image-item">
|
<div class="image-item">
|
||||||
<h2>Choose your map</h2>
|
<h2>CHOOSE YOUR WORKSPACE</h2>
|
||||||
<div class="step-image"><img src="static/images/maps/office.png"></div>
|
<div class="step-image"><img src="static/images/maps/office.png"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 text-center my-3 my-md-0">
|
<div class="col-12 col-md-4 text-center my-3 my-md-0">
|
||||||
<div class="image-item">
|
<div class="image-item">
|
||||||
<h2>Select your character</h2>
|
<h2>SELECT YOUR WOKA</h2>
|
||||||
<div class="step-image"><img src="static/images/choose_character.png"></div>
|
<div class="step-image"><img src="static/images/choose_character.png"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 text-center my-3 my-md-0">
|
<div class="col-12 col-md-4 text-center my-3 my-md-0">
|
||||||
<div class="image-item">
|
<div class="image-item">
|
||||||
<h2>Let's go explore and talk !</h2>
|
<h2>LET'S GO TO YOUR OFFICE</h2>
|
||||||
<div class="step-image"><img src="static/images/interact.png"></div>
|
<div class="step-image"><img src="static/images/interact.png"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -313,13 +313,14 @@
|
|||||||
<div class="section bg-white">
|
<div class="section bg-white">
|
||||||
<div class="container-fluid container-lg">
|
<div class="container-fluid container-lg">
|
||||||
<div class="col-12 credits">
|
<div class="col-12 credits">
|
||||||
<h2>Future features</h2>
|
<h2>CURRENT FEATURES</h2>
|
||||||
<h3>We have already thought of new features:</h3>
|
<!-- <h3>We have already thought of new features:</h3>-->
|
||||||
<p>Share files with others</p>
|
<p>Instant interaction with up to 4 people</p>
|
||||||
<p>Lock group conversations</p>
|
|
||||||
<p>Share screen with others</p>
|
<p>Share screen with others</p>
|
||||||
<p>Interact with objects</p>
|
<p>Organize a workshop and meeting with up to 60 people</p>
|
||||||
<h3>And you, what would you want?</h3>
|
<p>Design your own digital space</p>
|
||||||
|
<p>... and infinite possibilities</p>
|
||||||
|
<h3>You need more? Do not hesitate to tell us!</h3>
|
||||||
<div class="row justify-content-md-center pt-5" style="margin-top: 65px;">
|
<div class="row justify-content-md-center pt-5" style="margin-top: 65px;">
|
||||||
<div class="col col-lg-3">
|
<div class="col col-lg-3">
|
||||||
<a class="custom-link contribute" target="_BLANK" href="https://docs.google.com/forms/d/e/1FAIpQLSdxvajEyqsn4X0ai0SoDAcdsa_JQPIfiP2Tp9PDzkfZA54v9Q/viewform" title="FEEDBACK">
|
<a class="custom-link contribute" target="_BLANK" href="https://docs.google.com/forms/d/e/1FAIpQLSdxvajEyqsn4X0ai0SoDAcdsa_JQPIfiP2Tp9PDzkfZA54v9Q/viewform" title="FEEDBACK">
|
||||||
|
@ -148,7 +148,7 @@ header {
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 7px;
|
bottom: 7px;
|
||||||
padding: 1.125rem;
|
padding: 1.125rem 0.5rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
transition: all .1s cubic-bezier(0.000, -0.600, 1.000, 1.650); /* custom */
|
transition: all .1s cubic-bezier(0.000, -0.600, 1.000, 1.650); /* custom */
|
||||||
@ -431,7 +431,7 @@ img{
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
min-height: 6rem;
|
min-height: 6rem;
|
||||||
font-family: 'Karmatic Arcade';
|
font-family: 'Karmatic Arcade';
|
||||||
font-size: 22px;
|
font-size: 24px;
|
||||||
margin-bottom: 1.25rem;
|
margin-bottom: 1.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,6 +503,9 @@ img{
|
|||||||
.pixel-title{
|
.pixel-title{
|
||||||
font-family: "Karmatic Arcade" !important;
|
font-family: "Karmatic Arcade" !important;
|
||||||
}
|
}
|
||||||
|
.pixel-text{
|
||||||
|
font-family: "VCR OSD Mono" !important;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
Loading…
Reference in New Issue
Block a user