diff --git a/CHANGELOG.md b/CHANGELOG.md
index dec14540..d9afd71e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,11 @@
- The emote menu can be opened by clicking on your character.
- Clicking on one of its element will close the menu and play an emote above your character.
- This emote can be seen by other players.
+- Player names were improved. (@Kharhamel)
+ - We now create a GameObject.Text instead of GameObject.BitmapText
+ - now use the 'Press Start 2P' font family and added an outline
+ - As a result, we can now allow non-standard letters like french accents or chinese characters!
+
- Mobile support has been improved
- WorkAdventure automatically sets the zoom level based on the viewport size to ensure a sensible size of the map is visible, whatever the viewport used
- Mouse wheel support to zoom in / out
diff --git a/front/dist/index.tmpl.html b/front/dist/index.tmpl.html
index 7ef44116..9c251bf3 100644
--- a/front/dist/index.tmpl.html
+++ b/front/dist/index.tmpl.html
@@ -29,7 +29,6 @@
-
diff --git a/front/dist/resources/fonts/fonts.css b/front/dist/resources/fonts/fonts.css
new file mode 100644
index 00000000..a3d3cf71
--- /dev/null
+++ b/front/dist/resources/fonts/fonts.css
@@ -0,0 +1,5 @@
+/*This file is a workaround to allow phaser to load directly this font */
+@font-face {
+ font-family: "Press Start 2P";
+ src: url("/fonts/press-start-2p-latin-400-normal.woff2") format('woff2');
+}
\ No newline at end of file
diff --git a/front/package.json b/front/package.json
index e64c0816..6cf0ee97 100644
--- a/front/package.json
+++ b/front/package.json
@@ -34,6 +34,7 @@
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
+ "@fontsource/press-start-2p": "^4.3.0",
"@types/simple-peer": "^9.6.0",
"@types/socket.io-client": "^1.4.32",
"axios": "^0.21.1",
diff --git a/front/src/Components/App.svelte b/front/src/Components/App.svelte
index 69fa2f62..9b072e8d 100644
--- a/front/src/Components/App.svelte
+++ b/front/src/Components/App.svelte
@@ -1,11 +1,18 @@
+ {#if $gameOverlayVisibilityStore}
+
+
+ {/if}
diff --git a/front/src/Components/CameraControls.svelte b/front/src/Components/CameraControls.svelte
new file mode 100644
index 00000000..bd35d230
--- /dev/null
+++ b/front/src/Components/CameraControls.svelte
@@ -0,0 +1,59 @@
+
+
+
+
+ {#if $requestedScreenSharingState}
+
+ {:else}
+
+ {/if}
+
+
+ {#if $requestedCameraState}
+
+ {:else}
+
+ {/if}
+
+
+ {#if $requestedMicrophoneState}
+
+ {:else}
+
+ {/if}
+
+
diff --git a/front/src/Components/MyCamera.svelte b/front/src/Components/MyCamera.svelte
new file mode 100644
index 00000000..6e1e50ef
--- /dev/null
+++ b/front/src/Components/MyCamera.svelte
@@ -0,0 +1,46 @@
+
+
+
+
diff --git a/front/src/Components/SoundMeterWidget.svelte b/front/src/Components/SoundMeterWidget.svelte
new file mode 100644
index 00000000..cff6be86
--- /dev/null
+++ b/front/src/Components/SoundMeterWidget.svelte
@@ -0,0 +1,36 @@
+
+
+
+
0}>
+ 1}>
+ 2}>
+ 3}>
+ 4}>
+ 5}>
+
diff --git a/front/src/Components/images/cinema-close.svg b/front/src/Components/images/cinema-close.svg
new file mode 100644
index 00000000..aa1d9b17
--- /dev/null
+++ b/front/src/Components/images/cinema-close.svg
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/front/dist/resources/logos/cinema.svg b/front/src/Components/images/cinema.svg
similarity index 100%
rename from front/dist/resources/logos/cinema.svg
rename to front/src/Components/images/cinema.svg
diff --git a/front/src/Components/images/microphone-close.svg b/front/src/Components/images/microphone-close.svg
new file mode 100644
index 00000000..16731829
--- /dev/null
+++ b/front/src/Components/images/microphone-close.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/front/dist/resources/logos/microphone.svg b/front/src/Components/images/microphone.svg
similarity index 100%
rename from front/dist/resources/logos/microphone.svg
rename to front/src/Components/images/microphone.svg
diff --git a/front/dist/resources/logos/monitor-close.svg b/front/src/Components/images/monitor-close.svg
similarity index 100%
rename from front/dist/resources/logos/monitor-close.svg
rename to front/src/Components/images/monitor-close.svg
diff --git a/front/dist/resources/logos/monitor.svg b/front/src/Components/images/monitor.svg
similarity index 100%
rename from front/dist/resources/logos/monitor.svg
rename to front/src/Components/images/monitor.svg
diff --git a/front/src/Connexion/LocalUser.ts b/front/src/Connexion/LocalUser.ts
index 0793a938..43b184cf 100644
--- a/front/src/Connexion/LocalUser.ts
+++ b/front/src/Connexion/LocalUser.ts
@@ -9,9 +9,8 @@ export interface CharacterTexture {
export const maxUserNameLength: number = MAX_USERNAME_LENGTH;
-export function isUserNameValid(value: string): boolean {
- const regexp = new RegExp('^[A-Za-z0-9]{1,'+maxUserNameLength+'}$');
- return regexp.test(value);
+export function isUserNameValid(value: unknown): boolean {
+ return typeof value === "string" && value.length > 0 && value.length < maxUserNameLength && value.indexOf(' ') === -1;
}
export function areCharacterLayersValid(value: string[] | null): boolean {
diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts
index b1a85943..9c3273ec 100644
--- a/front/src/Phaser/Entity/Character.ts
+++ b/front/src/Phaser/Entity/Character.ts
@@ -1,6 +1,6 @@
import {PlayerAnimationDirections, PlayerAnimationTypes} from "../Player/Animation";
import {SpeechBubble} from "./SpeechBubble";
-import BitmapText = Phaser.GameObjects.BitmapText;
+import Text = Phaser.GameObjects.Text;
import Container = Phaser.GameObjects.Container;
import Sprite = Phaser.GameObjects.Sprite;
import {TextureError} from "../../Exception/TextureError";
@@ -23,7 +23,7 @@ const interactiveRadius = 35;
export abstract class Character extends Container {
private bubble: SpeechBubble|null = null;
- private readonly playerName: BitmapText;
+ private readonly playerName: Text;
public PlayerValue: string;
public sprites: Map
;
private lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
@@ -55,9 +55,9 @@ export abstract class Character extends Container {
this.addTextures(textures, frame);
this.invisible = false
})
-
- this.playerName = new BitmapText(scene, 0, playerNameY, 'main_font', name, 7);
- this.playerName.setOrigin(0.5).setCenterAlign().setDepth(DEPTH_INGAME_TEXT_INDEX);
+
+ this.playerName = new Text(scene, 0, playerNameY, name, {fontFamily: '"Press Start 2P"', fontSize: '8px', strokeThickness: 2, stroke: "gray"});
+ this.playerName.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX);
this.add(this.playerName);
if (this.isClickable()) {
diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts
index 2d34060f..300dc71d 100644
--- a/front/src/Phaser/Game/GameScene.ts
+++ b/front/src/Phaser/Game/GameScene.ts
@@ -279,6 +279,14 @@ export class GameScene extends DirtyScene implements CenterListener {
this.load.spritesheet('layout_modes', 'resources/objects/layout_modes.png', {frameWidth: 32, frameHeight: 32});
this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
+ //eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (this.load as any).rexWebFont({
+ custom: {
+ families: ['Press Start 2P'],
+ urls: ['/resources/fonts/fonts.css'],
+ testString: 'abcdefg'
+ },
+ });
//this function must stay at the end of preload function
addLoader(this);
diff --git a/front/src/Phaser/Login/LoginScene.ts b/front/src/Phaser/Login/LoginScene.ts
index 661ddeb4..4b36e3d9 100644
--- a/front/src/Phaser/Login/LoginScene.ts
+++ b/front/src/Phaser/Login/LoginScene.ts
@@ -41,7 +41,7 @@ export class LoginScene extends ResizableScene {
}
pErrorElement.innerHTML = '';
if(inputElement.value && !isUserNameValid(inputElement.value)){
- pErrorElement.innerHTML = 'Invalid user name: only letters and numbers are allowed. No spaces.';
+ pErrorElement.innerHTML = 'Invalid user name: No spaces are allowed.';
}
if (event.key === 'Enter') {
event.preventDefault();
diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts
index fad33de3..5ab603d2 100644
--- a/front/src/WebRtc/MediaManager.ts
+++ b/front/src/WebRtc/MediaManager.ts
@@ -8,33 +8,11 @@ import {SoundMeter} from "../Phaser/Components/SoundMeter";
import {DISABLE_NOTIFICATIONS} from "../Enum/EnvironmentVariable";
import {
gameOverlayVisibilityStore, localStreamStore,
- mediaStreamConstraintsStore,
- requestedCameraState,
- requestedMicrophoneState
} from "../Stores/MediaStore";
import {
- requestedScreenSharingState,
- screenSharingAvailableStore,
screenSharingLocalStreamStore
} from "../Stores/ScreenSharingStore";
-declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any
-
-const videoConstraint: boolean|MediaTrackConstraints = {
- width: { min: 640, ideal: 1280, max: 1920 },
- height: { min: 400, ideal: 720 },
- frameRate: { ideal: localUserStore.getVideoQualityValue() },
- facingMode: "user",
- resizeMode: 'crop-and-scale',
- aspectRatio: 1.777777778
-};
-const audioConstraint: boolean|MediaTrackConstraints = {
- //TODO: make these values configurable in the game settings menu and store them in localstorage
- autoGainControl: false,
- echoCancellation: true,
- noiseSuppression: true
-};
-
export type UpdatedLocalStreamCallback = (media: MediaStream|null) => void;
export type StartScreenSharingCallback = (media: MediaStream) => void;
export type StopScreenSharingCallback = (media: MediaStream) => void;
@@ -43,30 +21,16 @@ export type ShowReportCallBack = (userId: string, userName: string|undefined) =>
export type HelpCameraSettingsCallBack = () => void;
export class MediaManager {
- localStream: MediaStream|null = null;
- localScreenCapture: MediaStream|null = null;
private remoteVideo: Map = new Map();
- myCamVideo: HTMLVideoElement;
- cinemaClose: HTMLImageElement;
- cinema: HTMLImageElement;
- monitorClose: HTMLImageElement;
- monitor: HTMLImageElement;
- microphoneClose: HTMLImageElement;
- microphone: HTMLImageElement;
webrtcInAudio: HTMLAudioElement;
//FIX ME SOUNDMETER: check stalability of sound meter calculation
//mySoundMeterElement: HTMLDivElement;
private webrtcOutAudio: HTMLAudioElement;
- updatedLocalStreamCallBacks : Set = new Set();
startScreenSharingCallBacks : Set = new Set();
stopScreenSharingCallBacks : Set = new Set();
showReportModalCallBacks : Set = new Set();
helpCameraSettingsCallBacks : Set = new Set();
- private microphoneBtn: HTMLDivElement;
- private cinemaBtn: HTMLDivElement;
- private monitorBtn: HTMLDivElement;
-
private focused : boolean = true;
private triggerCloseJistiFrame : Map = new Map();
@@ -80,54 +44,11 @@ export class MediaManager {
constructor() {
- this.myCamVideo = HtmlUtils.getElementByIdOrFail('myCamVideo');
this.webrtcInAudio = HtmlUtils.getElementByIdOrFail('audio-webrtc-in');
this.webrtcOutAudio = HtmlUtils.getElementByIdOrFail('audio-webrtc-out');
this.webrtcInAudio.volume = 0.2;
this.webrtcOutAudio.volume = 0.2;
- this.microphoneBtn = HtmlUtils.getElementByIdOrFail('btn-micro');
- this.microphoneClose = HtmlUtils.getElementByIdOrFail('microphone-close');
- this.microphoneClose.style.display = "none";
- this.microphoneClose.addEventListener('click', (e: MouseEvent) => {
- e.preventDefault();
- requestedMicrophoneState.enableMicrophone();
- });
- this.microphone = HtmlUtils.getElementByIdOrFail('microphone');
- this.microphone.addEventListener('click', (e: MouseEvent) => {
- e.preventDefault();
- requestedMicrophoneState.disableMicrophone();
- });
-
- this.cinemaBtn = HtmlUtils.getElementByIdOrFail('btn-video');
- this.cinemaClose = HtmlUtils.getElementByIdOrFail('cinema-close');
- this.cinemaClose.style.display = "none";
- this.cinemaClose.addEventListener('click', (e: MouseEvent) => {
- e.preventDefault();
- requestedCameraState.enableWebcam();
- });
- this.cinema = HtmlUtils.getElementByIdOrFail('cinema');
- this.cinema.addEventListener('click', (e: MouseEvent) => {
- e.preventDefault();
- requestedCameraState.disableWebcam();
- });
-
- this.monitorBtn = HtmlUtils.getElementByIdOrFail('btn-monitor');
- this.monitorClose = HtmlUtils.getElementByIdOrFail('monitor-close');
- this.monitorClose.style.display = "block";
- this.monitorClose.addEventListener('click', (e: MouseEvent) => {
- e.preventDefault();
- //this.enableScreenSharing();
- requestedScreenSharingState.enableScreenSharing();
- });
- this.monitor = HtmlUtils.getElementByIdOrFail('monitor');
- this.monitor.style.display = "none";
- this.monitor.addEventListener('click', (e: MouseEvent) => {
- e.preventDefault();
- //this.disableScreenSharing();
- requestedScreenSharingState.disableScreenSharing();
- });
-
this.pingCameraStatus();
//FIX ME SOUNDMETER: check stability of sound meter calculation
@@ -147,40 +68,8 @@ export class MediaManager {
}, this.userInputManager);
return;
}
-
- if (result.constraints.video !== false) {
- HtmlUtils.getElementByIdOrFail('div-myCamVideo').classList.remove('hide');
- } else {
- HtmlUtils.getElementByIdOrFail('div-myCamVideo').classList.add('hide');
- }/*
- if (result.constraints.audio !== false) {
- this.enableMicrophoneStyle();
- } else {
- this.disableMicrophoneStyle();
- }*/
-
- this.localStream = result.stream;
- this.myCamVideo.srcObject = this.localStream;
-
- // TODO: migrate all listeners to the store directly.
- this.triggerUpdatedLocalStreamCallbacks(result.stream);
});
- requestedCameraState.subscribe((enabled) => {
- if (enabled) {
- this.enableCameraStyle();
- } else {
- this.disableCameraStyle();
- }
- });
- requestedMicrophoneState.subscribe((enabled) => {
- if (enabled) {
- this.enableMicrophoneStyle();
- } else {
- this.disableMicrophoneStyle();
- }
- });
- //let screenSharingStream : MediaStream|null;
screenSharingLocalStreamStore.subscribe((result) => {
if (result.type === 'error') {
console.error(result.error);
@@ -191,38 +80,21 @@ export class MediaManager {
}
if (result.stream !== null) {
- this.enableScreenSharingStyle();
- mediaManager.localScreenCapture = result.stream;
-
- // TODO: migrate this out of MediaManager
- this.triggerStartedScreenSharingCallbacks(result.stream);
-
- //screenSharingStream = result.stream;
-
this.addScreenSharingActiveVideo('me', DivImportance.Normal);
HtmlUtils.getElementByIdOrFail('screen-sharing-me').srcObject = result.stream;
} else {
- this.disableScreenSharingStyle();
this.removeActiveScreenSharingVideo('me');
-
- // FIXME: we need the old stream that is being stopped!
- if (this.localScreenCapture) {
- this.triggerStoppedScreenSharingCallbacks(this.localScreenCapture);
- this.localScreenCapture = null;
- }
-
- //screenSharingStream = null;
}
});
- screenSharingAvailableStore.subscribe((available) => {
+ /*screenSharingAvailableStore.subscribe((available) => {
if (available) {
document.querySelector('.btn-monitor')?.classList.remove('hide');
} else {
document.querySelector('.btn-monitor')?.classList.add('hide');
}
- });
+ });*/
}
public updateScene(){
@@ -230,40 +102,6 @@ export class MediaManager {
//this.updateSoudMeter();
}
- public onUpdateLocalStream(callback: UpdatedLocalStreamCallback): void {
- this.updatedLocalStreamCallBacks.add(callback);
- }
-
- public onStartScreenSharing(callback: StartScreenSharingCallback): void {
- this.startScreenSharingCallBacks.add(callback);
- }
-
- public onStopScreenSharing(callback: StopScreenSharingCallback): void {
- this.stopScreenSharingCallBacks.add(callback);
- }
-
- removeUpdateLocalStreamEventListener(callback: UpdatedLocalStreamCallback): void {
- this.updatedLocalStreamCallBacks.delete(callback);
- }
-
- private triggerUpdatedLocalStreamCallbacks(stream: MediaStream|null): void {
- for (const callback of this.updatedLocalStreamCallBacks) {
- callback(stream);
- }
- }
-
- private triggerStartedScreenSharingCallbacks(stream: MediaStream): void {
- for (const callback of this.startScreenSharingCallBacks) {
- callback(stream);
- }
- }
-
- private triggerStoppedScreenSharingCallbacks(stream: MediaStream): void {
- for (const callback of this.stopScreenSharingCallBacks) {
- callback(stream);
- }
- }
-
public showGameOverlay(): void {
const gameOverlay = HtmlUtils.getElementByIdOrFail('game-overlay');
gameOverlay.classList.add('active');
@@ -290,42 +128,6 @@ export class MediaManager {
gameOverlayVisibilityStore.hideGameOverlay();
}
- private enableCameraStyle(){
- this.cinemaClose.style.display = "none";
- this.cinemaBtn.classList.remove("disabled");
- this.cinema.style.display = "block";
- }
-
- private disableCameraStyle(){
- this.cinemaClose.style.display = "block";
- this.cinema.style.display = "none";
- this.cinemaBtn.classList.add("disabled");
- }
-
- private enableMicrophoneStyle(){
- this.microphoneClose.style.display = "none";
- this.microphone.style.display = "block";
- this.microphoneBtn.classList.remove("disabled");
- }
-
- private disableMicrophoneStyle(){
- this.microphoneClose.style.display = "block";
- this.microphone.style.display = "none";
- this.microphoneBtn.classList.add("disabled");
- }
-
- private enableScreenSharingStyle(){
- this.monitorClose.style.display = "none";
- this.monitor.style.display = "block";
- this.monitorBtn.classList.add("enabled");
- }
-
- private disableScreenSharingStyle(){
- this.monitorClose.style.display = "block";
- this.monitor.style.display = "none";
- this.monitorBtn.classList.remove("enabled");
- }
-
addActiveVideo(user: UserSimplePeerInterface, userName: string = ""){
this.webrtcInAudio.play();
const userId = ''+user.userId
diff --git a/front/src/WebRtc/ScreenSharingPeer.ts b/front/src/WebRtc/ScreenSharingPeer.ts
index f1786ef3..947549eb 100644
--- a/front/src/WebRtc/ScreenSharingPeer.ts
+++ b/front/src/WebRtc/ScreenSharingPeer.ts
@@ -19,7 +19,7 @@ export class ScreenSharingPeer extends Peer {
public _connected: boolean = false;
private userId: number;
- constructor(user: UserSimplePeerInterface, initiator: boolean, private connection: RoomConnection) {
+ constructor(user: UserSimplePeerInterface, initiator: boolean, private connection: RoomConnection, stream: MediaStream | null) {
super({
initiator: initiator ? initiator : false,
//reconnectTimer: 10000,
@@ -81,7 +81,9 @@ export class ScreenSharingPeer extends Peer {
this._onFinish();
});
- this.pushScreenSharingToRemoteUser();
+ if (stream) {
+ this.addStream(stream);
+ }
}
private sendWebrtcScreenSharingSignal(data: unknown) {
@@ -141,16 +143,6 @@ export class ScreenSharingPeer extends Peer {
}
}
- private pushScreenSharingToRemoteUser() {
- const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture;
- if(!localScreenCapture){
- return;
- }
-
- this.addStream(localScreenCapture);
- return;
- }
-
public stopPushingScreenSharingToRemoteUser(stream: MediaStream) {
this.removeStream(stream);
this.write(new Buffer(JSON.stringify({type: MESSAGE_TYPE_CONSTRAINT, streamEnded: true})));
diff --git a/front/src/WebRtc/SimplePeer.ts b/front/src/WebRtc/SimplePeer.ts
index 4633374d..caec53c5 100644
--- a/front/src/WebRtc/SimplePeer.ts
+++ b/front/src/WebRtc/SimplePeer.ts
@@ -15,7 +15,10 @@ import {connectionManager} from "../Connexion/ConnectionManager";
import {GameConnexionTypes} from "../Url/UrlManager";
import {blackListManager} from "./BlackListManager";
import {get} from "svelte/store";
-import {localStreamStore, obtainedMediaConstraintStore} from "../Stores/MediaStore";
+import {localStreamStore, LocalStreamStoreValue, obtainedMediaConstraintStore} from "../Stores/MediaStore";
+import {screenSharingLocalStreamStore} from "../Stores/ScreenSharingStore";
+import {DivImportance, layoutManager} from "./LayoutManager";
+import {HtmlUtils} from "./HtmlUtils";
export interface UserSimplePeerInterface{
userId: number;
@@ -39,9 +42,9 @@ export class SimplePeer {
private PeerScreenSharingConnectionArray: Map = new Map();
private PeerConnectionArray: Map = new Map();
- private readonly sendLocalVideoStreamCallback: UpdatedLocalStreamCallback;
private readonly sendLocalScreenSharingStreamCallback: StartScreenSharingCallback;
private readonly stopLocalScreenSharingStreamCallback: StopScreenSharingCallback;
+ private readonly unsubscribers: (() => void)[] = [];
private readonly peerConnectionListeners: Array = new Array();
private readonly userId: number;
private lastWebrtcUserName: string|undefined;
@@ -49,13 +52,32 @@ export class SimplePeer {
constructor(private Connection: RoomConnection, private enableReporting: boolean, private myName: string) {
// We need to go through this weird bound function pointer in order to be able to "free" this reference later.
- this.sendLocalVideoStreamCallback = this.sendLocalVideoStream.bind(this);
this.sendLocalScreenSharingStreamCallback = this.sendLocalScreenSharingStream.bind(this);
this.stopLocalScreenSharingStreamCallback = this.stopLocalScreenSharingStream.bind(this);
- mediaManager.onUpdateLocalStream(this.sendLocalVideoStreamCallback);
- mediaManager.onStartScreenSharing(this.sendLocalScreenSharingStreamCallback);
- mediaManager.onStopScreenSharing(this.stopLocalScreenSharingStreamCallback);
+ this.unsubscribers.push(localStreamStore.subscribe((streamResult) => {
+ this.sendLocalVideoStream(streamResult);
+ }));
+
+ let localScreenCapture: MediaStream|null = null;
+
+ this.unsubscribers.push(screenSharingLocalStreamStore.subscribe((streamResult) => {
+ if (streamResult.type === 'error') {
+ // Let's ignore screen sharing errors, we will deal with those in a different way.
+ return;
+ }
+
+ if (streamResult.stream !== null) {
+ localScreenCapture = streamResult.stream;
+ this.sendLocalScreenSharingStream(localScreenCapture);
+ } else {
+ if (localScreenCapture) {
+ this.stopLocalScreenSharingStream(localScreenCapture);
+ localScreenCapture = null;
+ }
+ }
+ }));
+
this.userId = Connection.getUserId();
this.initialise();
}
@@ -106,13 +128,19 @@ export class SimplePeer {
if(!user.initiator){
return;
}
- this.createPeerConnection(user);
+ const streamResult = get(localStreamStore);
+ let stream : MediaStream | null = null;
+ if (streamResult.type === 'success' && streamResult.stream) {
+ stream = streamResult.stream;
+ }
+
+ this.createPeerConnection(user, stream);
}
/**
* create peer connection to bind users
*/
- private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null {
+ private createPeerConnection(user : UserSimplePeerInterface, localStream: MediaStream | null) : VideoPeer | null {
const peerConnection = this.PeerConnectionArray.get(user.userId)
if (peerConnection) {
if (peerConnection.destroyed) {
@@ -122,11 +150,11 @@ export class SimplePeer {
if (!peerConnexionDeleted) {
throw 'Error to delete peer connection';
}
- this.createPeerConnection(user);
+ //return this.createPeerConnection(user, localStream);
} else {
peerConnection.toClose = false;
+ return null;
}
- return null;
}
let name = user.name;
@@ -144,7 +172,7 @@ export class SimplePeer {
this.lastWebrtcUserName = user.webRtcUser;
this.lastWebrtcPassword = user.webRtcPassword;
- const peer = new VideoPeer(user, user.initiator ? user.initiator : false, this.Connection);
+ const peer = new VideoPeer(user, user.initiator ? user.initiator : false, this.Connection, localStream);
//permit to send message
mediaManager.addSendMessageCallback(user.userId,(message: string) => {
@@ -155,8 +183,9 @@ export class SimplePeer {
// When a connection is established to a video stream, and if a screen sharing is taking place,
// the user sharing screen should also initiate a connection to the remote user!
peer.on('connect', () => {
- if (mediaManager.localScreenCapture) {
- this.sendLocalScreenSharingStreamToUser(user.userId);
+ const streamResult = get(screenSharingLocalStreamStore);
+ if (streamResult.type === 'success' && streamResult.stream !== null) {
+ this.sendLocalScreenSharingStreamToUser(user.userId, streamResult.stream);
}
});
@@ -175,7 +204,7 @@ export class SimplePeer {
/**
* create peer connection to bind users
*/
- private createPeerScreenSharingConnection(user : UserSimplePeerInterface) : ScreenSharingPeer | null{
+ private createPeerScreenSharingConnection(user : UserSimplePeerInterface, stream: MediaStream | null) : ScreenSharingPeer | null{
const peerConnection = this.PeerScreenSharingConnectionArray.get(user.userId);
if(peerConnection){
if(peerConnection.destroyed){
@@ -185,7 +214,7 @@ export class SimplePeer {
if(!peerConnexionDeleted){
throw 'Error to delete peer connection';
}
- this.createPeerConnection(user);
+ this.createPeerConnection(user, stream);
}else {
peerConnection.toClose = false;
}
@@ -204,7 +233,7 @@ export class SimplePeer {
user.webRtcPassword = this.lastWebrtcPassword;
}
- const peer = new ScreenSharingPeer(user, user.initiator ? user.initiator : false, this.Connection);
+ const peer = new ScreenSharingPeer(user, user.initiator ? user.initiator : false, this.Connection, stream);
this.PeerScreenSharingConnectionArray.set(user.userId, peer);
for (const peerConnectionListener of this.peerConnectionListeners) {
@@ -294,7 +323,9 @@ export class SimplePeer {
* Unregisters any held event handler.
*/
public unregister() {
- mediaManager.removeUpdateLocalStreamEventListener(this.sendLocalVideoStreamCallback);
+ for (const unsubscriber of this.unsubscribers) {
+ unsubscriber();
+ }
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -302,7 +333,13 @@ export class SimplePeer {
try {
//if offer type, create peer connection
if(data.signal.type === "offer"){
- this.createPeerConnection(data);
+ const streamResult = get(localStreamStore);
+ let stream : MediaStream | null = null;
+ if (streamResult.type === 'success' && streamResult.stream) {
+ stream = streamResult.stream;
+ }
+
+ this.createPeerConnection(data, stream);
}
const peer = this.PeerConnectionArray.get(data.userId);
if (peer !== undefined) {
@@ -318,18 +355,26 @@ export class SimplePeer {
private receiveWebrtcScreenSharingSignal(data: WebRtcSignalReceivedMessageInterface) {
if (blackListManager.isBlackListed(data.userId)) return;
console.log("receiveWebrtcScreenSharingSignal", data);
+ const streamResult = get(screenSharingLocalStreamStore);
+ let stream : MediaStream | null = null;
+ if (streamResult.type === 'success' && streamResult.stream !== null) {
+ stream = streamResult.stream;
+ }
+
try {
//if offer type, create peer connection
if(data.signal.type === "offer"){
- this.createPeerScreenSharingConnection(data);
+ this.createPeerScreenSharingConnection(data, stream);
}
const peer = this.PeerScreenSharingConnectionArray.get(data.userId);
if (peer !== undefined) {
peer.signal(data.signal);
} else {
console.error('Could not find peer whose ID is "'+data.userId+'" in receiveWebrtcScreenSharingSignal');
- console.info('tentative to create new peer connexion');
- this.sendLocalScreenSharingStreamToUser(data.userId);
+ console.info('Attempt to create new peer connexion');
+ if (stream) {
+ this.sendLocalScreenSharingStreamToUser(data.userId, stream);
+ }
}
} catch (e) {
console.error(`receiveWebrtcSignal => ${data.userId}`, e);
@@ -339,21 +384,19 @@ export class SimplePeer {
}
}
- private pushVideoToRemoteUser(userId : number) {
+ private pushVideoToRemoteUser(userId: number, streamResult: LocalStreamStoreValue) {
try {
const PeerConnection = this.PeerConnectionArray.get(userId);
if (!PeerConnection) {
throw new Error('While adding media, cannot find user with ID ' + userId);
}
- const result = get(localStreamStore);
+ PeerConnection.write(new Buffer(JSON.stringify({type: MESSAGE_TYPE_CONSTRAINT, ...streamResult.constraints})));
- PeerConnection.write(new Buffer(JSON.stringify({type: MESSAGE_TYPE_CONSTRAINT, ...result.constraints})));
-
- if (result.type === 'error') {
+ if (streamResult.type === 'error') {
return;
}
- const localStream: MediaStream | null = result.stream;
+ const localStream: MediaStream | null = streamResult.stream;
if(!localStream){
return;
@@ -370,15 +413,11 @@ export class SimplePeer {
}
}
- private pushScreenSharingToRemoteUser(userId : number) {
+ private pushScreenSharingToRemoteUser(userId: number, localScreenCapture: MediaStream) {
const PeerConnection = this.PeerScreenSharingConnectionArray.get(userId);
if (!PeerConnection) {
throw new Error('While pushing screen sharing, cannot find user with ID ' + userId);
}
- const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture;
- if(!localScreenCapture){
- return;
- }
for (const track of localScreenCapture.getTracks()) {
PeerConnection.addTrack(track, localScreenCapture);
@@ -386,23 +425,18 @@ export class SimplePeer {
return;
}
- public sendLocalVideoStream(){
+ public sendLocalVideoStream(streamResult: LocalStreamStoreValue){
for (const user of this.Users) {
- this.pushVideoToRemoteUser(user.userId);
+ this.pushVideoToRemoteUser(user.userId, streamResult);
}
}
/**
* Triggered locally when clicking on the screen sharing button
*/
- public sendLocalScreenSharingStream() {
- if (!mediaManager.localScreenCapture) {
- console.error('Could not find localScreenCapture to share')
- return;
- }
-
+ public sendLocalScreenSharingStream(localScreenCapture: MediaStream) {
for (const user of this.Users) {
- this.sendLocalScreenSharingStreamToUser(user.userId);
+ this.sendLocalScreenSharingStreamToUser(user.userId, localScreenCapture);
}
}
@@ -415,11 +449,11 @@ export class SimplePeer {
}
}
- private sendLocalScreenSharingStreamToUser(userId: number): void {
+ private sendLocalScreenSharingStreamToUser(userId: number, localScreenCapture: MediaStream): void {
if (blackListManager.isBlackListed(userId)) return;
// If a connection already exists with user (because it is already sharing a screen with us... let's use this connection)
if (this.PeerScreenSharingConnectionArray.has(userId)) {
- this.pushScreenSharingToRemoteUser(userId);
+ this.pushScreenSharingToRemoteUser(userId, localScreenCapture);
return;
}
@@ -427,7 +461,7 @@ export class SimplePeer {
userId,
initiator: true
};
- const PeerConnectionScreenSharing = this.createPeerScreenSharingConnection(screenSharingUser);
+ const PeerConnectionScreenSharing = this.createPeerScreenSharingConnection(screenSharingUser, localScreenCapture);
if (!PeerConnectionScreenSharing) {
return;
}
diff --git a/front/src/WebRtc/VideoPeer.ts b/front/src/WebRtc/VideoPeer.ts
index 32e8e97f..5ca8952c 100644
--- a/front/src/WebRtc/VideoPeer.ts
+++ b/front/src/WebRtc/VideoPeer.ts
@@ -27,7 +27,7 @@ export class VideoPeer extends Peer {
private onBlockSubscribe: Subscription;
private onUnBlockSubscribe: Subscription;
- constructor(public user: UserSimplePeerInterface, initiator: boolean, private connection: RoomConnection) {
+ constructor(public user: UserSimplePeerInterface, initiator: boolean, private connection: RoomConnection, localStream: MediaStream | null) {
super({
initiator: initiator ? initiator : false,
//reconnectTimer: 10000,
@@ -107,7 +107,7 @@ export class VideoPeer extends Peer {
this._onFinish();
});
- this.pushVideoToRemoteUser();
+ this.pushVideoToRemoteUser(localStream);
this.onBlockSubscribe = blackListManager.onBlockStream.subscribe((userId) => {
if (userId === this.userId) {
this.toggleRemoteStream(false);
@@ -190,9 +190,8 @@ export class VideoPeer extends Peer {
}
}
- private pushVideoToRemoteUser() {
+ private pushVideoToRemoteUser(localStream: MediaStream | null) {
try {
- const localStream: MediaStream | null = mediaManager.localStream;
this.write(new Buffer(JSON.stringify({type: MESSAGE_TYPE_CONSTRAINT, ...get(obtainedMediaConstraintStore)})));
if(!localStream){
diff --git a/front/src/index.ts b/front/src/index.ts
index 2cdcaa19..f9017c24 100644
--- a/front/src/index.ts
+++ b/front/src/index.ts
@@ -9,7 +9,7 @@ import {SelectCharacterScene} from "./Phaser/Login/SelectCharacterScene";
import {SelectCompanionScene} from "./Phaser/Login/SelectCompanionScene";
import {EnableCameraScene} from "./Phaser/Login/EnableCameraScene";
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
-import {ResizableScene} from "./Phaser/Login/ResizableScene";
+import WebFontLoaderPlugin from 'phaser3-rex-plugins/plugins/webfontloader-plugin.js';
import {EntryScene} from "./Phaser/Login/EntryScene";
import {coWebsiteManager} from "./WebRtc/CoWebsiteManager";
import {MenuScene} from "./Phaser/Menu/MenuScene";
@@ -107,6 +107,13 @@ const config: GameConfig = {
roundPixels: true,
antialias: false
},
+ plugins: {
+ global: [{
+ key: 'rexWebFontLoader',
+ plugin: WebFontLoaderPlugin,
+ start: true
+ }]
+ },
physics: {
default: "arcade",
arcade: {
diff --git a/front/src/rex-plugins.d.ts b/front/src/rex-plugins.d.ts
index d5457702..2e160315 100644
--- a/front/src/rex-plugins.d.ts
+++ b/front/src/rex-plugins.d.ts
@@ -7,6 +7,10 @@ declare module 'phaser3-rex-plugins/plugins/gestures-plugin.js' {
const content: any; // eslint-disable-line
export default content;
}
+declare module 'phaser3-rex-plugins/plugins/webfontloader-plugin.js' {
+ const content: any; // eslint-disable-line
+ export default content;
+}
declare module 'phaser3-rex-plugins/plugins/gestures.js' {
export const Pinch: any; // eslint-disable-line
}
diff --git a/front/style/fonts.scss b/front/style/fonts.scss
new file mode 100644
index 00000000..5ef9b9b4
--- /dev/null
+++ b/front/style/fonts.scss
@@ -0,0 +1 @@
+@import "~@fontsource/press-start-2p/index.css";
\ No newline at end of file
diff --git a/front/style/index.scss b/front/style/index.scss
index 67e85c5b..47f13c3b 100644
--- a/front/style/index.scss
+++ b/front/style/index.scss
@@ -1,4 +1,5 @@
@import "cowebsite.scss";
@import "cowebsite-mobile.scss";
@import "style.css";
-@import "mobile-style.scss";
\ No newline at end of file
+@import "mobile-style.scss";
+@import "fonts.scss";
\ No newline at end of file
diff --git a/front/style/mobile-style.scss b/front/style/mobile-style.scss
index 21753ebd..1b37053a 100644
--- a/front/style/mobile-style.scss
+++ b/front/style/mobile-style.scss
@@ -1,9 +1,24 @@
+@media (hover: none) {
+ /**
+ * If we cannot hover over elements, let's display camera button in full.
+ */
+ .btn-cam-action {
+ div {
+ transform: translateY(0px);
+ }
+ }
+}
+
@media screen and (max-width: 700px),
screen and (max-height: 700px){
- video#myCamVideo {
+ video.myCamVideo {
width: 150px;
}
+ .div-myCamVideo.hide {
+ right: -160px;
+ }
+
.sidebar {
width: 20%;
min-width: 200px;
@@ -22,21 +37,6 @@
}
}
- .btn-cam-action {
- min-width: 150px;
-
- &:hover{
- transform: translateY(20px);
- }
- div {
- margin: 0 1%;
- &:hover {
- background-color: #666;
- }
- margin-bottom: 30px;
- }
- }
-
.main-section {
position: absolute;
width: 100%;
diff --git a/front/style/style.css b/front/style/style.css
index a3bbfa1d..525b517a 100644
--- a/front/style/style.css
+++ b/front/style/style.css
@@ -133,11 +133,11 @@ body .message-info.warning{
outline: none;
}
-.video-container#div-myCamVideo{
+.video-container.div-myCamVideo{
border: none;
}
-#div-myCamVideo {
+.div-myCamVideo {
position: absolute;
right: 15px;
bottom: 30px;
@@ -146,11 +146,11 @@ body .message-info.warning{
transition: right 350ms;
}
-#div-myCamVideo.hide {
+.div-myCamVideo.hide {
right: -20vw;
}
-video#myCamVideo{
+video.myCamVideo{
width: 15vw;
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
@@ -212,7 +212,9 @@ video#myCamVideo{
/*btn animation*/
.btn-cam-action div{
cursor: url('./images/cursor_pointer.png'), pointer;
- /*position: absolute;*/
+ display: flex;
+ align-items: center;
+ justify-content: center;
border: solid 0px black;
width: 44px;
height: 44px;
@@ -267,8 +269,6 @@ video#myCamVideo{
.btn-cam-action div img{
height: 22px;
width: 30px;
- top: calc(48px - 37px);
- left: calc(48px - 41px);
position: relative;
cursor: url('./images/cursor_pointer.png'), pointer;
}
diff --git a/front/tests/Phaser/Connexion/LocalUserTest.ts b/front/tests/Phaser/Connexion/LocalUserTest.ts
index 25b54005..4ba20745 100644
--- a/front/tests/Phaser/Connexion/LocalUserTest.ts
+++ b/front/tests/Phaser/Connexion/LocalUserTest.ts
@@ -19,8 +19,14 @@ describe("isUserNameValid()", () => {
it("should not validate spaces", () => {
expect(isUserNameValid(' ')).toBe(false);
});
- it("should not validate special characters", () => {
- expect(isUserNameValid('a&-')).toBe(false);
+ it("should validate special characters", () => {
+ expect(isUserNameValid('%&-')).toBe(true);
+ });
+ it("should validate accents", () => {
+ expect(isUserNameValid('éàëè')).toBe(true);
+ });
+ it("should validate chinese characters", () => {
+ expect(isUserNameValid('中文鍵盤')).toBe(true);
});
});
diff --git a/front/webpack.config.ts b/front/webpack.config.ts
index cc87572a..6ebf907f 100644
--- a/front/webpack.config.ts
+++ b/front/webpack.config.ts
@@ -102,9 +102,17 @@ module.exports = {
}
},
{
- test: /\.(ttf|eot|svg|png|gif|jpg)$/,
+ test: /\.(eot|svg|png|gif|jpg)$/,
exclude: /node_modules/,
type: 'asset'
+ },
+ {
+ test: /\.(woff(2)?|ttf)$/,
+ type: 'asset',
+ generator: {
+ filename: 'fonts/[name][ext]'
+ }
+
}
],
},
diff --git a/front/yarn.lock b/front/yarn.lock
index bbdf0e06..180c82bf 100644
--- a/front/yarn.lock
+++ b/front/yarn.lock
@@ -50,6 +50,11 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
+"@fontsource/press-start-2p@^4.3.0":
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/@fontsource/press-start-2p/-/press-start-2p-4.3.0.tgz#37124387f7fbfe7792b5fc9a1906b80d9aeda4c6"
+ integrity sha512-gmS4070EoZp5/6NUJ+tBnvtDiSmFcR+S+ClAOJ8NGFXDWOkO12yMnyGJEJaDCNCAMX0s2TQCcmr6qWKx5ad3RQ==
+
"@nodelib/fs.scandir@2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69"