diff --git a/front/dist/index.html b/front/dist/index.html
index a680c59a..92a7bf3c 100644
--- a/front/dist/index.html
+++ b/front/dist/index.html
@@ -39,7 +39,53 @@
diff --git a/front/dist/resources/objects/layout_modes.png b/front/dist/resources/objects/layout_modes.png
new file mode 100644
index 00000000..abd9adaf
Binary files /dev/null and b/front/dist/resources/objects/layout_modes.png differ
diff --git a/front/dist/resources/style/style.css b/front/dist/resources/style/style.css
index 5f0e1cab..30e099ef 100644
--- a/front/dist/resources/style/style.css
+++ b/front/dist/resources/style/style.css
@@ -23,34 +23,12 @@ body .message-info.info{
body .message-info.warning{
background: #ffa500d6;
}
-video{
- -webkit-transform: scaleX(-1);
- transform: scaleX(-1);
-}
-.webrtc{
- display: none;
- position: absolute;
- right: 0px;
- height: 100%;
- width: 300px;
-}
-.webrtc.active{
- display: block;
-}
-
-.webrtc, .activeCam{}
-.activeCam .video-container{
- position: absolute;
- height: 25%;
- top: 10px;
- margin: 5px;
- right: -100px;
+.video-container{
+ position: relative;
transition: all 0.2s ease;
- border-color: black;
- border-style: solid;
- border-width: 0.2px;
+ background-color: #00000099;
}
-.activeCam .video-container i{
+.video-container i{
position: absolute;
width: 100px;
height: 65px;
@@ -63,10 +41,10 @@ video{
font-size: 28px;
color: white;
}
-.activeCam .video-container img.active{
+.video-container img.active{
display: block;
}
-.activeCam .video-container img{
+.video-container img{
position: absolute;
display: none;
width: 15px;
@@ -78,36 +56,29 @@ video{
padding: 10px;
z-index: 2;
}
-.activeCam .video-container video{
+.video-container video{
height: 100%;
}
-.webrtc:hover .activeCam .video-container{
- right: 10px;
-}
-.activeCam .video-container#div-myCamVideo{
+.video-container#div-myCamVideo{
border: none;
}
-.activeCam .video-container video#myCamVideo{
- width: 200px;
- height: 113px;
+
+#div-myCamVideo {
+ position: absolute;
+ right: 0;
+ bottom: 0;
}
-/*CSS size for 2 - 3 elements*/
-.activeCam .video-container:nth-child(1){
- /*this is for camera of user*/
- top: 75%;
-}
-.activeCam .video-container:nth-child(2){
- top: 0%;
-}
-.activeCam .video-container:nth-child(3){
- top: 25%;
-}
-.activeCam .video-container:nth-child(4) {
- top: 50%;
+video#myCamVideo{
+ width: 15vw;
+ -webkit-transform: scaleX(-1);
+ transform: scaleX(-1);
+ /*width: 200px;*/
+ /*height: 113px;*/
}
+
/*btn animation*/
.btn-cam-action div{
cursor: pointer;
@@ -118,11 +89,11 @@ video{
background: #666;
box-shadow: 2px 2px 24px #444;
border-radius: 48px;
- transform: translateY(12vw);
+ transform: translateY(12vh);
transition-timing-function: ease-in-out;
bottom: 20px;
}
-.webrtc:hover .btn-cam-action div{
+#activeCam:hover .btn-cam-action div{
transform: translateY(0);
}
.btn-cam-action div:hover{
@@ -237,3 +208,156 @@ video{
.webrtcsetup.active{
display: block;
}
+
+
+/* New layout */
+body {
+ margin: 0;
+ height: 100vh;
+ width: 100vw;
+}
+.main-container {
+ height: 100vh;
+ width: 100vw;
+ display: flex;
+ align-items: stretch;
+}
+
+@media (min-aspect-ratio: 1/1) {
+ .main-container {
+ flex-direction: row;
+ }
+
+ .game-overlay {
+ flex-direction: row;
+ }
+
+ .sidebar {
+ flex-direction: column;
+ }
+
+ .sidebar > div {
+ max-height: 21%;
+ }
+}
+@media (max-aspect-ratio: 1/1) {
+ .main-container {
+ flex-direction: column;
+ }
+
+ .game-overlay {
+ flex-direction: column;
+ }
+
+ .sidebar {
+ flex-direction: row;
+ align-items: flex-end;
+ }
+
+ .sidebar > div {
+ max-width: 21%;
+ }
+}
+
+.game {
+ flex-basis: 100%;
+ position: relative; /* Position relative is needed for the game-overlay. */
+}
+
+/* A potentially shared website could appear in an iframe in the cowebsite space. */
+.cowebsite {
+ flex-basis: 100%;
+ transition: flex-basis 0.5s;
+}
+
+/*.cowebsite:hover {
+ flex-basis: 100%;
+}*/
+
+.cowebsite iframe {
+ width: 100%;
+ height: 100%;
+}
+
+
+.game-overlay {
+ display: none;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ /* TODO: DO WE NEED FLEX HERE???? WE WANT A SIDEBAR OF EXACTLY 25% (note: flex useful for direction!!!) */
+}
+
+.game-overlay.active {
+ display: flex;
+}
+
+.game-overlay video {
+ width: 100%
+}
+
+.main-section {
+ flex: 0 0 75%;
+ display: flex;
+ justify-content: start;
+ /*align-items: flex-start;*/
+ flex-wrap: wrap;
+}
+
+.main-section > div {
+ margin: 5%;
+ flex-basis: 90%;
+ /*flex-shrink: 2;*/
+}
+
+.sidebar {
+ flex: 0 0 25%;
+ display: flex;
+}
+
+.sidebar > div {
+ margin: 2%;
+}
+
+/* Let's make sure videos are vertically centered if they need to be cropped */
+.media-container {
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.chat-mode {
+ display: flex;
+ width: 100%;
+
+ flex-wrap: wrap;
+ align-items: flex-start;
+
+ padding: 1%;
+}
+
+.chat-mode div {
+ margin: 1%;
+ max-height: 96%;
+}
+
+.chat-mode.one-col > div {
+ flex-basis: 98%;
+}
+
+.chat-mode.two-col > div {
+ flex-basis: 48%;
+}
+
+.chat-mode.three-col > div {
+ flex-basis: 31.333333%;
+}
+
+.chat-mode.four-col > div {
+ flex-basis: 23%;
+}
+
+.chat-mode > div:last-child {
+ flex-grow: 5;
+}
diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts
index 487f3fb1..c4517545 100644
--- a/front/src/Phaser/Game/GameScene.ts
+++ b/front/src/Phaser/Game/GameScene.ts
@@ -1,34 +1,33 @@
import {GameManager, gameManager, HasMovedEvent} from "./GameManager";
import {
Connection,
- GroupCreatedUpdatedMessageInterface, MessageUserJoined,
+ GroupCreatedUpdatedMessageInterface,
+ MessageUserJoined,
MessageUserMovedInterface,
- MessageUserPositionInterface, PointInterface, PositionInterface
+ MessageUserPositionInterface,
+ PointInterface,
+ PositionInterface
} from "../../Connection";
import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player";
-import { DEBUG_MODE, ZOOM_LEVEL, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
-import {
- ITiledMap,
- ITiledMapLayer,
- ITiledMapLayerProperty,
- ITiledTileSet
-} from "../Map/ITiledMap";
+import {DEBUG_MODE, POSITION_DELAY, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
+import {ITiledMap, ITiledMapLayer, ITiledMapLayerProperty, ITiledTileSet} from "../Map/ITiledMap";
import {PLAYER_RESOURCES, PlayerResourceDescriptionInterface} from "../Entity/Character";
-import Texture = Phaser.Textures.Texture;
-import Sprite = Phaser.GameObjects.Sprite;
-import CanvasTexture = Phaser.Textures.CanvasTexture;
import {AddPlayerInterface} from "./AddPlayerInterface";
import {PlayerAnimationNames} from "../Player/Animation";
import {PlayerMovement} from "./PlayerMovement";
import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator";
import {RemotePlayer} from "../Entity/RemotePlayer";
-import GameObject = Phaser.GameObjects.GameObject;
-import { Queue } from 'queue-typescript';
-import {SimplePeer} from "../../WebRtc/SimplePeer";
+import {Queue} from 'queue-typescript';
+import {SimplePeer, UserSimplePeer} from "../../WebRtc/SimplePeer";
import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene";
-import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
-import {LAYERS, loadAllLayers} from "../Entity/body_character";
+import {loadAllLayers} from "../Entity/body_character";
+import {layoutManager, LayoutMode} 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;
export enum Textures {
@@ -107,6 +106,9 @@ export class GameScene extends Phaser.Scene {
private PositionNextScene: Array
> = new Array>();
private startLayerName: string|undefined;
+ private presentationModeSprite!: Sprite;
+ private chatModeSprite!: Sprite;
+ private repositionCallback!: (this: Window, ev: UIEvent) => void;
static createFromUrl(mapUrlFile: string, instance: string, key: string|null = null): GameScene {
const mapKey = GameScene.getMapKeyByUrl(mapUrlFile);
@@ -159,6 +161,12 @@ export class GameScene extends Phaser.Scene {
);
});
+ this.load.spritesheet(
+ 'layout_modes',
+ 'resources/objects/layout_modes.png',
+ {frameWidth: 32, frameHeight: 32}
+ );
+
loadAllLayers(this.load);
this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
@@ -214,10 +222,24 @@ export class GameScene extends Phaser.Scene {
this.scene.stop(this.scene.key);
this.scene.remove(this.scene.key);
+ window.removeEventListener('resize', this.repositionCallback);
})
// When connection is performed, let's connect SimplePeer
this.simplePeer = new SimplePeer(this.connection);
+ const self = this;
+ this.simplePeer.registerPeerConnectionListener({
+ onConnect(user: UserSimplePeer) {
+ self.presentationModeSprite.setVisible(true);
+ self.chatModeSprite.setVisible(true);
+ },
+ onDisconnect(userId: string) {
+ if (self.simplePeer.getNbConnections() === 0) {
+ self.presentationModeSprite.setVisible(false);
+ self.chatModeSprite.setVisible(false);
+ }
+ }
+ })
this.scene.wake();
this.scene.sleep(ReconnectingSceneName);
@@ -364,6 +386,41 @@ export class GameScene extends Phaser.Scene {
}
}, 500);
}
+
+ this.presentationModeSprite = this.add.sprite(2, this.game.renderer.height - 2, 'layout_modes', 0);
+ this.presentationModeSprite.setScrollFactor(0, 0);
+ this.presentationModeSprite.setOrigin(0, 1);
+ this.presentationModeSprite.setInteractive();
+ this.presentationModeSprite.setVisible(false);
+ this.presentationModeSprite.on('pointerup', this.switchLayoutMode.bind(this));
+ this.chatModeSprite = this.add.sprite(36, this.game.renderer.height - 2, 'layout_modes', 3);
+ this.chatModeSprite.setScrollFactor(0, 0);
+ this.chatModeSprite.setOrigin(0, 1);
+ this.chatModeSprite.setInteractive();
+ this.chatModeSprite.setVisible(false);
+ this.chatModeSprite.on('pointerup', this.switchLayoutMode.bind(this));
+
+ // FIXME: change this to use the UserInputManager class for input
+ this.input.keyboard.on('keyup-' + 'M', () => {
+ this.switchLayoutMode();
+ });
+
+ this.repositionCallback = this.reposition.bind(this);
+ window.addEventListener('resize', this.repositionCallback);
+ this.reposition();
+ }
+
+ private switchLayoutMode(): void {
+ const mode = layoutManager.getLayoutMode();
+ if (mode === LayoutMode.Presentation) {
+ layoutManager.switchLayoutMode(LayoutMode.VideoChat);
+ this.presentationModeSprite.setFrame(1);
+ this.chatModeSprite.setFrame(2);
+ } else {
+ layoutManager.switchLayoutMode(LayoutMode.Presentation);
+ this.presentationModeSprite.setFrame(0);
+ this.chatModeSprite.setFrame(3);
+ }
}
private getExitSceneUrl(layer: ITiledMapLayer): string|undefined {
@@ -625,6 +682,7 @@ export class GameScene extends Phaser.Scene {
this.simplePeer.unregister();
this.scene.stop();
this.scene.remove(this.scene.key);
+ window.removeEventListener('resize', this.repositionCallback);
this.scene.start(nextSceneKey.key, {
startLayerName: nextSceneKey.hash
});
@@ -812,4 +870,9 @@ export class GameScene extends Phaser.Scene {
const endPos = mapUrlStart.indexOf(".json");
return mapUrlStart.substring(startPos, endPos);
}
+
+ private reposition(): void {
+ this.presentationModeSprite.setY(this.game.renderer.height - 2);
+ this.chatModeSprite.setY(this.game.renderer.height - 2);
+ }
}
diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts
new file mode 100644
index 00000000..0150760c
--- /dev/null
+++ b/front/src/WebRtc/CoWebsiteManager.ts
@@ -0,0 +1,56 @@
+import {HtmlUtils} from "./HtmlUtils";
+
+export type CoWebsiteStateChangedCallback = () => void;
+
+export class CoWebsiteManager {
+
+ private static observers = new Array();
+
+ public static loadCoWebsite(url: string): void {
+ const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite");
+ cowebsiteDiv.innerHTML = '';
+
+ const iframe = document.createElement('iframe');
+ iframe.id = 'cowebsite-iframe';
+ iframe.src = url;
+ cowebsiteDiv.appendChild(iframe);
+ CoWebsiteManager.fire();
+ }
+
+ public static closeCoWebsite(): void {
+ const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite");
+ cowebsiteDiv.innerHTML = '';
+ CoWebsiteManager.fire();
+ }
+
+ public static getGameSize(): {width: number, height: number} {
+ const iframe = document.getElementById('cowebsite-iframe');
+ if (iframe === null) {
+ return {
+ width: window.innerWidth,
+ height: window.innerHeight
+ }
+ }
+ if (window.innerWidth >= window.innerHeight) {
+ return {
+ width: window.innerWidth / 2,
+ height: window.innerHeight
+ }
+ } else {
+ return {
+ width: window.innerWidth,
+ height: window.innerHeight / 2
+ }
+ }
+ }
+
+ public static onStateChange(observer: CoWebsiteStateChangedCallback) {
+ CoWebsiteManager.observers.push(observer);
+ }
+
+ private static fire(): void {
+ for (const callback of CoWebsiteManager.observers) {
+ callback();
+ }
+ }
+}
diff --git a/front/src/WebRtc/HtmlUtils.ts b/front/src/WebRtc/HtmlUtils.ts
new file mode 100644
index 00000000..c2e6ff6d
--- /dev/null
+++ b/front/src/WebRtc/HtmlUtils.ts
@@ -0,0 +1,10 @@
+export class HtmlUtils {
+ public static getElementByIdOrFail(id: string): T {
+ const elem = document.getElementById(id);
+ if (elem === null) {
+ throw new Error("Cannot find HTML element with id '"+id+"'");
+ }
+ // FIXME: does not check the type of the returned type
+ return elem as T;
+ }
+}
diff --git a/front/src/WebRtc/LayoutManager.ts b/front/src/WebRtc/LayoutManager.ts
new file mode 100644
index 00000000..6695fe7f
--- /dev/null
+++ b/front/src/WebRtc/LayoutManager.ts
@@ -0,0 +1,135 @@
+import {HtmlUtils} from "./HtmlUtils";
+
+export enum LayoutMode {
+ // All videos are displayed on the right side of the screen. If there is a screen sharing, it is displayed in the middle.
+ Presentation = "Presentation",
+ // Videos take the whole page.
+ VideoChat = "VideoChat",
+}
+
+export enum DivImportance {
+ // For screen sharing
+ Important = "Important",
+ // For normal video
+ Normal = "Normal",
+}
+
+/**
+ * This class is in charge of the video-conference layout.
+ * It receives positioning requests for videos and does its best to place them on the screen depending on the active layout mode.
+ */
+class LayoutManager {
+ private mode: LayoutMode = LayoutMode.Presentation;
+
+ private importantDivs: Map = new Map();
+ private normalDivs: Map = new Map();
+
+ public add(importance: DivImportance, userId: string, html: string): void {
+ const div = document.createElement('div');
+ div.innerHTML = html;
+ div.id = "user-"+userId;
+ div.className = "media-container"
+
+ if (importance === DivImportance.Important) {
+ this.importantDivs.set(userId, div);
+
+ // If this is the first video with high importance, let's switch mode automatically.
+ if (this.importantDivs.size === 1 && this.mode === LayoutMode.VideoChat) {
+ this.switchLayoutMode(LayoutMode.Presentation);
+ }
+ } else if (importance === DivImportance.Normal) {
+ this.normalDivs.set(userId, div);
+ } else {
+ throw new Error('Unexpected importance');
+ }
+
+ this.positionDiv(div, importance);
+ this.adjustVideoChatClass();
+ }
+
+ private positionDiv(elem: HTMLDivElement, importance: DivImportance): void {
+ if (this.mode === LayoutMode.VideoChat) {
+ const chatModeDiv = HtmlUtils.getElementByIdOrFail('chat-mode');
+ chatModeDiv.appendChild(elem);
+ } else {
+ if (importance === DivImportance.Important) {
+ const mainSectionDiv = HtmlUtils.getElementByIdOrFail('main-section');
+ mainSectionDiv.appendChild(elem);
+ } else if (importance === DivImportance.Normal) {
+ const sideBarDiv = HtmlUtils.getElementByIdOrFail('sidebar');
+ sideBarDiv.appendChild(elem);
+ }
+ }
+ }
+
+ /**
+ * Removes the DIV matching userId.
+ */
+ public remove(userId: string): void {
+ console.log('Removing video for userID '+userId+'.');
+ let div = this.importantDivs.get(userId);
+ if (div !== undefined) {
+ div.remove();
+ this.importantDivs.delete(userId);
+ this.adjustVideoChatClass();
+ return;
+ }
+
+ div = this.normalDivs.get(userId);
+ if (div !== undefined) {
+ div.remove();
+ this.normalDivs.delete(userId);
+ this.adjustVideoChatClass();
+ return;
+ }
+
+ console.log('Cannot remove userID '+userId+'. Already removed?');
+ //throw new Error('Could not find user ID "'+userId+'"');
+ }
+
+ private adjustVideoChatClass(): void {
+ const chatModeDiv = HtmlUtils.getElementByIdOrFail('chat-mode');
+ chatModeDiv.classList.remove('one-col', 'two-col', 'three-col', 'four-col');
+
+ const nbUsers = this.importantDivs.size + this.normalDivs.size;
+
+ if (nbUsers <= 1) {
+ chatModeDiv.classList.add('one-col');
+ } else if (nbUsers <= 4) {
+ chatModeDiv.classList.add('two-col');
+ } else if (nbUsers <= 9) {
+ chatModeDiv.classList.add('three-col');
+ } else {
+ chatModeDiv.classList.add('four-col');
+ }
+ }
+
+ public switchLayoutMode(layoutMode: LayoutMode) {
+ this.mode = layoutMode;
+
+ if (layoutMode === LayoutMode.Presentation) {
+ HtmlUtils.getElementByIdOrFail('sidebar').style.display = 'flex';
+ HtmlUtils.getElementByIdOrFail('main-section').style.display = 'flex';
+ HtmlUtils.getElementByIdOrFail('chat-mode').style.display = 'none';
+ } else {
+ HtmlUtils.getElementByIdOrFail('sidebar').style.display = 'none';
+ HtmlUtils.getElementByIdOrFail('main-section').style.display = 'none';
+ HtmlUtils.getElementByIdOrFail('chat-mode').style.display = 'flex';
+ }
+
+ for (const div of this.importantDivs.values()) {
+ this.positionDiv(div, DivImportance.Important);
+ }
+ for (const div of this.normalDivs.values()) {
+ this.positionDiv(div, DivImportance.Normal);
+ }
+ }
+
+ public getLayoutMode(): LayoutMode {
+ return this.mode;
+ }
+}
+
+const layoutManager = new LayoutManager();
+
+export { layoutManager };
diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts
index e69850a2..39a61738 100644
--- a/front/src/WebRtc/MediaManager.ts
+++ b/front/src/WebRtc/MediaManager.ts
@@ -1,3 +1,5 @@
+import {DivImportance, layoutManager} from "./LayoutManager";
+
const videoConstraint: boolean|MediaTrackConstraints = {
width: { ideal: 1280 },
height: { ideal: 720 },
@@ -73,8 +75,8 @@ export class MediaManager {
}
activeVisio(){
- const webRtc = this.getElementByIdOrFail('webRtc');
- webRtc.classList.add('active');
+ const gameOverlay = this.getElementByIdOrFail('game-overlay');
+ gameOverlay.classList.add('active');
}
enabledCamera() {
@@ -184,18 +186,22 @@ export class MediaManager {
*/
addActiveVideo(userId : string, userName: string = ""){
this.webrtcInAudio.play();
- const elementRemoteVideo = this.getElementByIdOrFail("activeCam");
+
userName = userName.toUpperCase();
const color = this.getColorByString(userName);
- elementRemoteVideo.insertAdjacentHTML('beforeend', `
-
+
+ const html = `
+
-
${userName}
+
${userName}
- `);
+ `;
+
+ layoutManager.add(DivImportance.Normal, userId, html);
+
this.remoteVideo.set(userId, this.getElementByIdOrFail
(userId));
}
@@ -232,11 +238,10 @@ export class MediaManager {
if (element) {
element.style.opacity = "0";
}
- element = document.getElementById(`div-${userId}`);
- if (!element) {
- return;
+ element = document.getElementById(`name-${userId}`);
+ if (element) {
+ element.style.display = "block";
}
- element.style.borderStyle = "solid";
}
/**
@@ -248,11 +253,10 @@ export class MediaManager {
if(element){
element.style.opacity = "1";
}
- element = document.getElementById(`div-${userId}`);
- if(!element){
- return;
+ element = document.getElementById(`name-${userId}`);
+ if(element){
+ element.style.display = "none";
}
- element.style.borderStyle = "none";
}
/**
@@ -274,11 +278,7 @@ export class MediaManager {
* @param userId
*/
removeActiveVideo(userId : string){
- const element = document.getElementById(`div-${userId}`);
- if(!element){
- return;
- }
- element.remove();
+ layoutManager.remove(userId);
this.remoteVideo.delete(userId);
}
diff --git a/front/src/WebRtc/SimplePeer.ts b/front/src/WebRtc/SimplePeer.ts
index 553c9307..fdc2d0c2 100644
--- a/front/src/WebRtc/SimplePeer.ts
+++ b/front/src/WebRtc/SimplePeer.ts
@@ -14,6 +14,12 @@ export interface UserSimplePeer{
initiator?: boolean;
}
+export interface PeerConnectionListener {
+ onConnect(user: UserSimplePeer): void;
+
+ onDisconnect(userId: string): void;
+}
+
/**
* This class manages connections to all the peers in the same group as me.
*/
@@ -24,6 +30,7 @@ export class SimplePeer {
private PeerConnectionArray: Map = new Map();
private readonly updateLocalStreamCallback: (media: MediaStream) => void;
+ private readonly peerConnectionListeners: Array = new Array();
constructor(Connection: Connection, WebRtcRoomId: string = "test-webrtc") {
this.Connection = Connection;
@@ -34,6 +41,14 @@ export class SimplePeer {
this.initialise();
}
+ public registerPeerConnectionListener(peerConnectionListener: PeerConnectionListener) {
+ this.peerConnectionListeners.push(peerConnectionListener);
+ }
+
+ public getNbConnections(): number {
+ return this.PeerConnectionArray.size;
+ }
+
/**
* permit to listen when user could start visio
*/
@@ -182,6 +197,10 @@ export class SimplePeer {
});
this.addMedia(user.userId);
+
+ for (const peerConnectionListener of this.peerConnectionListeners) {
+ peerConnectionListener.onConnect(user);
+ }
}
/**
@@ -203,6 +222,9 @@ export class SimplePeer {
peer.destroy();
this.PeerConnectionArray.delete(userId)
//console.log('Nb users in peerConnectionArray '+this.PeerConnectionArray.size);
+ for (const peerConnectionListener of this.peerConnectionListeners) {
+ peerConnectionListener.onDisconnect(userId);
+ }
} catch (err) {
console.error("closeConnection", err)
}
diff --git a/front/src/index.ts b/front/src/index.ts
index 7634351f..75ad0fe6 100644
--- a/front/src/index.ts
+++ b/front/src/index.ts
@@ -4,16 +4,21 @@ import {DEBUG_MODE, RESOLUTION} from "./Enum/EnvironmentVariable";
import {cypressAsserter} from "./Cypress/CypressAsserter";
import {LoginScene} from "./Phaser/Login/LoginScene";
import {ReconnectingScene} from "./Phaser/Reconnecting/ReconnectingScene";
-import {gameManager} from "./Phaser/Game/GameManager";
import {SelectCharacterScene} from "./Phaser/Login/SelectCharacterScene";
import {EnableCameraScene} from "./Phaser/Login/EnableCameraScene";
import {FourOFourScene} from "./Phaser/Reconnecting/FourOFourScene";
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
+import {HtmlUtils} from "./WebRtc/HtmlUtils";
+import {CoWebsiteManager} from "./WebRtc/CoWebsiteManager";
+
+//CoWebsiteManager.loadCoWebsite('https://thecodingmachine.com');
+
+const {width, height} = CoWebsiteManager.getGameSize();
const config: GameConfig = {
- title: "Office game",
- width: window.innerWidth / RESOLUTION,
- height: window.innerHeight / RESOLUTION,
+ title: "WorkAdventure",
+ width: width / RESOLUTION,
+ height: height / RESOLUTION,
parent: "game",
scene: [LoginScene, SelectCharacterScene, EnableCameraScene, ReconnectingScene, FourOFourScene, CustomizeScene],
zoom: RESOLUTION,
@@ -30,5 +35,12 @@ cypressAsserter.gameStarted();
const game = new Phaser.Game(config);
window.addEventListener('resize', function (event) {
- game.scale.resize(window.innerWidth / RESOLUTION, window.innerHeight / RESOLUTION);
+ const {width, height} = CoWebsiteManager.getGameSize();
+
+ game.scale.resize(width / RESOLUTION, height / RESOLUTION);
+});
+CoWebsiteManager.onStateChange(() => {
+ const {width, height} = CoWebsiteManager.getGameSize();
+
+ game.scale.resize(width / RESOLUTION, height / RESOLUTION);
});