From 405f7b11374e6dcbfd1fe069eb663bc9595fadb6 Mon Sep 17 00:00:00 2001 From: Lurkars Date: Tue, 20 Apr 2021 21:37:48 +0200 Subject: [PATCH 01/16] audio player volume improvements --- front/dist/index.tmpl.html | 12 +++++++--- front/dist/resources/style/style.css | 13 +++++++++++ front/src/WebRtc/AudioManager.ts | 34 +++++++++++++++++++--------- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/front/dist/index.tmpl.html b/front/dist/index.tmpl.html index 062622b8..2c3aef43 100644 --- a/front/dist/index.tmpl.html +++ b/front/dist/index.tmpl.html @@ -88,9 +88,15 @@ - - - + + + + + + + + + diff --git a/front/dist/resources/style/style.css b/front/dist/resources/style/style.css index ff79245c..3ad0bdcf 100644 --- a/front/dist/resources/style/style.css +++ b/front/dist/resources/style/style.css @@ -403,6 +403,19 @@ body { visibility: hidden; display: none; } +#audioplayer_volume_icon_playing.low #audioplayer_volume_icon_playing_high { + visibility: hidden; + display: none; +} +#audioplayer_volume_icon_playing.low #audioplayer_volume_icon_playing_mid { + visibility: hidden; + display: none; +} +#audioplayer_volume_icon_playing.mid #audioplayer_volume_icon_playing_high { + visibility: hidden; + display: none; +} + #audioplayerctrl > #audioplayer_volume { width: 100%; background-color: rgba(0,0,0,0.5); diff --git a/front/src/WebRtc/AudioManager.ts b/front/src/WebRtc/AudioManager.ts index 60255a77..753cf7fb 100644 --- a/front/src/WebRtc/AudioManager.ts +++ b/front/src/WebRtc/AudioManager.ts @@ -11,7 +11,7 @@ enum audioStates { const audioPlayerDivId = "audioplayer"; const audioPlayerCtrlId = "audioplayerctrl"; const audioPlayerVolId = "audioplayer_volume"; -const audioPlayerMuteId = "audioplayer_volume_icon_playing"; +const audioPlayerVolumeIconId = "audioplayer_volume_icon_playing"; const animationTime = 500; class AudioManager { @@ -21,7 +21,7 @@ class AudioManager { private audioPlayerCtrl: HTMLDivElement; private audioPlayerElem: HTMLAudioElement | undefined; private audioPlayerVol: HTMLInputElement; - private audioPlayerMute: HTMLInputElement; + private audioPlayerVolumeIcon: HTMLInputElement; private volume = 1; private muted = false; @@ -32,14 +32,14 @@ class AudioManager { this.audioPlayerDiv = HtmlUtils.getElementByIdOrFail(audioPlayerDivId); this.audioPlayerCtrl = HtmlUtils.getElementByIdOrFail(audioPlayerCtrlId); this.audioPlayerVol = HtmlUtils.getElementByIdOrFail(audioPlayerVolId); - this.audioPlayerMute = HtmlUtils.getElementByIdOrFail(audioPlayerMuteId); + this.audioPlayerVolumeIcon = HtmlUtils.getElementByIdOrFail(audioPlayerVolumeIconId); this.volume = localUserStore.getAudioPlayerVolume(); this.audioPlayerVol.value = '' + this.volume; this.muted = localUserStore.getAudioPlayerMuted(); if (this.muted) { - this.audioPlayerMute.classList.add('muted'); + this.audioPlayerVolumeIcon.classList.add('muted'); } } @@ -93,7 +93,23 @@ class AudioManager { this.volumeReduced = reduceVolume; this.audioPlayerElem.volume = this.volume; - this.audioPlayerVol.value = '' + this.volume; + if (this.muted) { + this.audioPlayerVolumeIcon.classList.add('muted'); + this.audioPlayerVol.value = '0'; + } else { + this.audioPlayerVol.value = '' + this.volume; + this.audioPlayerVolumeIcon.classList.remove('muted'); + if (this.volume < 0.3) { + this.audioPlayerVolumeIcon.classList.add('low'); + } else if (this.volume < 0.7) { + this.audioPlayerVolumeIcon.classList.remove('low'); + this.audioPlayerVolumeIcon.classList.add('mid'); + } else { + this.audioPlayerVolumeIcon.classList.remove('low'); + this.audioPlayerVolumeIcon.classList.remove('mid'); + } + } + this.audioPlayerElem.muted = this.muted; } @@ -129,16 +145,12 @@ class AudioManager { this.muted = !this.muted; this.changeVolume(); localUserStore.setAudioPlayerMuted(this.muted); - - if (this.muted) { - this.audioPlayerMute.classList.add('muted'); - } else { - this.audioPlayerMute.classList.remove('muted'); - } } this.audioPlayerVol.oninput = (ev: Event)=> { this.setVolume(parseFloat((ev.currentTarget).value)); + this.muted = false; + localUserStore.setAudioPlayerMuted(this.muted); this.changeVolume(); (ev.currentTarget).blur(); From 3702173cd4b773ae9f988041a9e85e9dadcea24a Mon Sep 17 00:00:00 2001 From: Lurkars Date: Wed, 11 Aug 2021 20:01:51 +0200 Subject: [PATCH 02/16] migrate to svelte --- .../AudioManager/AudioManager.svelte | 127 ++++++++++++++---- 1 file changed, 98 insertions(+), 29 deletions(-) diff --git a/front/src/Components/AudioManager/AudioManager.svelte b/front/src/Components/AudioManager/AudioManager.svelte index a78b4bde..6d59b995 100644 --- a/front/src/Components/AudioManager/AudioManager.svelte +++ b/front/src/Components/AudioManager/AudioManager.svelte @@ -1,6 +1,4 @@
+ {#if $userIsConnected} +
+ {#if PROFILE_URL != undefined} + + {/if} +
+
+ +
+ {:else} +
+ Sing in +
+ {/if}
-
-
-
-
@@ -74,6 +95,12 @@ align-items: center; margin-bottom: 20px; + iframe{ + width: 100%; + height: 50vh; + border: none; + } + button { height: 50px; width: 250px; diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 9e245d3a..2010689c 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -7,6 +7,8 @@ import { localUserStore } from "./LocalUserStore"; import { CharacterTexture, LocalUser } from "./LocalUser"; import { Room } from "./Room"; import { _ServiceWorker } from "../Network/ServiceWorker"; +import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore"; +import { userIsConnected } from "../Stores/MenuStore"; class ConnectionManager { private localUser!: LocalUser; @@ -15,6 +17,7 @@ class ConnectionManager { private reconnectingTimeout: NodeJS.Timeout | null = null; private _unloading: boolean = false; private authToken: string | null = null; + private _currentRoom: Room | null = null; private serviceWorker?: _ServiceWorker; @@ -30,28 +33,39 @@ class ConnectionManager { } /** - * @return Promise + * TODO fix me to be move in game manager */ - public loadOpenIDScreen(): Promise { + public loadOpenIDScreen() { const state = localUserStore.generateState(); const nonce = localUserStore.generateNonce(); localUserStore.setAuthToken(null); - //TODO refactor this and don't realise previous call - return Axios.get(`http://${PUSHER_URL}/login-screen?state=${state}&nonce=${nonce}`) - .then(() => { - window.location.assign(`http://${PUSHER_URL}/login-screen?state=${state}&nonce=${nonce}`); - }) - .catch((err) => { - console.error(err, "We don't have URL to regenerate authentication user"); - //TODO show modal login - window.location.reload(); - }); + //TODO fix me to redirect this URL by pusher + if (!this._currentRoom || !this._currentRoom.iframeAuthentication) { + loginSceneVisibleIframeStore.set(false); + return null; + } + const redirectUrl = `${this._currentRoom.iframeAuthentication}?state=${state}&nonce=${nonce}`; + window.location.assign(redirectUrl); + return redirectUrl; } - public logout() { + /** + * Logout + */ + public async logout() { + //user logout, set connected store for menu at false + userIsConnected.set(false); + + //Logout user in pusher and hydra + const token = localUserStore.getAuthToken(); + const { authToken } = await Axios.get(`${PUSHER_URL}/logout-callback`, { params: { token } }).then( + (res) => res.data + ); localUserStore.setAuthToken(null); - window.location.reload(); + + //Go on login page can permit to clear token and start authentication process + window.location.assign("/login"); } /** @@ -60,8 +74,13 @@ class ConnectionManager { public async initGameConnexion(): Promise { const connexionType = urlManager.getGameConnexionType(); this.connexionType = connexionType; - let room: Room | null = null; - if (connexionType === GameConnexionTypes.jwt) { + this._currentRoom = null; + if (connexionType === GameConnexionTypes.login) { + //TODO clear all cash and redirect on login scene (iframe) + localUserStore.setAuthToken(null); + this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl())); + urlManager.pushRoomIdToUrl(this._currentRoom); + } else if (connexionType === GameConnexionTypes.jwt) { const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get("code"); const state = urlParams.get("state"); @@ -71,14 +90,15 @@ class ConnectionManager { if (!code) { throw "No Auth code provided"; } - const nonce = localUserStore.getNonce(); - const { authToken } = await Axios.get(`${PUSHER_URL}/login-callback`, { params: { code, nonce } }).then( - (res) => res.data - ); - localUserStore.setAuthToken(authToken); - this.authToken = authToken; - room = await Room.createRoom(new URL(localUserStore.getLastRoomUrl())); - urlManager.pushRoomIdToUrl(room); + localUserStore.setCode(code); + try { + await this.checkAuthUserConnexion(); + } catch (err) { + console.error(err); + this.loadOpenIDScreen(); + } + this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl())); + urlManager.pushRoomIdToUrl(this._currentRoom); } else if (connexionType === GameConnexionTypes.register) { //@deprecated const organizationMemberToken = urlManager.getOrganizationToken(); @@ -92,7 +112,7 @@ class ConnectionManager { const roomUrl = data.roomUrl; - room = await Room.createRoom( + this._currentRoom = await Room.createRoom( new URL( window.location.protocol + "//" + @@ -102,7 +122,7 @@ class ConnectionManager { window.location.hash ) ); - urlManager.pushRoomIdToUrl(room); + urlManager.pushRoomIdToUrl(this._currentRoom); } else if ( connexionType === GameConnexionTypes.organization || connexionType === GameConnexionTypes.anonymous || @@ -112,12 +132,18 @@ class ConnectionManager { //todo: add here some kind of warning if authToken has expired. if (!this.authToken) { await this.anonymousLogin(); + } else { + try { + await this.checkAuthUserConnexion(); + } catch (err) { + console.error(err); + } } this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null let roomPath: string; if (connexionType === GameConnexionTypes.empty) { - roomPath = window.location.protocol + "//" + window.location.host + START_ROOM_URL; + roomPath = localUserStore.getLastRoomUrl(); //get last room path from cache api try { const lastRoomUrl = await localUserStore.getLastRoomUrlCacheApi(); @@ -138,13 +164,13 @@ class ConnectionManager { } //get detail map for anonymous login and set texture in local storage - room = await Room.createRoom(new URL(roomPath)); - if (room.textures != undefined && room.textures.length > 0) { + this._currentRoom = await Room.createRoom(new URL(roomPath)); + if (this._currentRoom.textures != undefined && this._currentRoom.textures.length > 0) { //check if texture was changed if (this.localUser.textures.length === 0) { - this.localUser.textures = room.textures; + this.localUser.textures = this._currentRoom.textures; } else { - room.textures.forEach((newTexture) => { + this._currentRoom.textures.forEach((newTexture) => { const alreadyExistTexture = this.localUser.textures.find((c) => newTexture.id === c.id); if (this.localUser.textures.findIndex((c) => newTexture.id === c.id) !== -1) { return; @@ -155,12 +181,12 @@ class ConnectionManager { localUserStore.saveUser(this.localUser); } } - if (room == undefined) { + if (this._currentRoom == undefined) { return Promise.reject(new Error("Invalid URL")); } this.serviceWorker = new _ServiceWorker(); - return Promise.resolve(room); + return Promise.resolve(this._currentRoom); } public async anonymousLogin(isBenchmark: boolean = false): Promise { @@ -215,9 +241,6 @@ class ConnectionManager { }); connection.onConnect((connect: OnConnectInterface) => { - //save last room url connected - localUserStore.setLastRoomUrl(roomUrl); - resolve(connect); }); }).catch((err) => { @@ -237,6 +260,34 @@ class ConnectionManager { get getConnexionType() { return this.connexionType; } + + async checkAuthUserConnexion() { + //set connected store for menu at false + userIsConnected.set(false); + + const state = localUserStore.getState(); + const code = localUserStore.getCode(); + if (!state || !localUserStore.verifyState(state)) { + throw "Could not validate state!"; + } + if (!code) { + throw "No Auth code provided"; + } + const nonce = localUserStore.getNonce(); + const token = localUserStore.getAuthToken(); + const { authToken } = await Axios.get(`${PUSHER_URL}/login-callback`, { params: { code, nonce, token } }).then( + (res) => res.data + ); + localUserStore.setAuthToken(authToken); + this.authToken = authToken; + + //user connected, set connected store for menu at true + userIsConnected.set(true); + } + + get currentRoom() { + return this._currentRoom; + } } export const connectionManager = new ConnectionManager(); diff --git a/front/src/Connexion/LocalUserStore.ts b/front/src/Connexion/LocalUserStore.ts index 05c9613d..6c20aadb 100644 --- a/front/src/Connexion/LocalUserStore.ts +++ b/front/src/Connexion/LocalUserStore.ts @@ -1,5 +1,6 @@ import { areCharacterLayersValid, isUserNameValid, LocalUser } from "./LocalUser"; import { v4 as uuidv4 } from "uuid"; +import { START_ROOM_URL } from "../Enum/EnvironmentVariable"; const playerNameKey = "playerName"; const selectedPlayerKey = "selectedPlayer"; @@ -17,6 +18,7 @@ const authToken = "authToken"; const state = "state"; const nonce = "nonce"; const notification = "notificationPermission"; +const code = "code"; const cameraSetup = "cameraSetup"; const cacheAPIIndex = "workavdenture-cache"; @@ -126,7 +128,9 @@ class LocalUserStore { }); } getLastRoomUrl(): string { - return localStorage.getItem(lastRoomUrl) ?? ""; + return ( + localStorage.getItem(lastRoomUrl) ?? window.location.protocol + "//" + window.location.host + START_ROOM_URL + ); } getLastRoomUrlCacheApi(): Promise { return caches.open(cacheAPIIndex).then((cache) => { @@ -161,19 +165,24 @@ class LocalUserStore { verifyState(value: string): boolean { const oldValue = localStorage.getItem(state); - localStorage.removeItem(state); return oldValue === value; } + getState(): string | null { + return localStorage.getItem(state); + } generateNonce(): string { const newNonce = uuidv4(); localStorage.setItem(nonce, newNonce); return newNonce; } - getNonce(): string | null { - const oldValue = localStorage.getItem(nonce); - localStorage.removeItem(nonce); - return oldValue; + return localStorage.getItem(nonce); + } + setCode(value: string): void { + localStorage.setItem(code, value); + } + getCode(): string | null { + return localStorage.getItem(code); } setCameraSetup(cameraId: string) { diff --git a/front/src/Connexion/Room.ts b/front/src/Connexion/Room.ts index be9b5294..0e624d78 100644 --- a/front/src/Connexion/Room.ts +++ b/front/src/Connexion/Room.ts @@ -14,6 +14,8 @@ export interface RoomRedirect { export class Room { public readonly id: string; public readonly isPublic: boolean; + private _authenticationMandatory: boolean = false; + private _iframeAuthentication?: string; private _mapUrl: string | undefined; private _textures: CharacterTexture[] | undefined; private instance: string | undefined; @@ -101,6 +103,8 @@ export class Room { console.log("Map ", this.id, " resolves to URL ", data.mapUrl); this._mapUrl = data.mapUrl; this._textures = data.textures; + this._authenticationMandatory = data.authenticationMandatory || false; + this._iframeAuthentication = data.iframeAuthentication; return new MapDetail(data.mapUrl, data.textures); } @@ -186,4 +190,12 @@ export class Room { } return this._mapUrl; } + + get authenticationMandatory(): boolean { + return this._authenticationMandatory; + } + + get iframeAuthentication(): string | undefined { + return this._iframeAuthentication; + } } diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 248253a5..08672be1 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -78,6 +78,11 @@ export class RoomConnection implements RoomConnection { * * @param token A JWT token containing the email of the user * @param roomUrl The URL of the room in the form "https://example.com/_/[instance]/[map_url]" or "https://example.com/@/[org]/[event]/[map]" + * @param name + * @param characterLayers + * @param position + * @param viewport + * @param companion */ public constructor( token: string | null, @@ -218,7 +223,7 @@ export class RoomConnection implements RoomConnection { worldFullMessageStream.onMessage(); this.closed = true; } else if (message.hasTokenexpiredmessage()) { - connectionManager.loadOpenIDScreen(); + connectionManager.logout(); this.closed = true; //technically, this isn't needed since loadOpenIDScreen() will do window.location.assign() but I prefer to leave it for consistency } else if (message.hasWorldconnexionmessage()) { worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage()); diff --git a/front/src/Enum/EnvironmentVariable.ts b/front/src/Enum/EnvironmentVariable.ts index 907162d4..60678822 100644 --- a/front/src/Enum/EnvironmentVariable.ts +++ b/front/src/Enum/EnvironmentVariable.ts @@ -19,6 +19,7 @@ export const MAX_PER_GROUP = parseInt(process.env.MAX_PER_GROUP || "4"); export const DISPLAY_TERMS_OF_USE = process.env.DISPLAY_TERMS_OF_USE == "true"; export const NODE_ENV = process.env.NODE_ENV || "development"; export const CONTACT_URL = process.env.CONTACT_URL || undefined; +export const PROFILE_URL = process.env.PROFILE_URL || undefined; export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600; diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index 068e1734..1bf18d8d 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -35,7 +35,9 @@ export class GameManager { this.startRoom = await connectionManager.initGameConnexion(); this.loadMap(this.startRoom); - if (!this.playerName) { + //If player name was not set show login scene with player name + //If Room si not public and Auth was not set, show login scene to authenticate user (OpenID - SSO - Anonymous) + if (!this.playerName || (this.startRoom.authenticationMandatory && !localUserStore.getAuthToken())) { return LoginSceneName; } else if (!this.characterLayers || !this.characterLayers.length) { return SelectCharacterSceneName; @@ -143,6 +145,10 @@ export class GameManager { if (this.currentGameSceneName === null) throw "No current scene id set!"; return this.scenePlugin.get(this.currentGameSceneName) as GameScene; } + + public get currentStartedRoom() { + return this.startRoom; + } } export const gameManager = new GameManager(); diff --git a/front/src/Phaser/Login/LoginScene.ts b/front/src/Phaser/Login/LoginScene.ts index 0cca9ccd..7421934d 100644 --- a/front/src/Phaser/Login/LoginScene.ts +++ b/front/src/Phaser/Login/LoginScene.ts @@ -1,7 +1,9 @@ -import { gameManager } from "../Game/GameManager"; import { SelectCharacterSceneName } from "./SelectCharacterScene"; import { ResizableScene } from "./ResizableScene"; -import { loginSceneVisibleStore } from "../../Stores/LoginSceneStore"; +import { loginSceneVisibleIframeStore, loginSceneVisibleStore } from "../../Stores/LoginSceneStore"; +import { localUserStore } from "../../Connexion/LocalUserStore"; +import { connectionManager } from "../../Connexion/ConnectionManager"; +import { gameManager } from "../Game/GameManager"; export const LoginSceneName = "LoginScene"; @@ -18,6 +20,16 @@ export class LoginScene extends ResizableScene { preload() {} create() { + loginSceneVisibleIframeStore.set(false); + //If authentication is mandatory, push authentication iframe + if ( + localUserStore.getAuthToken() == undefined && + gameManager.currentStartedRoom && + gameManager.currentStartedRoom?.authenticationMandatory + ) { + connectionManager.loadOpenIDScreen(); + loginSceneVisibleIframeStore.set(true); + } loginSceneVisibleStore.set(true); } diff --git a/front/src/Stores/LoginSceneStore.ts b/front/src/Stores/LoginSceneStore.ts index 6e2ea18b..4bd5b10a 100644 --- a/front/src/Stores/LoginSceneStore.ts +++ b/front/src/Stores/LoginSceneStore.ts @@ -1,3 +1,4 @@ import { writable } from "svelte/store"; export const loginSceneVisibleStore = writable(false); +export const loginSceneVisibleIframeStore = writable(false); diff --git a/front/src/Stores/MenuStore.ts b/front/src/Stores/MenuStore.ts index 024c742d..035ba174 100644 --- a/front/src/Stores/MenuStore.ts +++ b/front/src/Stores/MenuStore.ts @@ -6,6 +6,8 @@ import { CONTACT_URL } from "../Enum/EnvironmentVariable"; export const menuIconVisiblilityStore = writable(false); export const menuVisiblilityStore = writable(false); export const menuInputFocusStore = writable(false); +export const loginUrlStore = writable(false); +export const userIsConnected = writable(false); let warningContainerTimeout: Timeout | null = null; function createWarningContainerStore() { diff --git a/front/src/Stores/PlayersStore.ts b/front/src/Stores/PlayersStore.ts index 86ab136f..e6f5b1af 100644 --- a/front/src/Stores/PlayersStore.ts +++ b/front/src/Stores/PlayersStore.ts @@ -2,6 +2,7 @@ import { writable } from "svelte/store"; import type { PlayerInterface } from "../Phaser/Game/PlayerInterface"; import type { RoomConnection } from "../Connexion/RoomConnection"; import { getRandomColor } from "../WebRtc/ColorGenerator"; +import { localUserStore } from "../Connexion/LocalUserStore"; let idCount = 0; diff --git a/front/src/Url/UrlManager.ts b/front/src/Url/UrlManager.ts index 6d4949ab..f1e15db1 100644 --- a/front/src/Url/UrlManager.ts +++ b/front/src/Url/UrlManager.ts @@ -1,4 +1,5 @@ import type { Room } from "../Connexion/Room"; +import { localUserStore } from "../Connexion/LocalUserStore"; export enum GameConnexionTypes { anonymous = 1, @@ -7,13 +8,16 @@ export enum GameConnexionTypes { empty, unknown, jwt, + login, } //this class is responsible with analysing and editing the game's url class UrlManager { public getGameConnexionType(): GameConnexionTypes { const url = window.location.pathname.toString(); - if (url === "/jwt") { + if (url === "/login") { + return GameConnexionTypes.login; + } else if (url === "/jwt") { return GameConnexionTypes.jwt; } else if (url.includes("_/")) { return GameConnexionTypes.anonymous; @@ -35,6 +39,8 @@ class UrlManager { public pushRoomIdToUrl(room: Room): void { if (window.location.pathname === room.id) return; + //Set last room visited! (connected or nor, must to be saved in localstorage and cache API) + localUserStore.setLastRoomUrl(room.key); const hash = window.location.hash; const search = room.search.toString(); history.pushState({}, "WorkAdventure", room.id + (search ? "?" + search : "") + hash); diff --git a/front/webpack.config.ts b/front/webpack.config.ts index 9d9a4a7b..48db1afa 100644 --- a/front/webpack.config.ts +++ b/front/webpack.config.ts @@ -7,6 +7,7 @@ import MiniCssExtractPlugin from "mini-css-extract-plugin"; import sveltePreprocess from "svelte-preprocess"; import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; import NodePolyfillPlugin from "node-polyfill-webpack-plugin"; +import { PROFILE_URL } from "./src/Enum/EnvironmentVariable"; const mode = process.env.NODE_ENV ?? "development"; const buildNpmTypingsForApi = !!process.env.BUILD_TYPINGS; @@ -191,6 +192,7 @@ module.exports = { UPLOADER_URL: null, ADMIN_URL: undefined, CONTACT_URL: null, + PROFILE_URL: null, DEBUG_MODE: null, STUN_SERVER: null, TURN_SERVER: null, diff --git a/pusher/src/Controller/AuthenticateController.ts b/pusher/src/Controller/AuthenticateController.ts index ffb6c048..000ac0ca 100644 --- a/pusher/src/Controller/AuthenticateController.ts +++ b/pusher/src/Controller/AuthenticateController.ts @@ -2,7 +2,7 @@ import { v4 } from "uuid"; import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js"; import { BaseController } from "./BaseController"; import { adminApi } from "../Services/AdminApi"; -import { jwtTokenManager } from "../Services/JWTTokenManager"; +import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager"; import { parse } from "query-string"; import { openIDClient } from "../Services/OpenIDClient"; @@ -17,6 +17,7 @@ export class AuthenticateController extends BaseController { this.openIDCallback(); this.register(); this.anonymLogin(); + this.profileCallback(); } openIDLogin() { @@ -48,14 +49,31 @@ export class AuthenticateController extends BaseController { res.onAborted(() => { console.warn("/message request was aborted"); }); - const { code, nonce } = parse(req.getQuery()); + const { code, nonce, token } = parse(req.getQuery()); try { + //verify connected by token + if (token != undefined) { + try { + const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false); + if (authTokenData.hydraAccessToken == undefined) { + throw Error("Token cannot to be check on Hydra"); + } + await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken); + res.writeStatus("200"); + this.addCorsHeaders(res); + return res.end(JSON.stringify({ authToken: token })); + } catch (err) { + console.info("User was not connected", err); + } + } + + //user have not token created, check data on hydra and create token const userInfo = await openIDClient.getUserInfo(code as string, nonce as string); const email = userInfo.email || userInfo.sub; if (!email) { throw new Error("No email in the response"); } - const authToken = jwtTokenManager.createAuthToken(email); + const authToken = jwtTokenManager.createAuthToken(email, userInfo.access_token); res.writeStatus("200"); this.addCorsHeaders(res); return res.end(JSON.stringify({ authToken })); @@ -63,6 +81,30 @@ export class AuthenticateController extends BaseController { return this.errorToResponse(e, res); } }); + + // eslint-disable-next-line @typescript-eslint/no-misused-promises + this.App.get("/logout-callback", async (res: HttpResponse, req: HttpRequest) => { + res.onAborted(() => { + console.warn("/message request was aborted"); + }); + + const { token } = parse(req.getQuery()); + + try { + const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false); + if (authTokenData.hydraAccessToken == undefined) { + throw Error("Token cannot to be logout on Hydra"); + } + await openIDClient.logoutUser(authTokenData.hydraAccessToken); + } catch (error) { + console.error("openIDCallback => logout-callback", error); + } finally { + res.writeStatus("200"); + this.addCorsHeaders(res); + // eslint-disable-next-line no-unsafe-finally + return res.end(); + } + }); } //Try to login with an admin token @@ -136,4 +178,39 @@ export class AuthenticateController extends BaseController { ); }); } + + profileCallback() { + //eslint-disable-next-line @typescript-eslint/no-misused-promises + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-misused-promises + this.App.get("/profile-callback", async (res: HttpResponse, req: HttpRequest) => { + res.onAborted(() => { + console.warn("/message request was aborted"); + }); + const { userIdentify, token } = parse(req.getQuery()); + try { + //verify connected by token + if (token != undefined) { + try { + const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false); + if (authTokenData.hydraAccessToken == undefined) { + throw Error("Token cannot to be check on Hydra"); + } + await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken); + + //get login profile + res.writeStatus("302"); + res.writeHeader("Location", adminApi.getProfileUrl(authTokenData.hydraAccessToken)); + this.addCorsHeaders(res); + // eslint-disable-next-line no-unsafe-finally + return res.end(); + } catch (error) { + return this.errorToResponse(error, res); + } + } + } catch (error) { + this.errorToResponse(error, res); + } + }); + } } diff --git a/pusher/src/Enum/EnvironmentVariable.ts b/pusher/src/Enum/EnvironmentVariable.ts index ea8f22d8..4a078d90 100644 --- a/pusher/src/Enum/EnvironmentVariable.ts +++ b/pusher/src/Enum/EnvironmentVariable.ts @@ -2,6 +2,7 @@ const SECRET_KEY = process.env.SECRET_KEY || "THECODINGMACHINE_SECRET_KEY"; const ALLOW_ARTILLERY = process.env.ALLOW_ARTILLERY ? process.env.ALLOW_ARTILLERY == "true" : false; const API_URL = process.env.API_URL || ""; const ADMIN_API_URL = process.env.ADMIN_API_URL || ""; +const ADMIN_URL = process.env.ADMIN_URL || ""; const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || "myapitoken"; const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80; const JITSI_URL: string | undefined = process.env.JITSI_URL === "" ? undefined : process.env.JITSI_URL; @@ -19,6 +20,7 @@ export { SECRET_KEY, API_URL, ADMIN_API_URL, + ADMIN_URL, ADMIN_API_TOKEN, ALLOW_ARTILLERY, CPU_OVERHEAT_THRESHOLD, diff --git a/pusher/src/Services/AdminApi.ts b/pusher/src/Services/AdminApi.ts index f33480ca..e53d00ae 100644 --- a/pusher/src/Services/AdminApi.ts +++ b/pusher/src/Services/AdminApi.ts @@ -1,4 +1,4 @@ -import { ADMIN_API_TOKEN, ADMIN_API_URL } from "../Enum/EnvironmentVariable"; +import { ADMIN_API_TOKEN, ADMIN_API_URL, ADMIN_URL } from "../Enum/EnvironmentVariable"; import Axios from "axios"; import { GameRoomPolicyTypes } from "_Model/PusherRoom"; import { CharacterTexture } from "./AdminApi/CharacterTexture"; @@ -141,6 +141,15 @@ class AdminApi { return data.data; }); } + + /*TODO add constant to use profile companny*/ + getProfileUrl(accessToken: string): string { + if (!ADMIN_URL) { + throw new Error("No admin backoffice set!"); + } + + return ADMIN_URL + `/profile?token=${accessToken}`; + } } export const adminApi = new AdminApi(); diff --git a/pusher/src/Services/JWTTokenManager.ts b/pusher/src/Services/JWTTokenManager.ts index 4711ccfd..24393084 100644 --- a/pusher/src/Services/JWTTokenManager.ts +++ b/pusher/src/Services/JWTTokenManager.ts @@ -6,13 +6,13 @@ import { adminApi, AdminBannedData } from "../Services/AdminApi"; export interface AuthTokenData { identifier: string; //will be a email if logged in or an uuid if anonymous + hydraAccessToken?: string; } export const tokenInvalidException = "tokenInvalid"; class JWTTokenManager { - public createAuthToken(identifier: string) { - //TODO fix me 200d when ory authentication will be available - return Jwt.sign({ identifier }, SECRET_KEY, { expiresIn: "200d" }); + public createAuthToken(identifier: string, hydraAccessToken?: string) { + return Jwt.sign({ identifier, hydraAccessToken }, SECRET_KEY, { expiresIn: "30d" }); } public verifyJWTToken(token: string, ignoreExpiration: boolean = false): AuthTokenData { diff --git a/pusher/src/Services/OpenIDClient.ts b/pusher/src/Services/OpenIDClient.ts index 4fda8b5e..b6506a5e 100644 --- a/pusher/src/Services/OpenIDClient.ts +++ b/pusher/src/Services/OpenIDClient.ts @@ -1,4 +1,4 @@ -import { Issuer, Client } from "openid-client"; +import { Issuer, Client, IntrospectionResponse } from "openid-client"; import { OPID_CLIENT_ID, OPID_CLIENT_SECRET, OPID_CLIENT_ISSUER, FRONT_URL } from "../Enum/EnvironmentVariable"; const opidRedirectUri = FRONT_URL + "/jwt"; @@ -31,13 +31,32 @@ class OpenIDClient { }); } - public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string }> { + public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string }> { return this.initClient().then((client) => { return client.callback(opidRedirectUri, { code }, { nonce }).then((tokenSet) => { - return client.userinfo(tokenSet); + return client.userinfo(tokenSet).then((res) => { + return { + ...res, + email: res.email as string, + sub: res.sub, + access_token: tokenSet.access_token as string, + }; + }); }); }); } + + public logoutUser(token: string): Promise { + return this.initClient().then((client) => { + return client.revoke(token); + }); + } + + public checkTokenAuth(token: string): Promise { + return this.initClient().then((client) => { + return client.userinfo(token); + }); + } } export const openIDClient = new OpenIDClient(); From 4f0bb95a384e0ee9fefc88403be2dc07149795e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?gr=C3=A9goire=20parant?= Date: Sun, 5 Sep 2021 18:36:22 +0200 Subject: [PATCH 12/16] Emote silent zone (#1342) * Add an emote when the user is in silent zone * Update silent icon strategy * Update strategy for silent zone - Add svelte store - Show silent zone indication and replace camera This update permit to hide silent zone when user is in Jitsi discussion * Fix css silent zone Signed-off-by: Gregoire Parant --- front/src/Components/CameraControls.svelte | 21 +- front/src/Components/MyCamera.svelte | 15 +- front/src/Phaser/Entity/Character.ts | 254 ++++++++++++--------- front/src/Phaser/Game/EmoteManager.ts | 51 +++-- front/src/Phaser/Game/GameScene.ts | 3 + front/src/Phaser/Player/Player.ts | 41 ++-- front/src/Stores/MediaStore.ts | 5 + front/style/style.scss | 16 ++ 8 files changed, 241 insertions(+), 165 deletions(-) diff --git a/front/src/Components/CameraControls.svelte b/front/src/Components/CameraControls.svelte index d6b31af4..6dc2726a 100644 --- a/front/src/Components/CameraControls.svelte +++ b/front/src/Components/CameraControls.svelte @@ -1,6 +1,6 @@
@@ -55,22 +62,22 @@ Switch to presentation mode {/if}
-
- {#if $requestedScreenSharingState} +
+ {#if $requestedScreenSharingState && !isSilent} Start screen sharing {:else} Stop screen sharing {/if}
-
- {#if $requestedCameraState} +
+ {#if $requestedCameraState && !isSilent} Turn on webcam {:else} Turn off webcam {/if}
-
- {#if $requestedMicrophoneState} +
+ {#if $requestedMicrophoneState && !isSilent} Turn on microphone {:else} Turn off microphone diff --git a/front/src/Components/MyCamera.svelte b/front/src/Components/MyCamera.svelte index 836a9108..67826859 100644 --- a/front/src/Components/MyCamera.svelte +++ b/front/src/Components/MyCamera.svelte @@ -1,6 +1,6 @@
-
+
{#if $localStreamStore.type === "success" && $localStreamStore.stream} {/if}
+
+ Silent zone +
diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 7263a584..3f85d6e5 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -1,29 +1,30 @@ -import {PlayerAnimationDirections, PlayerAnimationTypes} from "../Player/Animation"; -import {SpeechBubble} from "./SpeechBubble"; +import { PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Animation"; +import { SpeechBubble } from "./SpeechBubble"; import Text = Phaser.GameObjects.Text; import Container = Phaser.GameObjects.Container; import Sprite = Phaser.GameObjects.Sprite; -import {TextureError} from "../../Exception/TextureError"; -import {Companion} from "../Companion/Companion"; -import type {GameScene} from "../Game/GameScene"; -import {DEPTH_INGAME_TEXT_INDEX} from "../Game/DepthIndexes"; -import {waScaleManager} from "../Services/WaScaleManager"; +import { TextureError } from "../../Exception/TextureError"; +import { Companion } from "../Companion/Companion"; +import type { GameScene } from "../Game/GameScene"; +import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes"; +import { waScaleManager } from "../Services/WaScaleManager"; import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js"; +import { isSilentStore } from "../../Stores/MediaStore"; -const playerNameY = - 25; +const playerNameY = -25; interface AnimationData { key: string; frameRate: number; repeat: number; frameModel: string; //todo use an enum - frames : number[] + frames: number[]; } const interactiveRadius = 35; export abstract class Character extends Container { - private bubble: SpeechBubble|null = null; + private bubble: SpeechBubble | null = null; private readonly playerName: Text; public PlayerValue: string; public sprites: Map; @@ -32,35 +33,41 @@ export abstract class Character extends Container { private invisible: boolean; public companion?: Companion; private emote: Phaser.GameObjects.Sprite | null = null; - private emoteTween: Phaser.Tweens.Tween|null = null; + private emoteTween: Phaser.Tweens.Tween | null = null; scene: GameScene; - constructor(scene: GameScene, - x: number, - y: number, - texturesPromise: Promise, - name: string, - direction: PlayerAnimationDirections, - moving: boolean, - frame: string | number, - isClickable: boolean, - companion: string|null, - companionTexturePromise?: Promise + constructor( + scene: GameScene, + x: number, + y: number, + texturesPromise: Promise, + name: string, + direction: PlayerAnimationDirections, + moving: boolean, + frame: string | number, + isClickable: boolean, + companion: string | null, + companionTexturePromise?: Promise ) { - super(scene, x, y/*, texture, frame*/); + super(scene, x, y /*, texture, frame*/); this.scene = scene; this.PlayerValue = name; - this.invisible = true + this.invisible = true; this.sprites = new Map(); //textures are inside a Promise in case they need to be lazyloaded before use. texturesPromise.then((textures) => { this.addTextures(textures, frame); - this.invisible = false - }) + this.invisible = false; + }); - this.playerName = new Text(scene, 0, playerNameY, name, {fontFamily: '"Press Start 2P"', fontSize: '8px', strokeThickness: 2, stroke: "gray"}); + 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); @@ -71,18 +78,17 @@ export abstract class Character extends Container { useHandCursor: true, }); - this.on('pointerover',() => { + this.on("pointerover", () => { this.getOutlinePlugin()?.add(this.playerName, { thickness: 2, - outlineColor: 0xffff00 + outlineColor: 0xffff00, }); this.scene.markDirty(); }); - this.on('pointerout',() => { + this.on("pointerout", () => { this.getOutlinePlugin()?.remove(this.playerName); this.scene.markDirty(); - }) - + }); } scene.add.existing(this); @@ -97,38 +103,38 @@ export abstract class Character extends Container { this.playAnimation(direction, moving); - if (typeof companion === 'string') { + if (typeof companion === "string") { this.addCompanion(companion, companionTexturePromise); } } - private getOutlinePlugin(): OutlinePipelinePlugin|undefined { - return this.scene.plugins.get('rexOutlinePipeline') as unknown as OutlinePipelinePlugin|undefined; + private getOutlinePlugin(): OutlinePipelinePlugin | undefined { + return this.scene.plugins.get("rexOutlinePipeline") as unknown as OutlinePipelinePlugin | undefined; } public addCompanion(name: string, texturePromise?: Promise): void { - if (typeof texturePromise !== 'undefined') { + if (typeof texturePromise !== "undefined") { this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise); } } public addTextures(textures: string[], frame?: string | number): void { for (const texture of textures) { - if(this.scene && !this.scene.textures.exists(texture)){ - throw new TextureError('texture not found'); + if (this.scene && !this.scene.textures.exists(texture)) { + throw new TextureError("texture not found"); } const sprite = new Sprite(this.scene, 0, 0, texture, frame); this.add(sprite); - this.getPlayerAnimations(texture).forEach(d => { + this.getPlayerAnimations(texture).forEach((d) => { this.scene.anims.create({ key: d.key, - frames: this.scene.anims.generateFrameNumbers(d.frameModel, {frames: d.frames}), + frames: this.scene.anims.generateFrameNumbers(d.frameModel, { frames: d.frames }), frameRate: d.frameRate, - repeat: d.repeat + repeat: d.repeat, }); - }) + }); // Needed, otherwise, animations are not handled correctly. - if(this.scene) { + if (this.scene) { this.scene.sys.updateList.add(sprite); } this.sprites.set(texture, sprite); @@ -136,68 +142,77 @@ export abstract class Character extends Container { } private getPlayerAnimations(name: string): AnimationData[] { - return [{ - key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`, - frameModel: name, - frames: [0, 1, 2, 1], - frameRate: 10, - repeat: -1 - }, { - key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`, - frameModel: name, - frames: [3, 4, 5, 4], - frameRate: 10, - repeat: -1 - }, { - key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`, - frameModel: name, - frames: [6, 7, 8, 7], - frameRate: 10, - repeat: -1 - }, { - key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`, - frameModel: name, - frames: [9, 10, 11, 10], - frameRate: 10, - repeat: -1 - },{ - key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`, - frameModel: name, - frames: [1], - frameRate: 10, - repeat: 1 - }, { - key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`, - frameModel: name, - frames: [4], - frameRate: 10, - repeat: 1 - }, { - key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`, - frameModel: name, - frames: [7], - frameRate: 10, - repeat: 1 - }, { - key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`, - frameModel: name, - frames: [10], - frameRate: 10, - repeat: 1 - }]; + return [ + { + key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`, + frameModel: name, + frames: [0, 1, 2, 1], + frameRate: 10, + repeat: -1, + }, + { + key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`, + frameModel: name, + frames: [3, 4, 5, 4], + frameRate: 10, + repeat: -1, + }, + { + key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`, + frameModel: name, + frames: [6, 7, 8, 7], + frameRate: 10, + repeat: -1, + }, + { + key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`, + frameModel: name, + frames: [9, 10, 11, 10], + frameRate: 10, + repeat: -1, + }, + { + key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`, + frameModel: name, + frames: [1], + frameRate: 10, + repeat: 1, + }, + { + key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`, + frameModel: name, + frames: [4], + frameRate: 10, + repeat: 1, + }, + { + key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`, + frameModel: name, + frames: [7], + frameRate: 10, + repeat: 1, + }, + { + key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`, + frameModel: name, + frames: [10], + frameRate: 10, + repeat: 1, + }, + ]; } - protected playAnimation(direction : PlayerAnimationDirections, moving: boolean): void { + protected playAnimation(direction: PlayerAnimationDirections, moving: boolean): void { if (this.invisible) return; for (const [texture, sprite] of this.sprites.entries()) { if (!sprite.anims) { - console.error('ANIMS IS NOT DEFINED!!!'); + console.error("ANIMS IS NOT DEFINED!!!"); return; } if (moving && (!sprite.anims.currentAnim || sprite.anims.currentAnim.key !== direction)) { - sprite.play(texture+'-'+direction+'-'+PlayerAnimationTypes.Walk, true); + sprite.play(texture + "-" + direction + "-" + PlayerAnimationTypes.Walk, true); } else if (!moving) { - sprite.anims.play(texture + '-' + direction + '-'+PlayerAnimationTypes.Idle, true); + sprite.anims.play(texture + "-" + direction + "-" + PlayerAnimationTypes.Idle, true); } } } @@ -205,7 +220,7 @@ export abstract class Character extends Container { protected getBody(): Phaser.Physics.Arcade.Body { const body = this.body; if (!(body instanceof Phaser.Physics.Arcade.Body)) { - throw new Error('Container does not have arcade body'); + throw new Error("Container does not have arcade body"); } return body; } @@ -216,16 +231,20 @@ export abstract class Character extends Container { body.setVelocity(x, y); // up or down animations are prioritized over left and right - if (body.velocity.y < 0) { //moving up + if (body.velocity.y < 0) { + //moving up this.lastDirection = PlayerAnimationDirections.Up; this.playAnimation(PlayerAnimationDirections.Up, true); - } else if (body.velocity.y > 0) { //moving down + } else if (body.velocity.y > 0) { + //moving down this.lastDirection = PlayerAnimationDirections.Down; this.playAnimation(PlayerAnimationDirections.Down, true); - } else if (body.velocity.x > 0) { //moving right + } else if (body.velocity.x > 0) { + //moving right this.lastDirection = PlayerAnimationDirections.Right; this.playAnimation(PlayerAnimationDirections.Right, true); - } else if (body.velocity.x < 0) { //moving left + } else if (body.velocity.x < 0) { + //moving left this.lastDirection = PlayerAnimationDirections.Left; this.playAnimation(PlayerAnimationDirections.Left, true); } @@ -237,32 +256,39 @@ export abstract class Character extends Container { } } - stop(){ + stop() { this.getBody().setVelocity(0, 0); this.playAnimation(this.lastDirection, false); } say(text: string) { if (this.bubble) return; - this.bubble = new SpeechBubble(this.scene, this, text) + this.bubble = new SpeechBubble(this.scene, this, text); setTimeout(() => { if (this.bubble !== null) { this.bubble.destroy(); this.bubble = null; } - }, 3000) + }, 3000); } destroy(): void { for (const sprite of this.sprites.values()) { - if(this.scene) { + if (this.scene) { this.scene.sys.updateList.remove(sprite); } } - this.list.forEach(objectContaining => objectContaining.destroy()) + this.list.forEach((objectContaining) => objectContaining.destroy()); super.destroy(); } + isSilent() { + isSilentStore.set(true); + } + noSilent() { + isSilentStore.set(false); + } + playEmote(emoteKey: string) { this.cancelPreviousEmote(); @@ -270,7 +296,7 @@ export abstract class Character extends Container { const emoteY = -30 - scalingFactor * 10; this.playerName.setVisible(false); - this.emote = new Sprite(this.scene, 0, 0, emoteKey); + this.emote = new Sprite(this.scene, 0, 0, emoteKey); this.emote.setAlpha(0); this.emote.setScale(0.1 * scalingFactor); this.add(this.emote); @@ -287,11 +313,11 @@ export abstract class Character extends Container { alpha: 1, y: emoteY, }, - ease: 'Power2', + ease: "Power2", duration: 500, onComplete: () => { this.startPulseTransition(emoteY, scalingFactor); - } + }, }); } @@ -300,7 +326,7 @@ export abstract class Character extends Container { targets: this.emote, props: { y: emoteY * 1.3, - scale: scalingFactor * 1.1 + scale: scalingFactor * 1.1, }, duration: 250, yoyo: true, @@ -308,7 +334,7 @@ export abstract class Character extends Container { completeDelay: 200, onComplete: () => { this.startExitTransition(emoteY); - } + }, }); } @@ -319,11 +345,11 @@ export abstract class Character extends Container { alpha: 0, y: 2 * emoteY, }, - ease: 'Power2', + ease: "Power2", duration: 500, onComplete: () => { this.destroyEmote(); - } + }, }); } @@ -331,7 +357,7 @@ export abstract class Character extends Container { if (!this.emote) return; this.emoteTween?.remove(); - this.destroyEmote() + this.destroyEmote(); } private destroyEmote() { diff --git a/front/src/Phaser/Game/EmoteManager.ts b/front/src/Phaser/Game/EmoteManager.ts index 2e0bbd67..7c6acd5b 100644 --- a/front/src/Phaser/Game/EmoteManager.ts +++ b/front/src/Phaser/Game/EmoteManager.ts @@ -1,37 +1,36 @@ -import type {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures"; -import {emoteEventStream} from "../../Connexion/EmoteEventStream"; -import type {GameScene} from "./GameScene"; -import type {RadialMenuItem} from "../Components/RadialMenu"; +import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures"; +import { emoteEventStream } from "../../Connexion/EmoteEventStream"; +import type { GameScene } from "./GameScene"; +import type { RadialMenuItem } from "../Components/RadialMenu"; import LoaderPlugin = Phaser.Loader.LoaderPlugin; -import type {Subscription} from "rxjs"; - +import type { Subscription } from "rxjs"; interface RegisteredEmote extends BodyResourceDescriptionInterface { name: string; img: string; } -export const emotes: {[key: string]: RegisteredEmote} = { - 'emote-heart': {name: 'emote-heart', img: 'resources/emotes/heart-emote.png'}, - 'emote-clap': {name: 'emote-clap', img: 'resources/emotes/clap-emote.png'}, - 'emote-hand': {name: 'emote-hand', img: 'resources/emotes/hand-emote.png'}, - 'emote-thanks': {name: 'emote-thanks', img: 'resources/emotes/thanks-emote.png'}, - 'emote-thumb-up': {name: 'emote-thumb-up', img: 'resources/emotes/thumb-up-emote.png'}, - 'emote-thumb-down': {name: 'emote-thumb-down', img: 'resources/emotes/thumb-down-emote.png'}, +export const emotes: { [key: string]: RegisteredEmote } = { + "emote-heart": { name: "emote-heart", img: "resources/emotes/heart-emote.png" }, + "emote-clap": { name: "emote-clap", img: "resources/emotes/clap-emote.png" }, + "emote-hand": { name: "emote-hand", img: "resources/emotes/hand-emote.png" }, + "emote-thanks": { name: "emote-thanks", img: "resources/emotes/thanks-emote.png" }, + "emote-thumb-up": { name: "emote-thumb-up", img: "resources/emotes/thumb-up-emote.png" }, + "emote-thumb-down": { name: "emote-thumb-down", img: "resources/emotes/thumb-down-emote.png" }, }; export class EmoteManager { private subscription: Subscription; - + constructor(private scene: GameScene) { this.subscription = emoteEventStream.stream.subscribe((event) => { const actor = this.scene.MapPlayersByKey.get(event.userId); if (actor) { - this.lazyLoadEmoteTexture(event.emoteName).then(emoteKey => { + this.lazyLoadEmoteTexture(event.emoteName).then((emoteKey) => { actor.playEmote(emoteKey); - }) + }); } - }) + }); } createLoadingPromise(loadPlugin: LoaderPlugin, playerResourceDescriptor: BodyResourceDescriptionInterface) { return new Promise((res) => { @@ -39,20 +38,22 @@ export class EmoteManager { return res(playerResourceDescriptor.name); } loadPlugin.image(playerResourceDescriptor.name, playerResourceDescriptor.img); - loadPlugin.once('filecomplete-image-' + playerResourceDescriptor.name, () => res(playerResourceDescriptor.name)); + loadPlugin.once("filecomplete-image-" + playerResourceDescriptor.name, () => + res(playerResourceDescriptor.name) + ); }); } - + lazyLoadEmoteTexture(textureKey: string): Promise { const emoteDescriptor = emotes[textureKey]; if (emoteDescriptor === undefined) { - throw 'Emote not found!'; + throw "Emote not found!"; } const loadPromise = this.createLoadingPromise(this.scene.load, emoteDescriptor); this.scene.load.start(); - return loadPromise + return loadPromise; } - + getMenuImages(): Promise { const promises = []; for (const key in emotes) { @@ -60,14 +61,14 @@ export class EmoteManager { return { image: textureKey, name: textureKey, - } + }; }); promises.push(promise); } return Promise.all(promises); } - + destroy() { this.subscription.unsubscribe(); } -} \ No newline at end of file +} diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 9fbb7ea3..39c87db7 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -93,6 +93,7 @@ import { userIsAdminStore } from "../../Stores/GameStore"; import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore"; import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager"; import { GameMapPropertiesListener } from "./GameMapPropertiesListener"; +import type { RadialMenuItem } from "../Components/RadialMenu"; export interface GameSceneInitInterface { initPosition: PointInterface | null; @@ -853,8 +854,10 @@ export class GameScene extends DirtyScene { this.gameMap.onPropertyChange("silent", (newValue, oldValue) => { if (newValue === undefined || newValue === false || newValue === "") { this.connection?.setSilent(false); + this.CurrentPlayer.noSilent(); } else { this.connection?.setSilent(true); + this.CurrentPlayer.isSilent(); } }); this.gameMap.onPropertyChange("playAudio", (newValue, oldValue, allProps) => { diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index 7ed366f7..c4e68dd3 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -1,9 +1,9 @@ -import {PlayerAnimationDirections} from "./Animation"; -import type {GameScene} from "../Game/GameScene"; -import {UserInputEvent, UserInputManager} from "../UserInput/UserInputManager"; -import {Character} from "../Entity/Character"; -import {userMovingStore} from "../../Stores/GameStore"; -import {RadialMenu, RadialMenuClickEvent, RadialMenuItem} from "../Components/RadialMenu"; +import { PlayerAnimationDirections } from "./Animation"; +import type { GameScene } from "../Game/GameScene"; +import { UserInputEvent, UserInputManager } from "../UserInput/UserInputManager"; +import { Character } from "../Entity/Character"; +import { userMovingStore } from "../../Stores/GameStore"; +import { RadialMenu, RadialMenuClickEvent, RadialMenuItem } from "../Components/RadialMenu"; export const hasMovedEventName = "hasMoved"; export const requestEmoteEventName = "requestEmote"; @@ -11,7 +11,7 @@ export const requestEmoteEventName = "requestEmote"; export class Player extends Character { private previousDirection: string = PlayerAnimationDirections.Down; private wasMoving: boolean = false; - private emoteMenu: RadialMenu|null = null; + private emoteMenu: RadialMenu | null = null; private updateListener: () => void; constructor( @@ -23,7 +23,7 @@ export class Player extends Character { direction: PlayerAnimationDirections, moving: boolean, private userInputManager: UserInputManager, - companion: string|null, + companion: string | null, companionTexturePromise?: Promise ) { super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise); @@ -37,7 +37,7 @@ export class Player extends Character { this.emoteMenu.y = this.y; } }; - this.scene.events.addListener('postupdate', this.updateListener); + this.scene.events.addListener("postupdate", this.updateListener); } moveUser(delta: number): void { @@ -73,14 +73,14 @@ export class Player extends Character { if (x !== 0 || y !== 0) { this.move(x, y); - this.emit(hasMovedEventName, {moving, direction, x: this.x, y: this.y}); + this.emit(hasMovedEventName, { moving, direction, x: this.x, y: this.y }); } else if (this.wasMoving && moving) { // slow joystick movement this.move(0, 0); - this.emit(hasMovedEventName, {moving, direction: this.previousDirection, x: this.x, y: this.y}); + this.emit(hasMovedEventName, { moving, direction: this.previousDirection, x: this.x, y: this.y }); } else if (this.wasMoving && !moving) { this.stop(); - this.emit(hasMovedEventName, {moving, direction: this.previousDirection, x: this.x, y: this.y}); + this.emit(hasMovedEventName, { moving, direction: this.previousDirection, x: this.x, y: this.y }); } if (direction !== null) { @@ -94,17 +94,17 @@ export class Player extends Character { return this.wasMoving; } - openOrCloseEmoteMenu(emotes:RadialMenuItem[]) { - if(this.emoteMenu) { + openOrCloseEmoteMenu(emotes: RadialMenuItem[]) { + if (this.emoteMenu) { this.closeEmoteMenu(); } else { this.openEmoteMenu(emotes); } } - openEmoteMenu(emotes:RadialMenuItem[]): void { + openEmoteMenu(emotes: RadialMenuItem[]): void { this.cancelPreviousEmote(); - this.emoteMenu = new RadialMenu(this.scene, this.x, this.y, emotes) + this.emoteMenu = new RadialMenu(this.scene, this.x, this.y, emotes); this.emoteMenu.on(RadialMenuClickEvent, (item: RadialMenuItem) => { this.closeEmoteMenu(); this.emit(requestEmoteEventName, item.name); @@ -112,6 +112,13 @@ export class Player extends Character { }); } + isSilent() { + super.isSilent(); + } + noSilent() { + super.noSilent(); + } + closeEmoteMenu(): void { if (!this.emoteMenu) return; this.emoteMenu.destroy(); @@ -119,7 +126,7 @@ export class Player extends Character { } destroy() { - this.scene.events.removeListener('postupdate', this.updateListener); + this.scene.events.removeListener("postupdate", this.updateListener); super.destroy(); } } diff --git a/front/src/Stores/MediaStore.ts b/front/src/Stores/MediaStore.ts index 48832773..0ab40a79 100644 --- a/front/src/Stores/MediaStore.ts +++ b/front/src/Stores/MediaStore.ts @@ -569,3 +569,8 @@ localStreamStore.subscribe((streamResult) => { * A store containing the real active media is mobile */ export const obtainedMediaConstraintIsMobileStore = writable(false); + +/** + * A store containing if user is silent, so if he is in silent zone. This permit to show et hide camera of user + */ +export const isSilentStore = writable(false); diff --git a/front/style/style.scss b/front/style/style.scss index ecfc92fe..31eddfc8 100644 --- a/front/style/style.scss +++ b/front/style/style.scss @@ -1083,3 +1083,19 @@ div.action.danger p.action-body{ } } } + +div.is-silent { + position: absolute; + bottom: 40px; + border-radius: 15px 15px 15px 15px; + max-height: 20%; + transition: right 350ms; + right: -20vw; + background-color: black; + font-size: 20px; + color: white; + padding: 30px 20px; +} +div.is-silent.hide { + right: 15px; +} From f2ca02174002b7ebd81c85dccbdb3583b2775c60 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Sun, 5 Sep 2021 19:36:57 +0200 Subject: [PATCH 13/16] Hotfix media constraint error - Create error to manage displayed warning when we try to access on media with no constraint video and audio - Fix disabled microphone if we try to active and we don't have right or there is an error. Signed-off-by: Gregoire Parant --- .../Errors/MediaStreamConstraintsError.ts | 10 +++++++++ front/src/Stores/MediaStore.ts | 17 ++++++++++---- front/src/WebRtc/MediaManager.ts | 22 ++++++++++--------- 3 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 front/src/Stores/Errors/MediaStreamConstraintsError.ts diff --git a/front/src/Stores/Errors/MediaStreamConstraintsError.ts b/front/src/Stores/Errors/MediaStreamConstraintsError.ts new file mode 100644 index 00000000..e7057f61 --- /dev/null +++ b/front/src/Stores/Errors/MediaStreamConstraintsError.ts @@ -0,0 +1,10 @@ +export class MediaStreamConstraintsError extends Error { + static NAME = "MediaStreamConstraintsError"; + + constructor() { + super( + "Unable to access your camera or microphone. Your browser is too old. Please consider upgrading your browser or try using a recent version of Chrome." + ); + this.name = MediaStreamConstraintsError.NAME; + } +} diff --git a/front/src/Stores/MediaStore.ts b/front/src/Stores/MediaStore.ts index 0ab40a79..b19a9356 100644 --- a/front/src/Stores/MediaStore.ts +++ b/front/src/Stores/MediaStore.ts @@ -9,6 +9,7 @@ import { WebviewOnOldIOS } from "./Errors/WebviewOnOldIOS"; import { gameOverlayVisibilityStore } from "./GameOverlayStoreVisibility"; import { peerStore } from "./PeerStore"; import { privacyShutdownStore } from "./PrivacyShutdownStore"; +import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError"; /** * A store that contains the camera state requested by the user (on or off). @@ -251,8 +252,6 @@ export const mediaStreamConstraintsStore = derived( let currentAudioConstraint: boolean | MediaTrackConstraints = $audioConstraintStore; if ($enableCameraSceneVisibilityStore) { - console.log("currentVideoConstraint", currentVideoConstraint); - console.log("currentAudioConstraint", currentAudioConstraint); set({ video: currentVideoConstraint, audio: currentAudioConstraint, @@ -421,7 +420,7 @@ export const localStreamStore = derived, LocalS }); return; } catch (e) { - if (constraints.video !== false) { + if (constraints.video !== false || constraints.audio !== false) { console.info( "Error. Unable to get microphone and/or camera access. Trying audio only.", $mediaStreamConstraintsStore, @@ -433,7 +432,17 @@ export const localStreamStore = derived, LocalS error: e, }); // Let's try without video constraints - requestedCameraState.disableWebcam(); + if (constraints.video !== false) { + requestedCameraState.disableWebcam(); + } + if (constraints.audio !== false) { + requestedMicrophoneState.disableMicrophone(); + } + } else if (!constraints.video && !constraints.audio) { + set({ + type: "error", + error: new MediaStreamConstraintsError(), + }); } else { console.info( "Error. Unable to get microphone and/or camera access.", diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts index f2a54b9e..7b32699b 100644 --- a/front/src/WebRtc/MediaManager.ts +++ b/front/src/WebRtc/MediaManager.ts @@ -12,6 +12,7 @@ import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore"; import { get } from "svelte/store"; import { localUserStore } from "../Connexion/LocalUserStore"; +import { MediaStreamConstraintsError } from "../Stores/Errors/MediaStreamConstraintsError"; export class MediaManager { startScreenSharingCallBacks: Set = new Set(); @@ -24,16 +25,17 @@ export class MediaManager { constructor() { localStreamStore.subscribe((result) => { if (result.type === "error") { - console.error(result.error); - layoutManagerActionStore.addAction({ - uuid: "cameraAccessDenied", - type: "warning", - message: "Camera access denied. Click here and check your browser permissions.", - callback: () => { - helpCameraSettingsVisibleStore.set(true); - }, - userInputManager: this.userInputManager, - }); + if (result.error.name !== MediaStreamConstraintsError.NAME) { + layoutManagerActionStore.addAction({ + uuid: "cameraAccessDenied", + type: "warning", + message: "Camera access denied. Click here and check your browser permissions.", + callback: () => { + helpCameraSettingsVisibleStore.set(true); + }, + userInputManager: this.userInputManager, + }); + } //remove it after 10 sec setTimeout(() => { layoutManagerActionStore.removeAction("cameraAccessDenied"); From 7743bda3ebb52c04caefe3b40465613550ef03f3 Mon Sep 17 00:00:00 2001 From: kharhamel Date: Mon, 6 Sep 2021 14:27:01 +0200 Subject: [PATCH 14/16] added yarn run pretty to the front ci --- .github/workflows/continuous_integration.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml index ca2a01cb..a90d9397 100644 --- a/.github/workflows/continuous_integration.yml +++ b/.github/workflows/continuous_integration.yml @@ -61,6 +61,10 @@ jobs: run: yarn run lint working-directory: "front" + - name: "Pretty" + run: yarn run pretty + working-directory: "front" + - name: "Jasmine" run: yarn test working-directory: "front" From 4160235b92c2cb330a59920e769db9219560c3b9 Mon Sep 17 00:00:00 2001 From: kharhamel Date: Mon, 6 Sep 2021 14:27:54 +0200 Subject: [PATCH 15/16] ran pretty on the front --- front/src/Api/Events/ButtonClickedEvent.ts | 7 +- front/src/Api/Events/ChatEvent.ts | 7 +- front/src/Api/Events/ClosePopupEvent.ts | 7 +- front/src/Api/Events/EnterLeaveEvent.ts | 7 +- front/src/Api/Events/GoToPageEvent.ts | 9 +- front/src/Api/Events/LoadSoundEvent.ts | 7 +- front/src/Api/Events/OpenPopupEvent.ts | 18 +- front/src/Api/Events/OpenTabEvent.ts | 9 +- front/src/Api/Events/PlaySoundEvent.ts | 19 +- front/src/Api/Events/StopSoundEvent.ts | 7 +- front/src/Api/Events/UserInputChatEvent.ts | 7 +- front/src/Api/iframe/Ui/ButtonDescriptor.ts | 8 +- front/src/Api/iframe/Ui/Popup.ts | 15 +- front/src/Api/iframe/registeredCallbacks.ts | 16 +- front/src/Connexion/AdminMessagesService.ts | 20 +- front/src/Connexion/EmoteEventStream.ts | 16 +- front/src/Connexion/WorldFullMessageStream.ts | 10 +- front/src/Exception/TextureError.ts | 2 +- front/src/Logger/MessageUI.ts | 16 +- front/src/Network/ProtobufClientUtils.ts | 13 +- front/src/Phaser/Companion/Companion.ts | 61 +- .../src/Phaser/Companion/CompanionTextures.ts | 8 +- .../CompanionTexturesLoadingManager.ts | 14 +- front/src/Phaser/Components/ChatModeIcon.ts | 4 +- front/src/Phaser/Components/ClickButton.ts | 7 +- .../Phaser/Components/PresentationModeIcon.ts | 6 +- front/src/Phaser/Components/RadialMenu.ts | 44 +- front/src/Phaser/Components/SoundMeter.ts | 24 +- front/src/Phaser/Components/TextField.ts | 5 +- .../src/Phaser/Entity/CustomizedCharacter.ts | 2 +- front/src/Phaser/Entity/PlayerTextures.ts | 716 ++++++++++-------- front/src/Phaser/Entity/SpeechBubble.ts | 19 +- front/src/Phaser/Entity/Sprite.ts | 3 +- front/src/Phaser/Game/SoundManager.ts | 24 +- front/src/Phaser/Items/ActionableItem.ts | 24 +- front/src/Phaser/Items/Computer/computer.ts | 87 ++- .../src/Phaser/Items/ItemFactoryInterface.ts | 6 +- .../Phaser/Login/AbstractCharacterScene.ts | 23 +- front/src/Phaser/Login/ResizableScene.ts | 15 +- .../Login/SelectCharacterMobileScene.ts | 33 +- front/src/Phaser/Player/Animation.ts | 15 +- front/src/Phaser/Reconnecting/WAError.ts | 6 +- front/src/Phaser/Services/HdpiManager.ts | 28 +- front/src/Phaser/Services/WaScaleManager.ts | 31 +- front/src/Phaser/UserInput/PinchManager.ts | 14 +- .../ConsoleGlobalMessageManagerStore.ts | 2 +- front/src/Stores/ErrorStore.ts | 6 +- front/src/Stores/Errors/BrowserTooOldError.ts | 6 +- front/src/Stores/Errors/WebviewOnOldIOS.ts | 6 +- front/src/Stores/SelectCharacterStore.ts | 2 +- front/src/Stores/SoundPlayingStore.ts | 6 +- front/src/Touch/TouchScreenManager.ts | 10 +- front/src/WebRtc/DeviceUtils.ts | 15 +- front/src/rex-plugins.d.ts | 10 +- 54 files changed, 808 insertions(+), 694 deletions(-) diff --git a/front/src/Api/Events/ButtonClickedEvent.ts b/front/src/Api/Events/ButtonClickedEvent.ts index de807037..26a8aceb 100644 --- a/front/src/Api/Events/ButtonClickedEvent.ts +++ b/front/src/Api/Events/ButtonClickedEvent.ts @@ -1,10 +1,11 @@ import * as tg from "generic-type-guard"; -export const isButtonClickedEvent = - new tg.IsInterface().withProperties({ +export const isButtonClickedEvent = new tg.IsInterface() + .withProperties({ popupId: tg.isNumber, buttonId: tg.isNumber, - }).get(); + }) + .get(); /** * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. */ diff --git a/front/src/Api/Events/ChatEvent.ts b/front/src/Api/Events/ChatEvent.ts index 5729a120..984859e8 100644 --- a/front/src/Api/Events/ChatEvent.ts +++ b/front/src/Api/Events/ChatEvent.ts @@ -1,10 +1,11 @@ import * as tg from "generic-type-guard"; -export const isChatEvent = - new tg.IsInterface().withProperties({ +export const isChatEvent = new tg.IsInterface() + .withProperties({ message: tg.isString, author: tg.isString, - }).get(); + }) + .get(); /** * A message sent from the iFrame to the game to add a message in the chat. */ diff --git a/front/src/Api/Events/ClosePopupEvent.ts b/front/src/Api/Events/ClosePopupEvent.ts index 83b09c96..f604a404 100644 --- a/front/src/Api/Events/ClosePopupEvent.ts +++ b/front/src/Api/Events/ClosePopupEvent.ts @@ -1,9 +1,10 @@ import * as tg from "generic-type-guard"; -export const isClosePopupEvent = - new tg.IsInterface().withProperties({ +export const isClosePopupEvent = new tg.IsInterface() + .withProperties({ popupId: tg.isNumber, - }).get(); + }) + .get(); /** * A message sent from the iFrame to the game to add a message in the chat. diff --git a/front/src/Api/Events/EnterLeaveEvent.ts b/front/src/Api/Events/EnterLeaveEvent.ts index 0c0cb4ff..ca68136e 100644 --- a/front/src/Api/Events/EnterLeaveEvent.ts +++ b/front/src/Api/Events/EnterLeaveEvent.ts @@ -1,9 +1,10 @@ import * as tg from "generic-type-guard"; -export const isEnterLeaveEvent = - new tg.IsInterface().withProperties({ +export const isEnterLeaveEvent = new tg.IsInterface() + .withProperties({ name: tg.isString, - }).get(); + }) + .get(); /** * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. */ diff --git a/front/src/Api/Events/GoToPageEvent.ts b/front/src/Api/Events/GoToPageEvent.ts index cb258b03..d8d6467d 100644 --- a/front/src/Api/Events/GoToPageEvent.ts +++ b/front/src/Api/Events/GoToPageEvent.ts @@ -1,11 +1,10 @@ import * as tg from "generic-type-guard"; - - -export const isGoToPageEvent = - new tg.IsInterface().withProperties({ +export const isGoToPageEvent = new tg.IsInterface() + .withProperties({ url: tg.isString, - }).get(); + }) + .get(); /** * A message sent from the iFrame to the game to add a message in the chat. diff --git a/front/src/Api/Events/LoadSoundEvent.ts b/front/src/Api/Events/LoadSoundEvent.ts index 19b4b8e1..f48f202f 100644 --- a/front/src/Api/Events/LoadSoundEvent.ts +++ b/front/src/Api/Events/LoadSoundEvent.ts @@ -1,9 +1,10 @@ import * as tg from "generic-type-guard"; -export const isLoadSoundEvent = - new tg.IsInterface().withProperties({ +export const isLoadSoundEvent = new tg.IsInterface() + .withProperties({ url: tg.isString, - }).get(); + }) + .get(); /** * A message sent from the iFrame to the game to add a message in the chat. diff --git a/front/src/Api/Events/OpenPopupEvent.ts b/front/src/Api/Events/OpenPopupEvent.ts index 094ba555..c1070bbe 100644 --- a/front/src/Api/Events/OpenPopupEvent.ts +++ b/front/src/Api/Events/OpenPopupEvent.ts @@ -1,18 +1,20 @@ import * as tg from "generic-type-guard"; -const isButtonDescriptor = - new tg.IsInterface().withProperties({ +const isButtonDescriptor = new tg.IsInterface() + .withProperties({ label: tg.isString, - className: tg.isOptional(tg.isString) - }).get(); + className: tg.isOptional(tg.isString), + }) + .get(); -export const isOpenPopupEvent = - new tg.IsInterface().withProperties({ +export const isOpenPopupEvent = new tg.IsInterface() + .withProperties({ popupId: tg.isNumber, targetObject: tg.isString, message: tg.isString, - buttons: tg.isArray(isButtonDescriptor) - }).get(); + buttons: tg.isArray(isButtonDescriptor), + }) + .get(); /** * A message sent from the iFrame to the game to add a message in the chat. diff --git a/front/src/Api/Events/OpenTabEvent.ts b/front/src/Api/Events/OpenTabEvent.ts index e510f8b6..6fe6ec21 100644 --- a/front/src/Api/Events/OpenTabEvent.ts +++ b/front/src/Api/Events/OpenTabEvent.ts @@ -1,11 +1,10 @@ import * as tg from "generic-type-guard"; - - -export const isOpenTabEvent = - new tg.IsInterface().withProperties({ +export const isOpenTabEvent = new tg.IsInterface() + .withProperties({ url: tg.isString, - }).get(); + }) + .get(); /** * A message sent from the iFrame to the game to add a message in the chat. diff --git a/front/src/Api/Events/PlaySoundEvent.ts b/front/src/Api/Events/PlaySoundEvent.ts index 33ca1ff4..6fe56746 100644 --- a/front/src/Api/Events/PlaySoundEvent.ts +++ b/front/src/Api/Events/PlaySoundEvent.ts @@ -1,22 +1,23 @@ import * as tg from "generic-type-guard"; - -const isSoundConfig = - new tg.IsInterface().withProperties({ +const isSoundConfig = new tg.IsInterface() + .withProperties({ volume: tg.isOptional(tg.isNumber), loop: tg.isOptional(tg.isBoolean), mute: tg.isOptional(tg.isBoolean), rate: tg.isOptional(tg.isNumber), detune: tg.isOptional(tg.isNumber), seek: tg.isOptional(tg.isNumber), - delay: tg.isOptional(tg.isNumber) - }).get(); + delay: tg.isOptional(tg.isNumber), + }) + .get(); -export const isPlaySoundEvent = - new tg.IsInterface().withProperties({ +export const isPlaySoundEvent = new tg.IsInterface() + .withProperties({ url: tg.isString, - config : tg.isOptional(isSoundConfig), - }).get(); + config: tg.isOptional(isSoundConfig), + }) + .get(); /** * A message sent from the iFrame to the game to add a message in the chat. diff --git a/front/src/Api/Events/StopSoundEvent.ts b/front/src/Api/Events/StopSoundEvent.ts index 6d12516d..cdfe43ca 100644 --- a/front/src/Api/Events/StopSoundEvent.ts +++ b/front/src/Api/Events/StopSoundEvent.ts @@ -1,9 +1,10 @@ import * as tg from "generic-type-guard"; -export const isStopSoundEvent = - new tg.IsInterface().withProperties({ +export const isStopSoundEvent = new tg.IsInterface() + .withProperties({ url: tg.isString, - }).get(); + }) + .get(); /** * A message sent from the iFrame to the game to add a message in the chat. diff --git a/front/src/Api/Events/UserInputChatEvent.ts b/front/src/Api/Events/UserInputChatEvent.ts index de21ff6e..9de41327 100644 --- a/front/src/Api/Events/UserInputChatEvent.ts +++ b/front/src/Api/Events/UserInputChatEvent.ts @@ -1,9 +1,10 @@ import * as tg from "generic-type-guard"; -export const isUserInputChatEvent = - new tg.IsInterface().withProperties({ +export const isUserInputChatEvent = new tg.IsInterface() + .withProperties({ message: tg.isString, - }).get(); + }) + .get(); /** * A message sent from the game to the iFrame when a user types a message in the chat. */ diff --git a/front/src/Api/iframe/Ui/ButtonDescriptor.ts b/front/src/Api/iframe/Ui/ButtonDescriptor.ts index 119daf5c..9cf1688a 100644 --- a/front/src/Api/iframe/Ui/ButtonDescriptor.ts +++ b/front/src/Api/iframe/Ui/ButtonDescriptor.ts @@ -1,4 +1,4 @@ -import type {Popup} from "./Popup"; +import type { Popup } from "./Popup"; export type ButtonClickedCallback = (popup: Popup) => void; @@ -6,13 +6,13 @@ export interface ButtonDescriptor { /** * The label of the button */ - label: string, + label: string; /** * The type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled" */ - className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled", + className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled"; /** * Callback called if the button is pressed */ - callback: ButtonClickedCallback, + callback: ButtonClickedCallback; } diff --git a/front/src/Api/iframe/Ui/Popup.ts b/front/src/Api/iframe/Ui/Popup.ts index 37dea922..085fdc2c 100644 --- a/front/src/Api/iframe/Ui/Popup.ts +++ b/front/src/Api/iframe/Ui/Popup.ts @@ -1,19 +1,18 @@ -import {sendToWorkadventure} from "../IframeApiContribution"; -import type {ClosePopupEvent} from "../../Events/ClosePopupEvent"; +import { sendToWorkadventure } from "../IframeApiContribution"; +import type { ClosePopupEvent } from "../../Events/ClosePopupEvent"; export class Popup { - constructor(private id: number) { - } + constructor(private id: number) {} /** * Closes the popup */ public close(): void { sendToWorkadventure({ - 'type': 'closePopup', - 'data': { - 'popupId': this.id, - } as ClosePopupEvent + type: "closePopup", + data: { + popupId: this.id, + } as ClosePopupEvent, }); } } diff --git a/front/src/Api/iframe/registeredCallbacks.ts b/front/src/Api/iframe/registeredCallbacks.ts index 5d6f784d..3b6ee6c7 100644 --- a/front/src/Api/iframe/registeredCallbacks.ts +++ b/front/src/Api/iframe/registeredCallbacks.ts @@ -1,16 +1,18 @@ -import type {IframeResponseEventMap} from "../../Api/Events/IframeEvent"; -import type {IframeCallback} from "../../Api/iframe/IframeApiContribution"; -import type {IframeCallbackContribution} from "../../Api/iframe/IframeApiContribution"; +import type { IframeResponseEventMap } from "../../Api/Events/IframeEvent"; +import type { IframeCallback } from "../../Api/iframe/IframeApiContribution"; +import type { IframeCallbackContribution } from "../../Api/iframe/IframeApiContribution"; -export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: IframeCallback } = {} +export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: IframeCallback } = {}; -export function apiCallback(callbackData: IframeCallbackContribution): IframeCallbackContribution { +export function apiCallback( + callbackData: IframeCallbackContribution +): IframeCallbackContribution { const iframeCallback = { typeChecker: callbackData.typeChecker, - callback: callbackData.callback + callback: callbackData.callback, } as IframeCallback; const newCallback = { [callbackData.type]: iframeCallback }; - Object.assign(registeredCallbacks, newCallback) + Object.assign(registeredCallbacks, newCallback); return callbackData as unknown as IframeCallbackContribution; } diff --git a/front/src/Connexion/AdminMessagesService.ts b/front/src/Connexion/AdminMessagesService.ts index 0cf7f95f..0b217760 100644 --- a/front/src/Connexion/AdminMessagesService.ts +++ b/front/src/Connexion/AdminMessagesService.ts @@ -1,15 +1,15 @@ -import {Subject} from "rxjs"; -import type {BanUserMessage, SendUserMessage} from "../Messages/generated/messages_pb"; +import { Subject } from "rxjs"; +import type { BanUserMessage, SendUserMessage } from "../Messages/generated/messages_pb"; export enum AdminMessageEventTypes { - admin = 'message', - audio = 'audio', - ban = 'ban', - banned = 'banned', + admin = "message", + audio = "audio", + ban = "ban", + banned = "banned", } interface AdminMessageEvent { - type: AdminMessageEventTypes, + type: AdminMessageEventTypes; text: string; //todo add optional properties for other event types } @@ -21,14 +21,14 @@ class AdminMessagesService { public messageStream = this._messageStream.asObservable(); constructor() { - this.messageStream.subscribe((event) => console.log('message', event)) + this.messageStream.subscribe((event) => console.log("message", event)); } - onSendusermessage(message: SendUserMessage|BanUserMessage) { + onSendusermessage(message: SendUserMessage | BanUserMessage) { this._messageStream.next({ type: message.getType() as unknown as AdminMessageEventTypes, text: message.getMessage(), - }) + }); } } diff --git a/front/src/Connexion/EmoteEventStream.ts b/front/src/Connexion/EmoteEventStream.ts index 9a639697..e8d01095 100644 --- a/front/src/Connexion/EmoteEventStream.ts +++ b/front/src/Connexion/EmoteEventStream.ts @@ -1,19 +1,17 @@ -import {Subject} from "rxjs"; +import { Subject } from "rxjs"; interface EmoteEvent { - userId: number, - emoteName: string, + userId: number; + emoteName: string; } class EmoteEventStream { - - private _stream:Subject = new Subject(); + private _stream: Subject = new Subject(); public stream = this._stream.asObservable(); - - fire(userId: number, emoteName:string) { - this._stream.next({userId, emoteName}); + fire(userId: number, emoteName: string) { + this._stream.next({ userId, emoteName }); } } -export const emoteEventStream = new EmoteEventStream(); \ No newline at end of file +export const emoteEventStream = new EmoteEventStream(); diff --git a/front/src/Connexion/WorldFullMessageStream.ts b/front/src/Connexion/WorldFullMessageStream.ts index c9f65d84..01ce6f20 100644 --- a/front/src/Connexion/WorldFullMessageStream.ts +++ b/front/src/Connexion/WorldFullMessageStream.ts @@ -1,14 +1,12 @@ -import {Subject} from "rxjs"; +import { Subject } from "rxjs"; class WorldFullMessageStream { - - private _stream:Subject = new Subject(); + private _stream: Subject = new Subject(); public stream = this._stream.asObservable(); - - onMessage(message? :string) { + onMessage(message?: string) { this._stream.next(message); } } -export const worldFullMessageStream = new WorldFullMessageStream(); \ No newline at end of file +export const worldFullMessageStream = new WorldFullMessageStream(); diff --git a/front/src/Exception/TextureError.ts b/front/src/Exception/TextureError.ts index 39a339f6..4e7e2e80 100644 --- a/front/src/Exception/TextureError.ts +++ b/front/src/Exception/TextureError.ts @@ -1 +1 @@ -export class TextureError extends Error{} \ No newline at end of file +export class TextureError extends Error {} diff --git a/front/src/Logger/MessageUI.ts b/front/src/Logger/MessageUI.ts index 2a581091..d10460bd 100644 --- a/front/src/Logger/MessageUI.ts +++ b/front/src/Logger/MessageUI.ts @@ -1,19 +1,21 @@ export class MessageUI { - - static warningMessage(text: string){ + static warningMessage(text: string) { this.removeMessage(); const body = document.getElementById("body"); - body?.insertAdjacentHTML('afterbegin', ` + body?.insertAdjacentHTML( + "afterbegin", + `
${text}
- `); + ` + ); } - static removeMessage(id : string|null = null) { - if(!id){ + static removeMessage(id: string | null = null) { + if (!id) { const messages = document.getElementsByClassName("message-info"); - for (let i = 0; i < messages.length; i++){ + for (let i = 0; i < messages.length; i++) { messages.item(i)?.remove(); } return; diff --git a/front/src/Network/ProtobufClientUtils.ts b/front/src/Network/ProtobufClientUtils.ts index 3d2d5c32..9ba0f40b 100644 --- a/front/src/Network/ProtobufClientUtils.ts +++ b/front/src/Network/ProtobufClientUtils.ts @@ -1,23 +1,22 @@ -import {PositionMessage} from "../Messages/generated/messages_pb"; +import { PositionMessage } from "../Messages/generated/messages_pb"; import Direction = PositionMessage.Direction; -import type {PointInterface} from "../Connexion/ConnexionModels"; +import type { PointInterface } from "../Connexion/ConnexionModels"; export class ProtobufClientUtils { - public static toPointInterface(position: PositionMessage): PointInterface { let direction: string; switch (position.getDirection()) { case Direction.UP: - direction = 'up'; + direction = "up"; break; case Direction.DOWN: - direction = 'down'; + direction = "down"; break; case Direction.LEFT: - direction = 'left'; + direction = "left"; break; case Direction.RIGHT: - direction = 'right'; + direction = "right"; break; default: throw new Error("Unexpected direction"); diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index 1c43f452..75eb844f 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -16,7 +16,7 @@ export class Companion extends Container { private delta: number; private invisible: boolean; private updateListener: Function; - private target: { x: number, y: number, direction: PlayerAnimationDirections }; + private target: { x: number; y: number; direction: PlayerAnimationDirections }; private companionName: string; private direction: PlayerAnimationDirections; @@ -36,10 +36,10 @@ export class Companion extends Container { this.companionName = name; - texturePromise.then(resource => { + texturePromise.then((resource) => { this.addResource(resource); this.invisible = false; - }) + }); this.scene.physics.world.enableBody(this); @@ -52,7 +52,7 @@ export class Companion extends Container { this.setDepth(-1); this.updateListener = this.step.bind(this); - this.scene.events.addListener('update', this.updateListener); + this.scene.events.addListener("update", this.updateListener); this.scene.add.existing(this); } @@ -62,7 +62,7 @@ export class Companion extends Container { } public step(time: number, delta: number) { - if (typeof this.target === 'undefined') return; + if (typeof this.target === "undefined") return; this.delta += delta; if (this.delta < 128) { @@ -87,7 +87,10 @@ export class Companion extends Container { const yDir = yDist / Math.max(Math.abs(yDist), 1); const speed = 256; - this.getBody().setVelocity(Math.min(Math.abs(xDist * 2.5), speed) * xDir, Math.min(Math.abs(yDist * 2.5), speed) * yDir); + this.getBody().setVelocity( + Math.min(Math.abs(xDist * 2.5), speed) * xDir, + Math.min(Math.abs(yDist * 2.5), speed) * yDir + ); if (Math.abs(xDist) > Math.abs(yDist)) { if (xDist < 0) { @@ -116,8 +119,8 @@ export class Companion extends Container { y, direction, moving: animationType === PlayerAnimationTypes.Walk, - name: companionName - } + name: companionName, + }; } private playAnimation(direction: PlayerAnimationDirections, type: PlayerAnimationTypes): void { @@ -133,7 +136,7 @@ export class Companion extends Container { this.add(sprite); - this.getAnimations(resource).forEach(animation => { + this.getAnimations(resource).forEach((animation) => { this.scene.anims.create(animation); }); @@ -145,60 +148,60 @@ export class Companion extends Container { return [ { key: `${resource}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`, - frames: this.scene.anims.generateFrameNumbers(resource, {frames: [1]}), + frames: this.scene.anims.generateFrameNumbers(resource, { frames: [1] }), frameRate: 10, - repeat: 1 + repeat: 1, }, { key: `${resource}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`, - frames: this.scene.anims.generateFrameNumbers(resource, {frames: [4]}), + frames: this.scene.anims.generateFrameNumbers(resource, { frames: [4] }), frameRate: 10, - repeat: 1 + repeat: 1, }, { key: `${resource}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`, - frames: this.scene.anims.generateFrameNumbers(resource, {frames: [7]}), + frames: this.scene.anims.generateFrameNumbers(resource, { frames: [7] }), frameRate: 10, - repeat: 1 + repeat: 1, }, { key: `${resource}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`, - frames: this.scene.anims.generateFrameNumbers(resource, {frames: [10]}), + frames: this.scene.anims.generateFrameNumbers(resource, { frames: [10] }), frameRate: 10, - repeat: 1 + repeat: 1, }, { key: `${resource}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`, - frames: this.scene.anims.generateFrameNumbers(resource, {frames: [0, 1, 2]}), + frames: this.scene.anims.generateFrameNumbers(resource, { frames: [0, 1, 2] }), frameRate: 15, - repeat: -1 + repeat: -1, }, { key: `${resource}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`, - frames: this.scene.anims.generateFrameNumbers(resource, {frames: [3, 4, 5]}), + frames: this.scene.anims.generateFrameNumbers(resource, { frames: [3, 4, 5] }), frameRate: 15, - repeat: -1 + repeat: -1, }, { key: `${resource}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`, - frames: this.scene.anims.generateFrameNumbers(resource, {frames: [6, 7, 8]}), + frames: this.scene.anims.generateFrameNumbers(resource, { frames: [6, 7, 8] }), frameRate: 15, - repeat: -1 + repeat: -1, }, { key: `${resource}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`, - frames: this.scene.anims.generateFrameNumbers(resource, {frames: [9, 10, 11]}), + frames: this.scene.anims.generateFrameNumbers(resource, { frames: [9, 10, 11] }), frameRate: 15, - repeat: -1 - } - ] + repeat: -1, + }, + ]; } private getBody(): Phaser.Physics.Arcade.Body { const body = this.body; if (!(body instanceof Phaser.Physics.Arcade.Body)) { - throw new Error('Container does not have arcade body'); + throw new Error("Container does not have arcade body"); } return body; @@ -212,7 +215,7 @@ export class Companion extends Container { } if (this.scene) { - this.scene.events.removeListener('update', this.updateListener); + this.scene.events.removeListener("update", this.updateListener); } super.destroy(); diff --git a/front/src/Phaser/Companion/CompanionTextures.ts b/front/src/Phaser/Companion/CompanionTextures.ts index 84eaf38f..279b027d 100644 --- a/front/src/Phaser/Companion/CompanionTextures.ts +++ b/front/src/Phaser/Companion/CompanionTextures.ts @@ -1,7 +1,7 @@ export interface CompanionResourceDescriptionInterface { - name: string, - img: string, - behaviour: "dog" | "cat" + name: string; + img: string; + behaviour: "dog" | "cat"; } export const COMPANION_RESOURCES: CompanionResourceDescriptionInterface[] = [ @@ -11,4 +11,4 @@ export const COMPANION_RESOURCES: CompanionResourceDescriptionInterface[] = [ { name: "cat1", img: "resources/characters/pipoya/Cat 01-1.png", behaviour: "cat" }, { name: "cat2", img: "resources/characters/pipoya/Cat 01-2.png", behaviour: "cat" }, { name: "cat3", img: "resources/characters/pipoya/Cat 01-3.png", behaviour: "cat" }, -] +]; diff --git a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts index 75c20a48..bd87ba75 100644 --- a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts +++ b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts @@ -7,23 +7,23 @@ export const getAllCompanionResources = (loader: LoaderPlugin): CompanionResourc }); return COMPANION_RESOURCES; -} +}; export const lazyLoadCompanionResource = (loader: LoaderPlugin, name: string): Promise => { return new Promise((resolve, reject) => { - const resource = COMPANION_RESOURCES.find(item => item.name === name); + const resource = COMPANION_RESOURCES.find((item) => item.name === name); - if (typeof resource === 'undefined') { + if (typeof resource === "undefined") { return reject(`Texture '${name}' not found!`); } - + if (loader.textureManager.exists(resource.name)) { return resolve(resource.name); } - + loader.spritesheet(resource.name, resource.img, { frameWidth: 32, frameHeight: 32, endFrame: 12 }); loader.once(`filecomplete-spritesheet-${resource.name}`, () => resolve(resource.name)); - + loader.start(); // It's only automatically started during the Scene preload. }); -} +}; diff --git a/front/src/Phaser/Components/ChatModeIcon.ts b/front/src/Phaser/Components/ChatModeIcon.ts index 69449a1d..cba5a447 100644 --- a/front/src/Phaser/Components/ChatModeIcon.ts +++ b/front/src/Phaser/Components/ChatModeIcon.ts @@ -2,7 +2,7 @@ import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes"; export class ChatModeIcon extends Phaser.GameObjects.Sprite { constructor(scene: Phaser.Scene, x: number, y: number) { - super(scene, x, y, 'layout_modes', 3); + super(scene, x, y, "layout_modes", 3); scene.add.existing(this); this.setScrollFactor(0, 0); this.setOrigin(0, 1); @@ -10,4 +10,4 @@ export class ChatModeIcon extends Phaser.GameObjects.Sprite { this.setVisible(false); this.setDepth(DEPTH_INGAME_TEXT_INDEX); } -} \ No newline at end of file +} diff --git a/front/src/Phaser/Components/ClickButton.ts b/front/src/Phaser/Components/ClickButton.ts index 204e9542..65aaadbe 100644 --- a/front/src/Phaser/Components/ClickButton.ts +++ b/front/src/Phaser/Components/ClickButton.ts @@ -1,11 +1,8 @@ - -export class ClickButton extends Phaser.GameObjects.Image{ - +export class ClickButton extends Phaser.GameObjects.Image { constructor(scene: Phaser.Scene, x: number, y: number, textureName: string, callback: Function) { super(scene, x, y, textureName); this.scene.add.existing(this); this.setInteractive(); this.on("pointerup", callback); } - -} \ No newline at end of file +} diff --git a/front/src/Phaser/Components/PresentationModeIcon.ts b/front/src/Phaser/Components/PresentationModeIcon.ts index 09c8beb5..5f7c8d2f 100644 --- a/front/src/Phaser/Components/PresentationModeIcon.ts +++ b/front/src/Phaser/Components/PresentationModeIcon.ts @@ -1,8 +1,8 @@ -import {DEPTH_INGAME_TEXT_INDEX} from "../Game/DepthIndexes"; +import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes"; export class PresentationModeIcon extends Phaser.GameObjects.Sprite { constructor(scene: Phaser.Scene, x: number, y: number) { - super(scene, x, y, 'layout_modes', 0); + super(scene, x, y, "layout_modes", 0); scene.add.existing(this); this.setScrollFactor(0, 0); this.setOrigin(0, 1); @@ -10,4 +10,4 @@ export class PresentationModeIcon extends Phaser.GameObjects.Sprite { this.setVisible(false); this.setDepth(DEPTH_INGAME_TEXT_INDEX); } -} \ No newline at end of file +} diff --git a/front/src/Phaser/Components/RadialMenu.ts b/front/src/Phaser/Components/RadialMenu.ts index 1094f73a..c82bc4bf 100644 --- a/front/src/Phaser/Components/RadialMenu.ts +++ b/front/src/Phaser/Components/RadialMenu.ts @@ -1,20 +1,20 @@ import Sprite = Phaser.GameObjects.Sprite; -import {DEPTH_UI_INDEX} from "../Game/DepthIndexes"; -import {waScaleManager} from "../Services/WaScaleManager"; +import { DEPTH_UI_INDEX } from "../Game/DepthIndexes"; +import { waScaleManager } from "../Services/WaScaleManager"; export interface RadialMenuItem { - image: string, - name: string, + image: string; + name: string; } -export const RadialMenuClickEvent = 'radialClick'; +export const RadialMenuClickEvent = "radialClick"; export class RadialMenu extends Phaser.GameObjects.Container { private resizeCallback: OmitThisParameter<() => void>; - + constructor(scene: Phaser.Scene, x: number, y: number, private items: RadialMenuItem[]) { super(scene, x, y); - this.setDepth(DEPTH_UI_INDEX) + this.setDepth(DEPTH_UI_INDEX); this.scene.add.existing(this); this.initItems(); @@ -22,45 +22,45 @@ export class RadialMenu extends Phaser.GameObjects.Container { this.resizeCallback = this.resize.bind(this); this.scene.scale.on(Phaser.Scale.Events.RESIZE, this.resizeCallback); } - + private initItems() { const itemsNumber = this.items.length; const menuRadius = 70 + (waScaleManager.uiScalingFactor - 1) * 20; - this.items.forEach((item, index) => this.createRadialElement(item, index, itemsNumber, menuRadius)) + this.items.forEach((item, index) => this.createRadialElement(item, index, itemsNumber, menuRadius)); } - + private createRadialElement(item: RadialMenuItem, index: number, itemsNumber: number, menuRadius: number) { - const image = new Sprite(this.scene, 0, menuRadius, item.image); + const image = new Sprite(this.scene, 0, menuRadius, item.image); this.add(image); this.scene.sys.updateList.add(image); const scalingFactor = waScaleManager.uiScalingFactor * 0.075; - image.setScale(scalingFactor) + image.setScale(scalingFactor); image.setInteractive({ useHandCursor: true, }); - image.on('pointerdown', () => this.emit(RadialMenuClickEvent, item)); - image.on('pointerover', () => { + image.on("pointerdown", () => this.emit(RadialMenuClickEvent, item)); + image.on("pointerover", () => { this.scene.tweens.add({ targets: image, props: { scale: 2 * scalingFactor, }, duration: 500, - ease: 'Power3', - }) + ease: "Power3", + }); }); - image.on('pointerout', () => { + image.on("pointerout", () => { this.scene.tweens.add({ targets: image, props: { scale: scalingFactor, }, duration: 500, - ease: 'Power3', - }) + ease: "Power3", + }); }); - const angle = 2 * Math.PI * index / itemsNumber; - Phaser.Actions.RotateAroundDistance([image], {x: 0, y: 0}, angle, menuRadius); + const angle = (2 * Math.PI * index) / itemsNumber; + Phaser.Actions.RotateAroundDistance([image], { x: 0, y: 0 }, angle, menuRadius); } private resize() { @@ -71,4 +71,4 @@ export class RadialMenu extends Phaser.GameObjects.Container { this.scene.scale.removeListener(Phaser.Scale.Events.RESIZE, this.resizeCallback); super.destroy(); } -} \ No newline at end of file +} diff --git a/front/src/Phaser/Components/SoundMeter.ts b/front/src/Phaser/Components/SoundMeter.ts index 53802d31..4e7f4e8b 100644 --- a/front/src/Phaser/Components/SoundMeter.ts +++ b/front/src/Phaser/Components/SoundMeter.ts @@ -1,4 +1,4 @@ -import type {IAnalyserNode, IAudioContext, IMediaStreamAudioSourceNode} from 'standardized-audio-context'; +import type { IAnalyserNode, IAudioContext, IMediaStreamAudioSourceNode } from "standardized-audio-context"; /** * Class to measure the sound volume of a media stream @@ -7,10 +7,10 @@ export class SoundMeter { private instant: number; private clip: number; //private script: ScriptProcessorNode; - private analyser: IAnalyserNode|undefined; - private dataArray: Uint8Array|undefined; - private context: IAudioContext|undefined; - private source: IMediaStreamAudioSourceNode|undefined; + private analyser: IAnalyserNode | undefined; + private dataArray: Uint8Array | undefined; + private context: IAudioContext | undefined; + private source: IMediaStreamAudioSourceNode | undefined; constructor() { this.instant = 0.0; @@ -27,8 +27,7 @@ export class SoundMeter { this.dataArray = new Uint8Array(bufferLength); } - public connectToSource(stream: MediaStream, context: IAudioContext): void - { + public connectToSource(stream: MediaStream, context: IAudioContext): void { if (this.source !== undefined) { this.stop(); } @@ -42,8 +41,6 @@ export class SoundMeter { //analyser.connect(distortion); //distortion.connect(this.context.destination); //this.analyser.connect(this.context.destination); - - } public getVolume(): number { @@ -52,16 +49,15 @@ export class SoundMeter { } this.analyser.getByteFrequencyData(this.dataArray); - const input = this.dataArray; let i; let sum = 0.0; //let clipcount = 0; for (i = 0; i < input.length; ++i) { sum += input[i] * input[i]; - // if (Math.abs(input[i]) > 0.99) { - // clipcount += 1; - // } + // if (Math.abs(input[i]) > 0.99) { + // clipcount += 1; + // } } this.instant = Math.sqrt(sum / input.length); //this.slow = 0.95 * that.slow + 0.05 * that.instant; @@ -84,6 +80,4 @@ export class SoundMeter { this.dataArray = undefined; this.source = undefined; } - } - diff --git a/front/src/Phaser/Components/TextField.ts b/front/src/Phaser/Components/TextField.ts index 4eb6f41b..29f32497 100644 --- a/front/src/Phaser/Components/TextField.ts +++ b/front/src/Phaser/Components/TextField.ts @@ -1,10 +1,9 @@ - export class TextField extends Phaser.GameObjects.BitmapText { constructor(scene: Phaser.Scene, x: number, y: number, text: string | string[], center: boolean = true) { - super(scene, x, y, 'main_font', text, 8); + super(scene, x, y, "main_font", text, 8); this.scene.add.existing(this); if (center) { - this.setOrigin(0.5).setCenterAlign() + this.setOrigin(0.5).setCenterAlign(); } } } diff --git a/front/src/Phaser/Entity/CustomizedCharacter.ts b/front/src/Phaser/Entity/CustomizedCharacter.ts index 3a7f1597..79ac8ebc 100644 --- a/front/src/Phaser/Entity/CustomizedCharacter.ts +++ b/front/src/Phaser/Entity/CustomizedCharacter.ts @@ -1,5 +1,5 @@ import Container = Phaser.GameObjects.Container; -import type {Scene} from "phaser"; +import type { Scene } from "phaser"; import Sprite = Phaser.GameObjects.Sprite; /** diff --git a/front/src/Phaser/Entity/PlayerTextures.ts b/front/src/Phaser/Entity/PlayerTextures.ts index d0542d6a..d4376c66 100644 --- a/front/src/Phaser/Entity/PlayerTextures.ts +++ b/front/src/Phaser/Entity/PlayerTextures.ts @@ -1,333 +1,439 @@ //The list of all the player textures, both the default models and the partial textures used for customization export interface BodyResourceDescriptionListInterface { - [key: string]: BodyResourceDescriptionInterface + [key: string]: BodyResourceDescriptionInterface; } export interface BodyResourceDescriptionInterface { - name: string, - img: string, - level?: number + name: string; + img: string; + level?: number; } export const PLAYER_RESOURCES: BodyResourceDescriptionListInterface = { - "male1": {name: "male1", img: "resources/characters/pipoya/Male 01-1.png"}, - "male2": {name: "male2", img: "resources/characters/pipoya/Male 02-2.png"}, - "male3": {name: "male3", img: "resources/characters/pipoya/Male 03-4.png"}, - "male4": {name: "male4", img: "resources/characters/pipoya/Male 09-1.png"}, - "male5": {name: "male5", img: "resources/characters/pipoya/Male 10-3.png"}, - "male6": {name: "male6", img: "resources/characters/pipoya/Male 17-2.png"}, - "male7": {name: "male7", img: "resources/characters/pipoya/Male 18-1.png"}, - "male8": {name: "male8", img: "resources/characters/pipoya/Male 16-4.png"}, - "male9": {name: "male9", img: "resources/characters/pipoya/Male 07-2.png"}, - "male10": {name: "male10", img: "resources/characters/pipoya/Male 05-3.png"}, - "male11": {name: "male11", img: "resources/characters/pipoya/Teacher male 02.png"}, - "male12": {name: "male12", img: "resources/characters/pipoya/su4 Student male 12.png"}, + male1: { name: "male1", img: "resources/characters/pipoya/Male 01-1.png" }, + male2: { name: "male2", img: "resources/characters/pipoya/Male 02-2.png" }, + male3: { name: "male3", img: "resources/characters/pipoya/Male 03-4.png" }, + male4: { name: "male4", img: "resources/characters/pipoya/Male 09-1.png" }, + male5: { name: "male5", img: "resources/characters/pipoya/Male 10-3.png" }, + male6: { name: "male6", img: "resources/characters/pipoya/Male 17-2.png" }, + male7: { name: "male7", img: "resources/characters/pipoya/Male 18-1.png" }, + male8: { name: "male8", img: "resources/characters/pipoya/Male 16-4.png" }, + male9: { name: "male9", img: "resources/characters/pipoya/Male 07-2.png" }, + male10: { name: "male10", img: "resources/characters/pipoya/Male 05-3.png" }, + male11: { name: "male11", img: "resources/characters/pipoya/Teacher male 02.png" }, + male12: { name: "male12", img: "resources/characters/pipoya/su4 Student male 12.png" }, - "Female1": {name: "Female1", img: "resources/characters/pipoya/Female 01-1.png"}, - "Female2": {name: "Female2", img: "resources/characters/pipoya/Female 02-2.png"}, - "Female3": {name: "Female3", img: "resources/characters/pipoya/Female 03-4.png"}, - "Female4": {name: "Female4", img: "resources/characters/pipoya/Female 09-1.png"}, - "Female5": {name: "Female5", img: "resources/characters/pipoya/Female 10-3.png"}, - "Female6": {name: "Female6", img: "resources/characters/pipoya/Female 17-2.png"}, - "Female7": {name: "Female7", img: "resources/characters/pipoya/Female 18-1.png"}, - "Female8": {name: "Female8", img: "resources/characters/pipoya/Female 16-4.png"}, - "Female9": {name: "Female9", img: "resources/characters/pipoya/Female 07-2.png"}, - "Female10": {name: "Female10", img: "resources/characters/pipoya/Female 05-3.png"}, - "Female11": {name: "Female11", img: "resources/characters/pipoya/Teacher fmale 02.png"}, - "Female12": {name: "Female12", img: "resources/characters/pipoya/su4 Student fmale 12.png"}, + Female1: { name: "Female1", img: "resources/characters/pipoya/Female 01-1.png" }, + Female2: { name: "Female2", img: "resources/characters/pipoya/Female 02-2.png" }, + Female3: { name: "Female3", img: "resources/characters/pipoya/Female 03-4.png" }, + Female4: { name: "Female4", img: "resources/characters/pipoya/Female 09-1.png" }, + Female5: { name: "Female5", img: "resources/characters/pipoya/Female 10-3.png" }, + Female6: { name: "Female6", img: "resources/characters/pipoya/Female 17-2.png" }, + Female7: { name: "Female7", img: "resources/characters/pipoya/Female 18-1.png" }, + Female8: { name: "Female8", img: "resources/characters/pipoya/Female 16-4.png" }, + Female9: { name: "Female9", img: "resources/characters/pipoya/Female 07-2.png" }, + Female10: { name: "Female10", img: "resources/characters/pipoya/Female 05-3.png" }, + Female11: { name: "Female11", img: "resources/characters/pipoya/Teacher fmale 02.png" }, + Female12: { name: "Female12", img: "resources/characters/pipoya/su4 Student fmale 12.png" }, }; export const COLOR_RESOURCES: BodyResourceDescriptionListInterface = { - "color_1": {name: "color_1", img: "resources/customisation/character_color/character_color0.png"}, - "color_2": {name: "color_2", img: "resources/customisation/character_color/character_color1.png"}, - "color_3": {name: "color_3", img: "resources/customisation/character_color/character_color2.png"}, - "color_4": {name: "color_4", img: "resources/customisation/character_color/character_color3.png"}, - "color_5": {name: "color_5", img: "resources/customisation/character_color/character_color4.png"}, - "color_6": {name: "color_6", img: "resources/customisation/character_color/character_color5.png"}, - "color_7": {name: "color_7", img: "resources/customisation/character_color/character_color6.png"}, - "color_8": {name: "color_8", img: "resources/customisation/character_color/character_color7.png"}, - "color_9": {name: "color_9", img: "resources/customisation/character_color/character_color8.png"}, - "color_10": {name: "color_10", img: "resources/customisation/character_color/character_color9.png"}, - "color_11": {name: "color_11", img: "resources/customisation/character_color/character_color10.png"}, - "color_12": {name: "color_12", img: "resources/customisation/character_color/character_color11.png"}, - "color_13": {name: "color_13", img: "resources/customisation/character_color/character_color12.png"}, - "color_14": {name: "color_14", img: "resources/customisation/character_color/character_color13.png"}, - "color_15": {name: "color_15", img: "resources/customisation/character_color/character_color14.png"}, - "color_16": {name: "color_16", img: "resources/customisation/character_color/character_color15.png"}, - "color_17": {name: "color_17", img: "resources/customisation/character_color/character_color16.png"}, - "color_18": {name: "color_18", img: "resources/customisation/character_color/character_color17.png"}, - "color_19": {name: "color_19", img: "resources/customisation/character_color/character_color18.png"}, - "color_20": {name: "color_20", img: "resources/customisation/character_color/character_color19.png"}, - "color_21": {name: "color_21", img: "resources/customisation/character_color/character_color20.png"}, - "color_22": {name: "color_22", img: "resources/customisation/character_color/character_color21.png"}, - "color_23": {name: "color_23", img: "resources/customisation/character_color/character_color22.png"}, - "color_24": {name: "color_24", img: "resources/customisation/character_color/character_color23.png"}, - "color_25": {name: "color_25", img: "resources/customisation/character_color/character_color24.png"}, - "color_26": {name: "color_26", img: "resources/customisation/character_color/character_color25.png"}, - "color_27": {name: "color_27", img: "resources/customisation/character_color/character_color26.png"}, - "color_28": {name: "color_28", img: "resources/customisation/character_color/character_color27.png"}, - "color_29": {name: "color_29", img: "resources/customisation/character_color/character_color28.png"}, - "color_30": {name: "color_30", img: "resources/customisation/character_color/character_color29.png"}, - "color_31": {name: "color_31", img: "resources/customisation/character_color/character_color30.png"}, - "color_32": {name: "color_32", img: "resources/customisation/character_color/character_color31.png"}, - "color_33": {name: "color_33", img: "resources/customisation/character_color/character_color32.png"} + color_1: { name: "color_1", img: "resources/customisation/character_color/character_color0.png" }, + color_2: { name: "color_2", img: "resources/customisation/character_color/character_color1.png" }, + color_3: { name: "color_3", img: "resources/customisation/character_color/character_color2.png" }, + color_4: { name: "color_4", img: "resources/customisation/character_color/character_color3.png" }, + color_5: { name: "color_5", img: "resources/customisation/character_color/character_color4.png" }, + color_6: { name: "color_6", img: "resources/customisation/character_color/character_color5.png" }, + color_7: { name: "color_7", img: "resources/customisation/character_color/character_color6.png" }, + color_8: { name: "color_8", img: "resources/customisation/character_color/character_color7.png" }, + color_9: { name: "color_9", img: "resources/customisation/character_color/character_color8.png" }, + color_10: { name: "color_10", img: "resources/customisation/character_color/character_color9.png" }, + color_11: { name: "color_11", img: "resources/customisation/character_color/character_color10.png" }, + color_12: { name: "color_12", img: "resources/customisation/character_color/character_color11.png" }, + color_13: { name: "color_13", img: "resources/customisation/character_color/character_color12.png" }, + color_14: { name: "color_14", img: "resources/customisation/character_color/character_color13.png" }, + color_15: { name: "color_15", img: "resources/customisation/character_color/character_color14.png" }, + color_16: { name: "color_16", img: "resources/customisation/character_color/character_color15.png" }, + color_17: { name: "color_17", img: "resources/customisation/character_color/character_color16.png" }, + color_18: { name: "color_18", img: "resources/customisation/character_color/character_color17.png" }, + color_19: { name: "color_19", img: "resources/customisation/character_color/character_color18.png" }, + color_20: { name: "color_20", img: "resources/customisation/character_color/character_color19.png" }, + color_21: { name: "color_21", img: "resources/customisation/character_color/character_color20.png" }, + color_22: { name: "color_22", img: "resources/customisation/character_color/character_color21.png" }, + color_23: { name: "color_23", img: "resources/customisation/character_color/character_color22.png" }, + color_24: { name: "color_24", img: "resources/customisation/character_color/character_color23.png" }, + color_25: { name: "color_25", img: "resources/customisation/character_color/character_color24.png" }, + color_26: { name: "color_26", img: "resources/customisation/character_color/character_color25.png" }, + color_27: { name: "color_27", img: "resources/customisation/character_color/character_color26.png" }, + color_28: { name: "color_28", img: "resources/customisation/character_color/character_color27.png" }, + color_29: { name: "color_29", img: "resources/customisation/character_color/character_color28.png" }, + color_30: { name: "color_30", img: "resources/customisation/character_color/character_color29.png" }, + color_31: { name: "color_31", img: "resources/customisation/character_color/character_color30.png" }, + color_32: { name: "color_32", img: "resources/customisation/character_color/character_color31.png" }, + color_33: { name: "color_33", img: "resources/customisation/character_color/character_color32.png" }, }; export const EYES_RESOURCES: BodyResourceDescriptionListInterface = { - "eyes_1": {name: "eyes_1", img: "resources/customisation/character_eyes/character_eyes1.png"}, - "eyes_2": {name: "eyes_2", img: "resources/customisation/character_eyes/character_eyes2.png"}, - "eyes_3": {name: "eyes_3", img: "resources/customisation/character_eyes/character_eyes3.png"}, - "eyes_4": {name: "eyes_4", img: "resources/customisation/character_eyes/character_eyes4.png"}, - "eyes_5": {name: "eyes_5", img: "resources/customisation/character_eyes/character_eyes5.png"}, - "eyes_6": {name: "eyes_6", img: "resources/customisation/character_eyes/character_eyes6.png"}, - "eyes_7": {name: "eyes_7", img: "resources/customisation/character_eyes/character_eyes7.png"}, - "eyes_8": {name: "eyes_8", img: "resources/customisation/character_eyes/character_eyes8.png"}, - "eyes_9": {name: "eyes_9", img: "resources/customisation/character_eyes/character_eyes9.png"}, - "eyes_10": {name: "eyes_10", img: "resources/customisation/character_eyes/character_eyes10.png"}, - "eyes_11": {name: "eyes_11", img: "resources/customisation/character_eyes/character_eyes11.png"}, - "eyes_12": {name: "eyes_12", img: "resources/customisation/character_eyes/character_eyes12.png"}, - "eyes_13": {name: "eyes_13", img: "resources/customisation/character_eyes/character_eyes13.png"}, - "eyes_14": {name: "eyes_14", img: "resources/customisation/character_eyes/character_eyes14.png"}, - "eyes_15": {name: "eyes_15", img: "resources/customisation/character_eyes/character_eyes15.png"}, - "eyes_16": {name: "eyes_16", img: "resources/customisation/character_eyes/character_eyes16.png"}, - "eyes_17": {name: "eyes_17", img: "resources/customisation/character_eyes/character_eyes17.png"}, - "eyes_18": {name: "eyes_18", img: "resources/customisation/character_eyes/character_eyes18.png"}, - "eyes_19": {name: "eyes_19", img: "resources/customisation/character_eyes/character_eyes19.png"}, - "eyes_20": {name: "eyes_20", img: "resources/customisation/character_eyes/character_eyes20.png"}, - "eyes_21": {name: "eyes_21", img: "resources/customisation/character_eyes/character_eyes21.png"}, - "eyes_22": {name: "eyes_22", img: "resources/customisation/character_eyes/character_eyes22.png"}, - "eyes_23": {name: "eyes_23", img: "resources/customisation/character_eyes/character_eyes23.png"}, - "eyes_24": {name: "eyes_24", img: "resources/customisation/character_eyes/character_eyes24.png"}, - "eyes_25": {name: "eyes_25", img: "resources/customisation/character_eyes/character_eyes25.png"}, - "eyes_26": {name: "eyes_26", img: "resources/customisation/character_eyes/character_eyes26.png"}, - "eyes_27": {name: "eyes_27", img: "resources/customisation/character_eyes/character_eyes27.png"}, - "eyes_28": {name: "eyes_28", img: "resources/customisation/character_eyes/character_eyes28.png"}, - "eyes_29": {name: "eyes_29", img: "resources/customisation/character_eyes/character_eyes29.png"}, - "eyes_30": {name: "eyes_30", img: "resources/customisation/character_eyes/character_eyes30.png"} - + eyes_1: { name: "eyes_1", img: "resources/customisation/character_eyes/character_eyes1.png" }, + eyes_2: { name: "eyes_2", img: "resources/customisation/character_eyes/character_eyes2.png" }, + eyes_3: { name: "eyes_3", img: "resources/customisation/character_eyes/character_eyes3.png" }, + eyes_4: { name: "eyes_4", img: "resources/customisation/character_eyes/character_eyes4.png" }, + eyes_5: { name: "eyes_5", img: "resources/customisation/character_eyes/character_eyes5.png" }, + eyes_6: { name: "eyes_6", img: "resources/customisation/character_eyes/character_eyes6.png" }, + eyes_7: { name: "eyes_7", img: "resources/customisation/character_eyes/character_eyes7.png" }, + eyes_8: { name: "eyes_8", img: "resources/customisation/character_eyes/character_eyes8.png" }, + eyes_9: { name: "eyes_9", img: "resources/customisation/character_eyes/character_eyes9.png" }, + eyes_10: { name: "eyes_10", img: "resources/customisation/character_eyes/character_eyes10.png" }, + eyes_11: { name: "eyes_11", img: "resources/customisation/character_eyes/character_eyes11.png" }, + eyes_12: { name: "eyes_12", img: "resources/customisation/character_eyes/character_eyes12.png" }, + eyes_13: { name: "eyes_13", img: "resources/customisation/character_eyes/character_eyes13.png" }, + eyes_14: { name: "eyes_14", img: "resources/customisation/character_eyes/character_eyes14.png" }, + eyes_15: { name: "eyes_15", img: "resources/customisation/character_eyes/character_eyes15.png" }, + eyes_16: { name: "eyes_16", img: "resources/customisation/character_eyes/character_eyes16.png" }, + eyes_17: { name: "eyes_17", img: "resources/customisation/character_eyes/character_eyes17.png" }, + eyes_18: { name: "eyes_18", img: "resources/customisation/character_eyes/character_eyes18.png" }, + eyes_19: { name: "eyes_19", img: "resources/customisation/character_eyes/character_eyes19.png" }, + eyes_20: { name: "eyes_20", img: "resources/customisation/character_eyes/character_eyes20.png" }, + eyes_21: { name: "eyes_21", img: "resources/customisation/character_eyes/character_eyes21.png" }, + eyes_22: { name: "eyes_22", img: "resources/customisation/character_eyes/character_eyes22.png" }, + eyes_23: { name: "eyes_23", img: "resources/customisation/character_eyes/character_eyes23.png" }, + eyes_24: { name: "eyes_24", img: "resources/customisation/character_eyes/character_eyes24.png" }, + eyes_25: { name: "eyes_25", img: "resources/customisation/character_eyes/character_eyes25.png" }, + eyes_26: { name: "eyes_26", img: "resources/customisation/character_eyes/character_eyes26.png" }, + eyes_27: { name: "eyes_27", img: "resources/customisation/character_eyes/character_eyes27.png" }, + eyes_28: { name: "eyes_28", img: "resources/customisation/character_eyes/character_eyes28.png" }, + eyes_29: { name: "eyes_29", img: "resources/customisation/character_eyes/character_eyes29.png" }, + eyes_30: { name: "eyes_30", img: "resources/customisation/character_eyes/character_eyes30.png" }, }; export const HAIR_RESOURCES: BodyResourceDescriptionListInterface = { - "hair_1": {name:"hair_1", img: "resources/customisation/character_hairs/character_hairs0.png"}, - "hair_2": {name:"hair_2", img: "resources/customisation/character_hairs/character_hairs1.png"}, - "hair_3": {name:"hair_3", img: "resources/customisation/character_hairs/character_hairs2.png"}, - "hair_4": {name:"hair_4", img: "resources/customisation/character_hairs/character_hairs3.png"}, - "hair_5": {name:"hair_5", img: "resources/customisation/character_hairs/character_hairs4.png"}, - "hair_6": {name:"hair_6", img: "resources/customisation/character_hairs/character_hairs5.png"}, - "hair_7": {name:"hair_7", img: "resources/customisation/character_hairs/character_hairs6.png"}, - "hair_8": {name:"hair_8", img: "resources/customisation/character_hairs/character_hairs7.png"}, - "hair_9": {name:"hair_9", img: "resources/customisation/character_hairs/character_hairs8.png"}, - "hair_10": {name:"hair_10",img: "resources/customisation/character_hairs/character_hairs9.png"}, - "hair_11": {name:"hair_11",img: "resources/customisation/character_hairs/character_hairs10.png"}, - "hair_12": {name:"hair_12",img: "resources/customisation/character_hairs/character_hairs11.png"}, - "hair_13": {name:"hair_13",img: "resources/customisation/character_hairs/character_hairs12.png"}, - "hair_14": {name:"hair_14",img: "resources/customisation/character_hairs/character_hairs13.png"}, - "hair_15": {name:"hair_15",img: "resources/customisation/character_hairs/character_hairs14.png"}, - "hair_16": {name:"hair_16",img: "resources/customisation/character_hairs/character_hairs15.png"}, - "hair_17": {name:"hair_17",img: "resources/customisation/character_hairs/character_hairs16.png"}, - "hair_18": {name:"hair_18",img: "resources/customisation/character_hairs/character_hairs17.png"}, - "hair_19": {name:"hair_19",img: "resources/customisation/character_hairs/character_hairs18.png"}, - "hair_20": {name:"hair_20",img: "resources/customisation/character_hairs/character_hairs19.png"}, - "hair_21": {name:"hair_21",img: "resources/customisation/character_hairs/character_hairs20.png"}, - "hair_22": {name:"hair_22",img: "resources/customisation/character_hairs/character_hairs21.png"}, - "hair_23": {name:"hair_23",img: "resources/customisation/character_hairs/character_hairs22.png"}, - "hair_24": {name:"hair_24",img: "resources/customisation/character_hairs/character_hairs23.png"}, - "hair_25": {name:"hair_25",img: "resources/customisation/character_hairs/character_hairs24.png"}, - "hair_26": {name:"hair_26",img: "resources/customisation/character_hairs/character_hairs25.png"}, - "hair_27": {name:"hair_27",img: "resources/customisation/character_hairs/character_hairs26.png"}, - "hair_28": {name:"hair_28",img: "resources/customisation/character_hairs/character_hairs27.png"}, - "hair_29": {name:"hair_29",img: "resources/customisation/character_hairs/character_hairs28.png"}, - "hair_30": {name:"hair_30",img: "resources/customisation/character_hairs/character_hairs29.png"}, - "hair_31": {name:"hair_31",img: "resources/customisation/character_hairs/character_hairs30.png"}, - "hair_32": {name:"hair_32",img: "resources/customisation/character_hairs/character_hairs31.png"}, - "hair_33": {name:"hair_33",img: "resources/customisation/character_hairs/character_hairs32.png"}, - "hair_34": {name:"hair_34",img: "resources/customisation/character_hairs/character_hairs33.png"}, - "hair_35": {name:"hair_35",img: "resources/customisation/character_hairs/character_hairs34.png"}, - "hair_36": {name:"hair_36",img: "resources/customisation/character_hairs/character_hairs35.png"}, - "hair_37": {name:"hair_37",img: "resources/customisation/character_hairs/character_hairs36.png"}, - "hair_38": {name:"hair_38",img: "resources/customisation/character_hairs/character_hairs37.png"}, - "hair_39": {name:"hair_39",img: "resources/customisation/character_hairs/character_hairs38.png"}, - "hair_40": {name:"hair_40",img: "resources/customisation/character_hairs/character_hairs39.png"}, - "hair_41": {name:"hair_41",img: "resources/customisation/character_hairs/character_hairs40.png"}, - "hair_42": {name:"hair_42",img: "resources/customisation/character_hairs/character_hairs41.png"}, - "hair_43": {name:"hair_43",img: "resources/customisation/character_hairs/character_hairs42.png"}, - "hair_44": {name:"hair_44",img: "resources/customisation/character_hairs/character_hairs43.png"}, - "hair_45": {name:"hair_45",img: "resources/customisation/character_hairs/character_hairs44.png"}, - "hair_46": {name:"hair_46",img: "resources/customisation/character_hairs/character_hairs45.png"}, - "hair_47": {name:"hair_47",img: "resources/customisation/character_hairs/character_hairs46.png"}, - "hair_48": {name:"hair_48",img: "resources/customisation/character_hairs/character_hairs47.png"}, - "hair_49": {name:"hair_49",img: "resources/customisation/character_hairs/character_hairs48.png"}, - "hair_50": {name:"hair_50",img: "resources/customisation/character_hairs/character_hairs49.png"}, - "hair_51": {name:"hair_51",img: "resources/customisation/character_hairs/character_hairs50.png"}, - "hair_52": {name:"hair_52",img: "resources/customisation/character_hairs/character_hairs51.png"}, - "hair_53": {name:"hair_53",img: "resources/customisation/character_hairs/character_hairs52.png"}, - "hair_54": {name:"hair_54",img: "resources/customisation/character_hairs/character_hairs53.png"}, - "hair_55": {name:"hair_55",img: "resources/customisation/character_hairs/character_hairs54.png"}, - "hair_56": {name:"hair_56",img: "resources/customisation/character_hairs/character_hairs55.png"}, - "hair_57": {name:"hair_57",img: "resources/customisation/character_hairs/character_hairs56.png"}, - "hair_58": {name:"hair_58",img: "resources/customisation/character_hairs/character_hairs57.png"}, - "hair_59": {name:"hair_59",img: "resources/customisation/character_hairs/character_hairs58.png"}, - "hair_60": {name:"hair_60",img: "resources/customisation/character_hairs/character_hairs59.png"}, - "hair_61": {name:"hair_61",img: "resources/customisation/character_hairs/character_hairs60.png"}, - "hair_62": {name:"hair_62",img: "resources/customisation/character_hairs/character_hairs61.png"}, - "hair_63": {name:"hair_63",img: "resources/customisation/character_hairs/character_hairs62.png"}, - "hair_64": {name:"hair_64",img: "resources/customisation/character_hairs/character_hairs63.png"}, - "hair_65": {name:"hair_65",img: "resources/customisation/character_hairs/character_hairs64.png"}, - "hair_66": {name:"hair_66",img: "resources/customisation/character_hairs/character_hairs65.png"}, - "hair_67": {name:"hair_67",img: "resources/customisation/character_hairs/character_hairs66.png"}, - "hair_68": {name:"hair_68",img: "resources/customisation/character_hairs/character_hairs67.png"}, - "hair_69": {name:"hair_69",img: "resources/customisation/character_hairs/character_hairs68.png"}, - "hair_70": {name:"hair_70",img: "resources/customisation/character_hairs/character_hairs69.png"}, - "hair_71": {name:"hair_71",img: "resources/customisation/character_hairs/character_hairs70.png"}, - "hair_72": {name:"hair_72",img: "resources/customisation/character_hairs/character_hairs71.png"}, - "hair_73": {name:"hair_73",img: "resources/customisation/character_hairs/character_hairs72.png"}, - "hair_74": {name:"hair_74",img: "resources/customisation/character_hairs/character_hairs73.png"} + hair_1: { name: "hair_1", img: "resources/customisation/character_hairs/character_hairs0.png" }, + hair_2: { name: "hair_2", img: "resources/customisation/character_hairs/character_hairs1.png" }, + hair_3: { name: "hair_3", img: "resources/customisation/character_hairs/character_hairs2.png" }, + hair_4: { name: "hair_4", img: "resources/customisation/character_hairs/character_hairs3.png" }, + hair_5: { name: "hair_5", img: "resources/customisation/character_hairs/character_hairs4.png" }, + hair_6: { name: "hair_6", img: "resources/customisation/character_hairs/character_hairs5.png" }, + hair_7: { name: "hair_7", img: "resources/customisation/character_hairs/character_hairs6.png" }, + hair_8: { name: "hair_8", img: "resources/customisation/character_hairs/character_hairs7.png" }, + hair_9: { name: "hair_9", img: "resources/customisation/character_hairs/character_hairs8.png" }, + hair_10: { name: "hair_10", img: "resources/customisation/character_hairs/character_hairs9.png" }, + hair_11: { name: "hair_11", img: "resources/customisation/character_hairs/character_hairs10.png" }, + hair_12: { name: "hair_12", img: "resources/customisation/character_hairs/character_hairs11.png" }, + hair_13: { name: "hair_13", img: "resources/customisation/character_hairs/character_hairs12.png" }, + hair_14: { name: "hair_14", img: "resources/customisation/character_hairs/character_hairs13.png" }, + hair_15: { name: "hair_15", img: "resources/customisation/character_hairs/character_hairs14.png" }, + hair_16: { name: "hair_16", img: "resources/customisation/character_hairs/character_hairs15.png" }, + hair_17: { name: "hair_17", img: "resources/customisation/character_hairs/character_hairs16.png" }, + hair_18: { name: "hair_18", img: "resources/customisation/character_hairs/character_hairs17.png" }, + hair_19: { name: "hair_19", img: "resources/customisation/character_hairs/character_hairs18.png" }, + hair_20: { name: "hair_20", img: "resources/customisation/character_hairs/character_hairs19.png" }, + hair_21: { name: "hair_21", img: "resources/customisation/character_hairs/character_hairs20.png" }, + hair_22: { name: "hair_22", img: "resources/customisation/character_hairs/character_hairs21.png" }, + hair_23: { name: "hair_23", img: "resources/customisation/character_hairs/character_hairs22.png" }, + hair_24: { name: "hair_24", img: "resources/customisation/character_hairs/character_hairs23.png" }, + hair_25: { name: "hair_25", img: "resources/customisation/character_hairs/character_hairs24.png" }, + hair_26: { name: "hair_26", img: "resources/customisation/character_hairs/character_hairs25.png" }, + hair_27: { name: "hair_27", img: "resources/customisation/character_hairs/character_hairs26.png" }, + hair_28: { name: "hair_28", img: "resources/customisation/character_hairs/character_hairs27.png" }, + hair_29: { name: "hair_29", img: "resources/customisation/character_hairs/character_hairs28.png" }, + hair_30: { name: "hair_30", img: "resources/customisation/character_hairs/character_hairs29.png" }, + hair_31: { name: "hair_31", img: "resources/customisation/character_hairs/character_hairs30.png" }, + hair_32: { name: "hair_32", img: "resources/customisation/character_hairs/character_hairs31.png" }, + hair_33: { name: "hair_33", img: "resources/customisation/character_hairs/character_hairs32.png" }, + hair_34: { name: "hair_34", img: "resources/customisation/character_hairs/character_hairs33.png" }, + hair_35: { name: "hair_35", img: "resources/customisation/character_hairs/character_hairs34.png" }, + hair_36: { name: "hair_36", img: "resources/customisation/character_hairs/character_hairs35.png" }, + hair_37: { name: "hair_37", img: "resources/customisation/character_hairs/character_hairs36.png" }, + hair_38: { name: "hair_38", img: "resources/customisation/character_hairs/character_hairs37.png" }, + hair_39: { name: "hair_39", img: "resources/customisation/character_hairs/character_hairs38.png" }, + hair_40: { name: "hair_40", img: "resources/customisation/character_hairs/character_hairs39.png" }, + hair_41: { name: "hair_41", img: "resources/customisation/character_hairs/character_hairs40.png" }, + hair_42: { name: "hair_42", img: "resources/customisation/character_hairs/character_hairs41.png" }, + hair_43: { name: "hair_43", img: "resources/customisation/character_hairs/character_hairs42.png" }, + hair_44: { name: "hair_44", img: "resources/customisation/character_hairs/character_hairs43.png" }, + hair_45: { name: "hair_45", img: "resources/customisation/character_hairs/character_hairs44.png" }, + hair_46: { name: "hair_46", img: "resources/customisation/character_hairs/character_hairs45.png" }, + hair_47: { name: "hair_47", img: "resources/customisation/character_hairs/character_hairs46.png" }, + hair_48: { name: "hair_48", img: "resources/customisation/character_hairs/character_hairs47.png" }, + hair_49: { name: "hair_49", img: "resources/customisation/character_hairs/character_hairs48.png" }, + hair_50: { name: "hair_50", img: "resources/customisation/character_hairs/character_hairs49.png" }, + hair_51: { name: "hair_51", img: "resources/customisation/character_hairs/character_hairs50.png" }, + hair_52: { name: "hair_52", img: "resources/customisation/character_hairs/character_hairs51.png" }, + hair_53: { name: "hair_53", img: "resources/customisation/character_hairs/character_hairs52.png" }, + hair_54: { name: "hair_54", img: "resources/customisation/character_hairs/character_hairs53.png" }, + hair_55: { name: "hair_55", img: "resources/customisation/character_hairs/character_hairs54.png" }, + hair_56: { name: "hair_56", img: "resources/customisation/character_hairs/character_hairs55.png" }, + hair_57: { name: "hair_57", img: "resources/customisation/character_hairs/character_hairs56.png" }, + hair_58: { name: "hair_58", img: "resources/customisation/character_hairs/character_hairs57.png" }, + hair_59: { name: "hair_59", img: "resources/customisation/character_hairs/character_hairs58.png" }, + hair_60: { name: "hair_60", img: "resources/customisation/character_hairs/character_hairs59.png" }, + hair_61: { name: "hair_61", img: "resources/customisation/character_hairs/character_hairs60.png" }, + hair_62: { name: "hair_62", img: "resources/customisation/character_hairs/character_hairs61.png" }, + hair_63: { name: "hair_63", img: "resources/customisation/character_hairs/character_hairs62.png" }, + hair_64: { name: "hair_64", img: "resources/customisation/character_hairs/character_hairs63.png" }, + hair_65: { name: "hair_65", img: "resources/customisation/character_hairs/character_hairs64.png" }, + hair_66: { name: "hair_66", img: "resources/customisation/character_hairs/character_hairs65.png" }, + hair_67: { name: "hair_67", img: "resources/customisation/character_hairs/character_hairs66.png" }, + hair_68: { name: "hair_68", img: "resources/customisation/character_hairs/character_hairs67.png" }, + hair_69: { name: "hair_69", img: "resources/customisation/character_hairs/character_hairs68.png" }, + hair_70: { name: "hair_70", img: "resources/customisation/character_hairs/character_hairs69.png" }, + hair_71: { name: "hair_71", img: "resources/customisation/character_hairs/character_hairs70.png" }, + hair_72: { name: "hair_72", img: "resources/customisation/character_hairs/character_hairs71.png" }, + hair_73: { name: "hair_73", img: "resources/customisation/character_hairs/character_hairs72.png" }, + hair_74: { name: "hair_74", img: "resources/customisation/character_hairs/character_hairs73.png" }, }; - export const CLOTHES_RESOURCES: BodyResourceDescriptionListInterface = { - "clothes_1": {name:"clothes_1", img: "resources/customisation/character_clothes/character_clothes0.png"}, - "clothes_2": {name:"clothes_2", img: "resources/customisation/character_clothes/character_clothes1.png"}, - "clothes_3": {name:"clothes_3", img: "resources/customisation/character_clothes/character_clothes2.png"}, - "clothes_4": {name:"clothes_4", img: "resources/customisation/character_clothes/character_clothes3.png"}, - "clothes_5": {name:"clothes_5", img: "resources/customisation/character_clothes/character_clothes4.png"}, - "clothes_6": {name:"clothes_6", img: "resources/customisation/character_clothes/character_clothes5.png"}, - "clothes_7": {name:"clothes_7", img: "resources/customisation/character_clothes/character_clothes6.png"}, - "clothes_8": {name:"clothes_8", img: "resources/customisation/character_clothes/character_clothes7.png"}, - "clothes_9": {name:"clothes_9", img: "resources/customisation/character_clothes/character_clothes8.png"}, - "clothes_10": {name:"clothes_10",img: "resources/customisation/character_clothes/character_clothes9.png"}, - "clothes_11": {name:"clothes_11",img: "resources/customisation/character_clothes/character_clothes10.png"}, - "clothes_12": {name:"clothes_12",img: "resources/customisation/character_clothes/character_clothes11.png"}, - "clothes_13": {name:"clothes_13",img: "resources/customisation/character_clothes/character_clothes12.png"}, - "clothes_14": {name:"clothes_14",img: "resources/customisation/character_clothes/character_clothes13.png"}, - "clothes_15": {name:"clothes_15",img: "resources/customisation/character_clothes/character_clothes14.png"}, - "clothes_16": {name:"clothes_16",img: "resources/customisation/character_clothes/character_clothes15.png"}, - "clothes_17": {name:"clothes_17",img: "resources/customisation/character_clothes/character_clothes16.png"}, - "clothes_18": {name:"clothes_18",img: "resources/customisation/character_clothes/character_clothes17.png"}, - "clothes_19": {name:"clothes_19",img: "resources/customisation/character_clothes/character_clothes18.png"}, - "clothes_20": {name:"clothes_20",img: "resources/customisation/character_clothes/character_clothes19.png"}, - "clothes_21": {name:"clothes_21",img: "resources/customisation/character_clothes/character_clothes20.png"}, - "clothes_22": {name:"clothes_22",img: "resources/customisation/character_clothes/character_clothes21.png"}, - "clothes_23": {name:"clothes_23",img: "resources/customisation/character_clothes/character_clothes22.png"}, - "clothes_24": {name:"clothes_24",img: "resources/customisation/character_clothes/character_clothes23.png"}, - "clothes_25": {name:"clothes_25",img: "resources/customisation/character_clothes/character_clothes24.png"}, - "clothes_26": {name:"clothes_26",img: "resources/customisation/character_clothes/character_clothes25.png"}, - "clothes_27": {name:"clothes_27",img: "resources/customisation/character_clothes/character_clothes26.png"}, - "clothes_28": {name:"clothes_28",img: "resources/customisation/character_clothes/character_clothes27.png"}, - "clothes_29": {name:"clothes_29",img: "resources/customisation/character_clothes/character_clothes28.png"}, - "clothes_30": {name:"clothes_30",img: "resources/customisation/character_clothes/character_clothes29.png"}, - "clothes_31": {name:"clothes_31",img: "resources/customisation/character_clothes/character_clothes30.png"}, - "clothes_32": {name:"clothes_32",img: "resources/customisation/character_clothes/character_clothes31.png"}, - "clothes_33": {name:"clothes_33",img: "resources/customisation/character_clothes/character_clothes32.png"}, - "clothes_34": {name:"clothes_34",img: "resources/customisation/character_clothes/character_clothes33.png"}, - "clothes_35": {name:"clothes_35",img: "resources/customisation/character_clothes/character_clothes34.png"}, - "clothes_36": {name:"clothes_36",img: "resources/customisation/character_clothes/character_clothes35.png"}, - "clothes_37": {name:"clothes_37",img: "resources/customisation/character_clothes/character_clothes36.png"}, - "clothes_38": {name:"clothes_38",img: "resources/customisation/character_clothes/character_clothes37.png"}, - "clothes_39": {name:"clothes_39",img: "resources/customisation/character_clothes/character_clothes38.png"}, - "clothes_40": {name:"clothes_40",img: "resources/customisation/character_clothes/character_clothes39.png"}, - "clothes_41": {name:"clothes_41",img: "resources/customisation/character_clothes/character_clothes40.png"}, - "clothes_42": {name:"clothes_42",img: "resources/customisation/character_clothes/character_clothes41.png"}, - "clothes_43": {name:"clothes_43",img: "resources/customisation/character_clothes/character_clothes42.png"}, - "clothes_44": {name:"clothes_44",img: "resources/customisation/character_clothes/character_clothes43.png"}, - "clothes_45": {name:"clothes_45",img: "resources/customisation/character_clothes/character_clothes44.png"}, - "clothes_46": {name:"clothes_46",img: "resources/customisation/character_clothes/character_clothes45.png"}, - "clothes_47": {name:"clothes_47",img: "resources/customisation/character_clothes/character_clothes46.png"}, - "clothes_48": {name:"clothes_48",img: "resources/customisation/character_clothes/character_clothes47.png"}, - "clothes_49": {name:"clothes_49",img: "resources/customisation/character_clothes/character_clothes48.png"}, - "clothes_50": {name:"clothes_50",img: "resources/customisation/character_clothes/character_clothes49.png"}, - "clothes_51": {name:"clothes_51",img: "resources/customisation/character_clothes/character_clothes50.png"}, - "clothes_52": {name:"clothes_52",img: "resources/customisation/character_clothes/character_clothes51.png"}, - "clothes_53": {name:"clothes_53",img: "resources/customisation/character_clothes/character_clothes52.png"}, - "clothes_54": {name:"clothes_54",img: "resources/customisation/character_clothes/character_clothes53.png"}, - "clothes_55": {name:"clothes_55",img: "resources/customisation/character_clothes/character_clothes54.png"}, - "clothes_56": {name:"clothes_56",img: "resources/customisation/character_clothes/character_clothes55.png"}, - "clothes_57": {name:"clothes_57",img: "resources/customisation/character_clothes/character_clothes56.png"}, - "clothes_58": {name:"clothes_58",img: "resources/customisation/character_clothes/character_clothes57.png"}, - "clothes_59": {name:"clothes_59",img: "resources/customisation/character_clothes/character_clothes58.png"}, - "clothes_60": {name:"clothes_60",img: "resources/customisation/character_clothes/character_clothes59.png"}, - "clothes_61": {name:"clothes_61",img: "resources/customisation/character_clothes/character_clothes60.png"}, - "clothes_62": {name:"clothes_62",img: "resources/customisation/character_clothes/character_clothes61.png"}, - "clothes_63": {name:"clothes_63",img: "resources/customisation/character_clothes/character_clothes62.png"}, - "clothes_64": {name:"clothes_64",img: "resources/customisation/character_clothes/character_clothes63.png"}, - "clothes_65": {name:"clothes_65",img: "resources/customisation/character_clothes/character_clothes64.png"}, - "clothes_66": {name:"clothes_66",img: "resources/customisation/character_clothes/character_clothes65.png"}, - "clothes_67": {name:"clothes_67",img: "resources/customisation/character_clothes/character_clothes66.png"}, - "clothes_68": {name:"clothes_68",img: "resources/customisation/character_clothes/character_clothes67.png"}, - "clothes_69": {name:"clothes_69",img: "resources/customisation/character_clothes/character_clothes68.png"}, - "clothes_70": {name:"clothes_70",img: "resources/customisation/character_clothes/character_clothes69.png"}, - "clothes_pride_shirt": {name:"clothes_pride_shirt",img: "resources/customisation/character_clothes/pride_shirt.png"}, - "clothes_black_hoodie": {name:"clothes_black_hoodie",img: "resources/customisation/character_clothes/black_hoodie.png"}, - "clothes_white_hoodie": {name:"clothes_white_hoodie",img: "resources/customisation/character_clothes/white_hoodie.png"}, - "clothes_engelbert": {name:"clothes_engelbert",img: "resources/customisation/character_clothes/engelbert.png"} + clothes_1: { name: "clothes_1", img: "resources/customisation/character_clothes/character_clothes0.png" }, + clothes_2: { name: "clothes_2", img: "resources/customisation/character_clothes/character_clothes1.png" }, + clothes_3: { name: "clothes_3", img: "resources/customisation/character_clothes/character_clothes2.png" }, + clothes_4: { name: "clothes_4", img: "resources/customisation/character_clothes/character_clothes3.png" }, + clothes_5: { name: "clothes_5", img: "resources/customisation/character_clothes/character_clothes4.png" }, + clothes_6: { name: "clothes_6", img: "resources/customisation/character_clothes/character_clothes5.png" }, + clothes_7: { name: "clothes_7", img: "resources/customisation/character_clothes/character_clothes6.png" }, + clothes_8: { name: "clothes_8", img: "resources/customisation/character_clothes/character_clothes7.png" }, + clothes_9: { name: "clothes_9", img: "resources/customisation/character_clothes/character_clothes8.png" }, + clothes_10: { name: "clothes_10", img: "resources/customisation/character_clothes/character_clothes9.png" }, + clothes_11: { name: "clothes_11", img: "resources/customisation/character_clothes/character_clothes10.png" }, + clothes_12: { name: "clothes_12", img: "resources/customisation/character_clothes/character_clothes11.png" }, + clothes_13: { name: "clothes_13", img: "resources/customisation/character_clothes/character_clothes12.png" }, + clothes_14: { name: "clothes_14", img: "resources/customisation/character_clothes/character_clothes13.png" }, + clothes_15: { name: "clothes_15", img: "resources/customisation/character_clothes/character_clothes14.png" }, + clothes_16: { name: "clothes_16", img: "resources/customisation/character_clothes/character_clothes15.png" }, + clothes_17: { name: "clothes_17", img: "resources/customisation/character_clothes/character_clothes16.png" }, + clothes_18: { name: "clothes_18", img: "resources/customisation/character_clothes/character_clothes17.png" }, + clothes_19: { name: "clothes_19", img: "resources/customisation/character_clothes/character_clothes18.png" }, + clothes_20: { name: "clothes_20", img: "resources/customisation/character_clothes/character_clothes19.png" }, + clothes_21: { name: "clothes_21", img: "resources/customisation/character_clothes/character_clothes20.png" }, + clothes_22: { name: "clothes_22", img: "resources/customisation/character_clothes/character_clothes21.png" }, + clothes_23: { name: "clothes_23", img: "resources/customisation/character_clothes/character_clothes22.png" }, + clothes_24: { name: "clothes_24", img: "resources/customisation/character_clothes/character_clothes23.png" }, + clothes_25: { name: "clothes_25", img: "resources/customisation/character_clothes/character_clothes24.png" }, + clothes_26: { name: "clothes_26", img: "resources/customisation/character_clothes/character_clothes25.png" }, + clothes_27: { name: "clothes_27", img: "resources/customisation/character_clothes/character_clothes26.png" }, + clothes_28: { name: "clothes_28", img: "resources/customisation/character_clothes/character_clothes27.png" }, + clothes_29: { name: "clothes_29", img: "resources/customisation/character_clothes/character_clothes28.png" }, + clothes_30: { name: "clothes_30", img: "resources/customisation/character_clothes/character_clothes29.png" }, + clothes_31: { name: "clothes_31", img: "resources/customisation/character_clothes/character_clothes30.png" }, + clothes_32: { name: "clothes_32", img: "resources/customisation/character_clothes/character_clothes31.png" }, + clothes_33: { name: "clothes_33", img: "resources/customisation/character_clothes/character_clothes32.png" }, + clothes_34: { name: "clothes_34", img: "resources/customisation/character_clothes/character_clothes33.png" }, + clothes_35: { name: "clothes_35", img: "resources/customisation/character_clothes/character_clothes34.png" }, + clothes_36: { name: "clothes_36", img: "resources/customisation/character_clothes/character_clothes35.png" }, + clothes_37: { name: "clothes_37", img: "resources/customisation/character_clothes/character_clothes36.png" }, + clothes_38: { name: "clothes_38", img: "resources/customisation/character_clothes/character_clothes37.png" }, + clothes_39: { name: "clothes_39", img: "resources/customisation/character_clothes/character_clothes38.png" }, + clothes_40: { name: "clothes_40", img: "resources/customisation/character_clothes/character_clothes39.png" }, + clothes_41: { name: "clothes_41", img: "resources/customisation/character_clothes/character_clothes40.png" }, + clothes_42: { name: "clothes_42", img: "resources/customisation/character_clothes/character_clothes41.png" }, + clothes_43: { name: "clothes_43", img: "resources/customisation/character_clothes/character_clothes42.png" }, + clothes_44: { name: "clothes_44", img: "resources/customisation/character_clothes/character_clothes43.png" }, + clothes_45: { name: "clothes_45", img: "resources/customisation/character_clothes/character_clothes44.png" }, + clothes_46: { name: "clothes_46", img: "resources/customisation/character_clothes/character_clothes45.png" }, + clothes_47: { name: "clothes_47", img: "resources/customisation/character_clothes/character_clothes46.png" }, + clothes_48: { name: "clothes_48", img: "resources/customisation/character_clothes/character_clothes47.png" }, + clothes_49: { name: "clothes_49", img: "resources/customisation/character_clothes/character_clothes48.png" }, + clothes_50: { name: "clothes_50", img: "resources/customisation/character_clothes/character_clothes49.png" }, + clothes_51: { name: "clothes_51", img: "resources/customisation/character_clothes/character_clothes50.png" }, + clothes_52: { name: "clothes_52", img: "resources/customisation/character_clothes/character_clothes51.png" }, + clothes_53: { name: "clothes_53", img: "resources/customisation/character_clothes/character_clothes52.png" }, + clothes_54: { name: "clothes_54", img: "resources/customisation/character_clothes/character_clothes53.png" }, + clothes_55: { name: "clothes_55", img: "resources/customisation/character_clothes/character_clothes54.png" }, + clothes_56: { name: "clothes_56", img: "resources/customisation/character_clothes/character_clothes55.png" }, + clothes_57: { name: "clothes_57", img: "resources/customisation/character_clothes/character_clothes56.png" }, + clothes_58: { name: "clothes_58", img: "resources/customisation/character_clothes/character_clothes57.png" }, + clothes_59: { name: "clothes_59", img: "resources/customisation/character_clothes/character_clothes58.png" }, + clothes_60: { name: "clothes_60", img: "resources/customisation/character_clothes/character_clothes59.png" }, + clothes_61: { name: "clothes_61", img: "resources/customisation/character_clothes/character_clothes60.png" }, + clothes_62: { name: "clothes_62", img: "resources/customisation/character_clothes/character_clothes61.png" }, + clothes_63: { name: "clothes_63", img: "resources/customisation/character_clothes/character_clothes62.png" }, + clothes_64: { name: "clothes_64", img: "resources/customisation/character_clothes/character_clothes63.png" }, + clothes_65: { name: "clothes_65", img: "resources/customisation/character_clothes/character_clothes64.png" }, + clothes_66: { name: "clothes_66", img: "resources/customisation/character_clothes/character_clothes65.png" }, + clothes_67: { name: "clothes_67", img: "resources/customisation/character_clothes/character_clothes66.png" }, + clothes_68: { name: "clothes_68", img: "resources/customisation/character_clothes/character_clothes67.png" }, + clothes_69: { name: "clothes_69", img: "resources/customisation/character_clothes/character_clothes68.png" }, + clothes_70: { name: "clothes_70", img: "resources/customisation/character_clothes/character_clothes69.png" }, + clothes_pride_shirt: { + name: "clothes_pride_shirt", + img: "resources/customisation/character_clothes/pride_shirt.png", + }, + clothes_black_hoodie: { + name: "clothes_black_hoodie", + img: "resources/customisation/character_clothes/black_hoodie.png", + }, + clothes_white_hoodie: { + name: "clothes_white_hoodie", + img: "resources/customisation/character_clothes/white_hoodie.png", + }, + clothes_engelbert: { name: "clothes_engelbert", img: "resources/customisation/character_clothes/engelbert.png" }, }; export const HATS_RESOURCES: BodyResourceDescriptionListInterface = { - "hats_1": {name: "hats_1", img: "resources/customisation/character_hats/character_hats1.png"}, - "hats_2": {name: "hats_2", img: "resources/customisation/character_hats/character_hats2.png"}, - "hats_3": {name: "hats_3", img: "resources/customisation/character_hats/character_hats3.png"}, - "hats_4": {name: "hats_4", img: "resources/customisation/character_hats/character_hats4.png"}, - "hats_5": {name: "hats_5", img: "resources/customisation/character_hats/character_hats5.png"}, - "hats_6": {name: "hats_6", img: "resources/customisation/character_hats/character_hats6.png"}, - "hats_7": {name: "hats_7", img: "resources/customisation/character_hats/character_hats7.png"}, - "hats_8": {name: "hats_8", img: "resources/customisation/character_hats/character_hats8.png"}, - "hats_9": {name: "hats_9", img: "resources/customisation/character_hats/character_hats9.png"}, - "hats_10": {name: "hats_10", img: "resources/customisation/character_hats/character_hats10.png"}, - "hats_11": {name: "hats_11", img: "resources/customisation/character_hats/character_hats11.png"}, - "hats_12": {name: "hats_12", img: "resources/customisation/character_hats/character_hats12.png"}, - "hats_13": {name: "hats_13", img: "resources/customisation/character_hats/character_hats13.png"}, - "hats_14": {name: "hats_14", img: "resources/customisation/character_hats/character_hats14.png"}, - "hats_15": {name: "hats_15", img: "resources/customisation/character_hats/character_hats15.png"}, - "hats_16": {name: "hats_16", img: "resources/customisation/character_hats/character_hats16.png"}, - "hats_17": {name: "hats_17", img: "resources/customisation/character_hats/character_hats17.png"}, - "hats_18": {name: "hats_18", img: "resources/customisation/character_hats/character_hats18.png"}, - "hats_19": {name: "hats_19", img: "resources/customisation/character_hats/character_hats19.png"}, - "hats_20": {name: "hats_20", img: "resources/customisation/character_hats/character_hats20.png"}, - "hats_21": {name: "hats_21", img: "resources/customisation/character_hats/character_hats21.png"}, - "hats_22": {name: "hats_22", img: "resources/customisation/character_hats/character_hats22.png"}, - "hats_23": {name: "hats_23", img: "resources/customisation/character_hats/character_hats23.png"}, - "hats_24": {name: "hats_24", img: "resources/customisation/character_hats/character_hats24.png"}, - "hats_25": {name: "hats_25", img: "resources/customisation/character_hats/character_hats25.png"}, - "hats_26": {name: "hats_26", img: "resources/customisation/character_hats/character_hats26.png"}, - "tinfoil_hat1": {name: "tinfoil_hat1", img: "resources/customisation/character_hats/tinfoil_hat1.png"} + hats_1: { name: "hats_1", img: "resources/customisation/character_hats/character_hats1.png" }, + hats_2: { name: "hats_2", img: "resources/customisation/character_hats/character_hats2.png" }, + hats_3: { name: "hats_3", img: "resources/customisation/character_hats/character_hats3.png" }, + hats_4: { name: "hats_4", img: "resources/customisation/character_hats/character_hats4.png" }, + hats_5: { name: "hats_5", img: "resources/customisation/character_hats/character_hats5.png" }, + hats_6: { name: "hats_6", img: "resources/customisation/character_hats/character_hats6.png" }, + hats_7: { name: "hats_7", img: "resources/customisation/character_hats/character_hats7.png" }, + hats_8: { name: "hats_8", img: "resources/customisation/character_hats/character_hats8.png" }, + hats_9: { name: "hats_9", img: "resources/customisation/character_hats/character_hats9.png" }, + hats_10: { name: "hats_10", img: "resources/customisation/character_hats/character_hats10.png" }, + hats_11: { name: "hats_11", img: "resources/customisation/character_hats/character_hats11.png" }, + hats_12: { name: "hats_12", img: "resources/customisation/character_hats/character_hats12.png" }, + hats_13: { name: "hats_13", img: "resources/customisation/character_hats/character_hats13.png" }, + hats_14: { name: "hats_14", img: "resources/customisation/character_hats/character_hats14.png" }, + hats_15: { name: "hats_15", img: "resources/customisation/character_hats/character_hats15.png" }, + hats_16: { name: "hats_16", img: "resources/customisation/character_hats/character_hats16.png" }, + hats_17: { name: "hats_17", img: "resources/customisation/character_hats/character_hats17.png" }, + hats_18: { name: "hats_18", img: "resources/customisation/character_hats/character_hats18.png" }, + hats_19: { name: "hats_19", img: "resources/customisation/character_hats/character_hats19.png" }, + hats_20: { name: "hats_20", img: "resources/customisation/character_hats/character_hats20.png" }, + hats_21: { name: "hats_21", img: "resources/customisation/character_hats/character_hats21.png" }, + hats_22: { name: "hats_22", img: "resources/customisation/character_hats/character_hats22.png" }, + hats_23: { name: "hats_23", img: "resources/customisation/character_hats/character_hats23.png" }, + hats_24: { name: "hats_24", img: "resources/customisation/character_hats/character_hats24.png" }, + hats_25: { name: "hats_25", img: "resources/customisation/character_hats/character_hats25.png" }, + hats_26: { name: "hats_26", img: "resources/customisation/character_hats/character_hats26.png" }, + tinfoil_hat1: { name: "tinfoil_hat1", img: "resources/customisation/character_hats/tinfoil_hat1.png" }, }; export const ACCESSORIES_RESOURCES: BodyResourceDescriptionListInterface = { - "accessory_1": {name: "accessory_1", img: "resources/customisation/character_accessories/character_accessories1.png"}, - "accessory_2": {name: "accessory_2", img: "resources/customisation/character_accessories/character_accessories2.png"}, - "accessory_3": {name: "accessory_3", img: "resources/customisation/character_accessories/character_accessories3.png"}, - "accessory_4": {name: "accessory_4", img: "resources/customisation/character_accessories/character_accessories4.png"}, - "accessory_5": {name: "accessory_5", img: "resources/customisation/character_accessories/character_accessories5.png"}, - "accessory_6": {name: "accessory_6", img: "resources/customisation/character_accessories/character_accessories6.png"}, - "accessory_7": {name: "accessory_7", img: "resources/customisation/character_accessories/character_accessories7.png"}, - "accessory_8": {name: "accessory_8", img: "resources/customisation/character_accessories/character_accessories8.png"}, - "accessory_9": {name: "accessory_9", img: "resources/customisation/character_accessories/character_accessories9.png"}, - "accessory_10": {name: "accessory_10", img: "resources/customisation/character_accessories/character_accessories10.png"}, - "accessory_11": {name: "accessory_11", img: "resources/customisation/character_accessories/character_accessories11.png"}, - "accessory_12": {name: "accessory_12", img: "resources/customisation/character_accessories/character_accessories12.png"}, - "accessory_13": {name: "accessory_13", img: "resources/customisation/character_accessories/character_accessories13.png"}, - "accessory_14": {name: "accessory_14", img: "resources/customisation/character_accessories/character_accessories14.png"}, - "accessory_15": {name: "accessory_15", img: "resources/customisation/character_accessories/character_accessories15.png"}, - "accessory_16": {name: "accessory_16", img: "resources/customisation/character_accessories/character_accessories16.png"}, - "accessory_17": {name: "accessory_17", img: "resources/customisation/character_accessories/character_accessories17.png"}, - "accessory_18": {name: "accessory_18", img: "resources/customisation/character_accessories/character_accessories18.png"}, - "accessory_19": {name: "accessory_19", img: "resources/customisation/character_accessories/character_accessories19.png"}, - "accessory_20": {name: "accessory_20", img: "resources/customisation/character_accessories/character_accessories20.png"}, - "accessory_21": {name: "accessory_21", img: "resources/customisation/character_accessories/character_accessories21.png"}, - "accessory_22": {name: "accessory_22", img: "resources/customisation/character_accessories/character_accessories22.png"}, - "accessory_23": {name: "accessory_23", img: "resources/customisation/character_accessories/character_accessories23.png"}, - "accessory_24": {name: "accessory_24", img: "resources/customisation/character_accessories/character_accessories24.png"}, - "accessory_25": {name: "accessory_25", img: "resources/customisation/character_accessories/character_accessories25.png"}, - "accessory_26": {name: "accessory_26", img: "resources/customisation/character_accessories/character_accessories26.png"}, - "accessory_27": {name: "accessory_27", img: "resources/customisation/character_accessories/character_accessories27.png"}, - "accessory_28": {name: "accessory_28", img: "resources/customisation/character_accessories/character_accessories28.png"}, - "accessory_29": {name: "accessory_29", img: "resources/customisation/character_accessories/character_accessories29.png"}, - "accessory_30": {name: "accessory_30", img: "resources/customisation/character_accessories/character_accessories30.png"}, - "accessory_31": {name: "accessory_31", img: "resources/customisation/character_accessories/character_accessories31.png"}, - "accessory_32": {name: "accessory_32", img: "resources/customisation/character_accessories/character_accessories32.png"}, - "accessory_mate_bottle": {name: "accessory_mate_bottle", img: "resources/customisation/character_accessories/mate_bottle1.png"}, - "accessory_mask": {name: "accessory_mask", img: "resources/customisation/character_accessories/mask.png"} + accessory_1: { + name: "accessory_1", + img: "resources/customisation/character_accessories/character_accessories1.png", + }, + accessory_2: { + name: "accessory_2", + img: "resources/customisation/character_accessories/character_accessories2.png", + }, + accessory_3: { + name: "accessory_3", + img: "resources/customisation/character_accessories/character_accessories3.png", + }, + accessory_4: { + name: "accessory_4", + img: "resources/customisation/character_accessories/character_accessories4.png", + }, + accessory_5: { + name: "accessory_5", + img: "resources/customisation/character_accessories/character_accessories5.png", + }, + accessory_6: { + name: "accessory_6", + img: "resources/customisation/character_accessories/character_accessories6.png", + }, + accessory_7: { + name: "accessory_7", + img: "resources/customisation/character_accessories/character_accessories7.png", + }, + accessory_8: { + name: "accessory_8", + img: "resources/customisation/character_accessories/character_accessories8.png", + }, + accessory_9: { + name: "accessory_9", + img: "resources/customisation/character_accessories/character_accessories9.png", + }, + accessory_10: { + name: "accessory_10", + img: "resources/customisation/character_accessories/character_accessories10.png", + }, + accessory_11: { + name: "accessory_11", + img: "resources/customisation/character_accessories/character_accessories11.png", + }, + accessory_12: { + name: "accessory_12", + img: "resources/customisation/character_accessories/character_accessories12.png", + }, + accessory_13: { + name: "accessory_13", + img: "resources/customisation/character_accessories/character_accessories13.png", + }, + accessory_14: { + name: "accessory_14", + img: "resources/customisation/character_accessories/character_accessories14.png", + }, + accessory_15: { + name: "accessory_15", + img: "resources/customisation/character_accessories/character_accessories15.png", + }, + accessory_16: { + name: "accessory_16", + img: "resources/customisation/character_accessories/character_accessories16.png", + }, + accessory_17: { + name: "accessory_17", + img: "resources/customisation/character_accessories/character_accessories17.png", + }, + accessory_18: { + name: "accessory_18", + img: "resources/customisation/character_accessories/character_accessories18.png", + }, + accessory_19: { + name: "accessory_19", + img: "resources/customisation/character_accessories/character_accessories19.png", + }, + accessory_20: { + name: "accessory_20", + img: "resources/customisation/character_accessories/character_accessories20.png", + }, + accessory_21: { + name: "accessory_21", + img: "resources/customisation/character_accessories/character_accessories21.png", + }, + accessory_22: { + name: "accessory_22", + img: "resources/customisation/character_accessories/character_accessories22.png", + }, + accessory_23: { + name: "accessory_23", + img: "resources/customisation/character_accessories/character_accessories23.png", + }, + accessory_24: { + name: "accessory_24", + img: "resources/customisation/character_accessories/character_accessories24.png", + }, + accessory_25: { + name: "accessory_25", + img: "resources/customisation/character_accessories/character_accessories25.png", + }, + accessory_26: { + name: "accessory_26", + img: "resources/customisation/character_accessories/character_accessories26.png", + }, + accessory_27: { + name: "accessory_27", + img: "resources/customisation/character_accessories/character_accessories27.png", + }, + accessory_28: { + name: "accessory_28", + img: "resources/customisation/character_accessories/character_accessories28.png", + }, + accessory_29: { + name: "accessory_29", + img: "resources/customisation/character_accessories/character_accessories29.png", + }, + accessory_30: { + name: "accessory_30", + img: "resources/customisation/character_accessories/character_accessories30.png", + }, + accessory_31: { + name: "accessory_31", + img: "resources/customisation/character_accessories/character_accessories31.png", + }, + accessory_32: { + name: "accessory_32", + img: "resources/customisation/character_accessories/character_accessories32.png", + }, + accessory_mate_bottle: { + name: "accessory_mate_bottle", + img: "resources/customisation/character_accessories/mate_bottle1.png", + }, + accessory_mask: { name: "accessory_mask", img: "resources/customisation/character_accessories/mask.png" }, }; export const LAYERS: BodyResourceDescriptionListInterface[] = [ @@ -336,9 +442,9 @@ export const LAYERS: BodyResourceDescriptionListInterface[] = [ HAIR_RESOURCES, CLOTHES_RESOURCES, HATS_RESOURCES, - ACCESSORIES_RESOURCES + ACCESSORIES_RESOURCES, ]; export const OBJECTS: BodyResourceDescriptionInterface[] = [ - {name:'teleportation', img:'resources/objects/teleportation.png'}, -]; \ No newline at end of file + { name: "teleportation", img: "resources/objects/teleportation.png" }, +]; diff --git a/front/src/Phaser/Entity/SpeechBubble.ts b/front/src/Phaser/Entity/SpeechBubble.ts index 17b7ed0e..4ca3d9ee 100644 --- a/front/src/Phaser/Entity/SpeechBubble.ts +++ b/front/src/Phaser/Entity/SpeechBubble.ts @@ -1,14 +1,12 @@ import Scene = Phaser.Scene; -import type {Character} from "./Character"; +import type { Character } from "./Character"; //todo: improve this WIP export class SpeechBubble { private bubble: Phaser.GameObjects.Graphics; private content: Phaser.GameObjects.Text; - constructor(scene: Scene, player: Character, text: string = "") { - const bubbleHeight = 50; const bubblePadding = 10; const bubbleWidth = bubblePadding * 2 + text.length * 10; @@ -49,15 +47,24 @@ export class SpeechBubble { this.bubble.lineBetween(point2X, point2Y, point3X, point3Y); this.bubble.lineBetween(point1X, point1Y, point3X, point3Y); - this.content = scene.add.text(0, 0, text, { fontFamily: 'Arial', fontSize: '20', color: '#000000', align: 'center', wordWrap: { width: bubbleWidth - (bubblePadding * 2) } }); + this.content = scene.add.text(0, 0, text, { + fontFamily: "Arial", + fontSize: "20", + color: "#000000", + align: "center", + wordWrap: { width: bubbleWidth - bubblePadding * 2 }, + }); player.add(this.content); const bounds = this.content.getBounds(); - this.content.setPosition(this.bubble.x + (bubbleWidth / 2) - (bounds.width / 2), this.bubble.y + (bubbleHeight / 2) - (bounds.height / 2)); + this.content.setPosition( + this.bubble.x + bubbleWidth / 2 - bounds.width / 2, + this.bubble.y + bubbleHeight / 2 - bounds.height / 2 + ); } destroy(): void { - this.bubble.setVisible(false) //todo find a better way + this.bubble.setVisible(false); //todo find a better way this.bubble.destroy(); this.content.destroy(); } diff --git a/front/src/Phaser/Entity/Sprite.ts b/front/src/Phaser/Entity/Sprite.ts index f2abad52..3ef73e7c 100644 --- a/front/src/Phaser/Entity/Sprite.ts +++ b/front/src/Phaser/Entity/Sprite.ts @@ -1,8 +1,7 @@ export class Sprite extends Phaser.GameObjects.Sprite { - constructor(scene: Phaser.Scene, x: number, y: number, texture: string, frame?: number | string) { super(scene, x, y, texture, frame); scene.sys.updateList.add(this); scene.sys.displayList.add(this); } -} \ No newline at end of file +} diff --git a/front/src/Phaser/Game/SoundManager.ts b/front/src/Phaser/Game/SoundManager.ts index 47614fca..cf1c165a 100644 --- a/front/src/Phaser/Game/SoundManager.ts +++ b/front/src/Phaser/Game/SoundManager.ts @@ -4,35 +4,39 @@ import BaseSound = Phaser.Sound.BaseSound; import SoundConfig = Phaser.Types.Sound.SoundConfig; class SoundManager { - private soundPromises : Map> = new Map>(); - public loadSound (loadPlugin: LoaderPlugin, soundManager : BaseSoundManager, soundUrl: string) : Promise { - let soundPromise = this.soundPromises.get(soundUrl); + private soundPromises: Map> = new Map>(); + public loadSound(loadPlugin: LoaderPlugin, soundManager: BaseSoundManager, soundUrl: string): Promise { + let soundPromise = this.soundPromises.get(soundUrl); if (soundPromise !== undefined) { return soundPromise; } - soundPromise = new Promise((res) => { - + soundPromise = new Promise((res) => { const sound = soundManager.get(soundUrl); if (sound !== null) { return res(sound); } loadPlugin.audio(soundUrl, soundUrl); - loadPlugin.once('filecomplete-audio-' + soundUrl, () => { + loadPlugin.once("filecomplete-audio-" + soundUrl, () => { res(soundManager.add(soundUrl)); }); loadPlugin.start(); }); - this.soundPromises.set(soundUrl,soundPromise); + this.soundPromises.set(soundUrl, soundPromise); return soundPromise; } - public async playSound(loadPlugin: LoaderPlugin, soundManager : BaseSoundManager, soundUrl: string, config: SoundConfig|undefined) : Promise { - const sound = await this.loadSound(loadPlugin,soundManager,soundUrl); + public async playSound( + loadPlugin: LoaderPlugin, + soundManager: BaseSoundManager, + soundUrl: string, + config: SoundConfig | undefined + ): Promise { + const sound = await this.loadSound(loadPlugin, soundManager, soundUrl); if (config === undefined) sound.play(); else sound.play(config); } - public stopSound(soundManager : BaseSoundManager,soundUrl : string){ + public stopSound(soundManager: BaseSoundManager, soundUrl: string) { soundManager.get(soundUrl).stop(); } } diff --git a/front/src/Phaser/Items/ActionableItem.ts b/front/src/Phaser/Items/ActionableItem.ts index 7c7090b0..44b633ed 100644 --- a/front/src/Phaser/Items/ActionableItem.ts +++ b/front/src/Phaser/Items/ActionableItem.ts @@ -3,17 +3,23 @@ * It has coordinates and an "activation radius" */ import Sprite = Phaser.GameObjects.Sprite; -import type {GameScene} from "../Game/GameScene"; +import type { GameScene } from "../Game/GameScene"; import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js"; type EventCallback = (state: unknown, parameters: unknown) => void; export class ActionableItem { - private readonly activationRadiusSquared : number; + private readonly activationRadiusSquared: number; private isSelectable: boolean = false; private callbacks: Map> = new Map>(); - public constructor(private id: number, private sprite: Sprite, private eventHandler: GameScene, private activationRadius: number, private onActivateCallback: (item: ActionableItem) => void) { + public constructor( + private id: number, + private sprite: Sprite, + private eventHandler: GameScene, + private activationRadius: number, + private onActivateCallback: (item: ActionableItem) => void + ) { this.activationRadiusSquared = activationRadius * activationRadius; } @@ -25,8 +31,8 @@ export class ActionableItem { * Returns the square of the distance to the object center IF we are in item action range * OR null if we are out of range. */ - public actionableDistance(x: number, y: number): number|null { - const distanceSquared = (x - this.sprite.x)*(x - this.sprite.x) + (y - this.sprite.y)*(y - this.sprite.y); + public actionableDistance(x: number, y: number): number | null { + const distanceSquared = (x - this.sprite.x) * (x - this.sprite.x) + (y - this.sprite.y) * (y - this.sprite.y); if (distanceSquared < this.activationRadiusSquared) { return distanceSquared; } else { @@ -45,7 +51,7 @@ export class ActionableItem { this.getOutlinePlugin()?.add(this.sprite, { thickness: 2, - outlineColor: 0xffff00 + outlineColor: 0xffff00, }); } @@ -60,8 +66,8 @@ export class ActionableItem { this.getOutlinePlugin()?.remove(this.sprite); } - private getOutlinePlugin(): OutlinePipelinePlugin|undefined { - return this.sprite.scene.plugins.get('rexOutlinePipeline') as unknown as OutlinePipelinePlugin|undefined; + private getOutlinePlugin(): OutlinePipelinePlugin | undefined { + return this.sprite.scene.plugins.get("rexOutlinePipeline") as unknown as OutlinePipelinePlugin | undefined; } /** @@ -78,7 +84,7 @@ export class ActionableItem { } public on(eventName: string, callback: EventCallback): void { - let callbacksArray: Array|undefined = this.callbacks.get(eventName); + let callbacksArray: Array | undefined = this.callbacks.get(eventName); if (callbacksArray === undefined) { callbacksArray = new Array(); this.callbacks.set(eventName, callbacksArray); diff --git a/front/src/Phaser/Items/Computer/computer.ts b/front/src/Phaser/Items/Computer/computer.ts index 8240d904..4665c546 100644 --- a/front/src/Phaser/Items/Computer/computer.ts +++ b/front/src/Phaser/Items/Computer/computer.ts @@ -1,86 +1,91 @@ -import * as Phaser from 'phaser'; -import {Scene} from "phaser"; +import * as Phaser from "phaser"; +import { Scene } from "phaser"; import Sprite = Phaser.GameObjects.Sprite; -import type {ITiledMapObject} from "../../Map/ITiledMap"; -import type {ItemFactoryInterface} from "../ItemFactoryInterface"; -import type {GameScene} from "../../Game/GameScene"; -import {ActionableItem} from "../ActionableItem"; +import type { ITiledMapObject } from "../../Map/ITiledMap"; +import type { ItemFactoryInterface } from "../ItemFactoryInterface"; +import type { GameScene } from "../../Game/GameScene"; +import { ActionableItem } from "../ActionableItem"; import * as tg from "generic-type-guard"; -const isComputerState = - new tg.IsInterface().withProperties({ +const isComputerState = new tg.IsInterface() + .withProperties({ status: tg.isString, - }).get(); + }) + .get(); type ComputerState = tg.GuardedType; let state: ComputerState = { - 'status': 'off' + status: "off", }; export default { preload: (loader: Phaser.Loader.LoaderPlugin): void => { - loader.atlas('computer', '/resources/items/computer/computer.png', '/resources/items/computer/computer_atlas.json'); + loader.atlas( + "computer", + "/resources/items/computer/computer.png", + "/resources/items/computer/computer_atlas.json" + ); }, create: (scene: GameScene): void => { scene.anims.create({ - key: 'computer_off', + key: "computer_off", frames: [ { - key: 'computer', - frame: 'computer_off' - } + key: "computer", + frame: "computer_off", + }, ], frameRate: 10, - repeat: -1 + repeat: -1, }); scene.anims.create({ - key: 'computer_run', + key: "computer_run", frames: [ - { - key: 'computer', - frame: 'computer_on1' - }, - { - key: 'computer', - frame: 'computer_on2' - } - ], + { + key: "computer", + frame: "computer_on1", + }, + { + key: "computer", + frame: "computer_on2", + }, + ], frameRate: 5, - repeat: -1 + repeat: -1, }); }, factory: (scene: GameScene, object: ITiledMapObject, initState: unknown): ActionableItem => { if (initState !== undefined) { if (!isComputerState(initState)) { - throw new Error('Invalid state received for computer object'); + throw new Error("Invalid state received for computer object"); } state = initState; } // Idée: ESSAYER WebPack? https://paultavares.wordpress.com/2018/07/02/webpack-how-to-generate-an-es-module-bundle/ - const computer = new Sprite(scene, object.x, object.y, 'computer'); + const computer = new Sprite(scene, object.x, object.y, "computer"); scene.add.existing(computer); - if (state.status === 'on') { - computer.anims.play('computer_run'); + if (state.status === "on") { + computer.anims.play("computer_run"); } const item = new ActionableItem(object.id, computer, scene, 32, (item: ActionableItem) => { - if (state.status === 'off') { - state.status = 'on'; - item.emit('TURN_ON', state); + if (state.status === "off") { + state.status = "on"; + item.emit("TURN_ON", state); } else { - state.status = 'off'; - item.emit('TURN_OFF', state); + state.status = "off"; + item.emit("TURN_OFF", state); } }); - item.on('TURN_ON', () => { - computer.anims.play('computer_run'); + item.on("TURN_ON", () => { + computer.anims.play("computer_run"); }); - item.on('TURN_OFF', () => { - computer.anims.play('computer_off'); + item.on("TURN_OFF", () => { + computer.anims.play("computer_off"); }); return item; //scene.add.sprite(object.x, object.y, 'computer'); - } + }, } as ItemFactoryInterface; diff --git a/front/src/Phaser/Items/ItemFactoryInterface.ts b/front/src/Phaser/Items/ItemFactoryInterface.ts index deff8fbb..fa7e7459 100644 --- a/front/src/Phaser/Items/ItemFactoryInterface.ts +++ b/front/src/Phaser/Items/ItemFactoryInterface.ts @@ -1,6 +1,6 @@ -import type {GameScene} from "../Game/GameScene"; -import type {ITiledMapObject} from "../Map/ITiledMap"; -import type {ActionableItem} from "./ActionableItem"; +import type { GameScene } from "../Game/GameScene"; +import type { ITiledMapObject } from "../Map/ITiledMap"; +import type { ActionableItem } from "./ActionableItem"; import LoaderPlugin = Phaser.Loader.LoaderPlugin; export interface ItemFactoryInterface { diff --git a/front/src/Phaser/Login/AbstractCharacterScene.ts b/front/src/Phaser/Login/AbstractCharacterScene.ts index 0d3a7c3b..6376498a 100644 --- a/front/src/Phaser/Login/AbstractCharacterScene.ts +++ b/front/src/Phaser/Login/AbstractCharacterScene.ts @@ -1,14 +1,13 @@ -import {ResizableScene} from "./ResizableScene"; -import {localUserStore} from "../../Connexion/LocalUserStore"; -import type {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures"; -import {loadCustomTexture} from "../Entity/PlayerTexturesLoadingManager"; -import type {CharacterTexture} from "../../Connexion/LocalUser"; +import { ResizableScene } from "./ResizableScene"; +import { localUserStore } from "../../Connexion/LocalUserStore"; +import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures"; +import { loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager"; +import type { CharacterTexture } from "../../Connexion/LocalUser"; export abstract class AbstractCharacterScene extends ResizableScene { - - loadCustomSceneSelectCharacters() : Promise { + loadCustomSceneSelectCharacters(): Promise { const textures = this.getTextures(); - const promises : Promise[] = []; + const promises: Promise[] = []; if (textures) { for (const texture of textures) { if (texture.level === -1) { @@ -17,10 +16,10 @@ export abstract class AbstractCharacterScene extends ResizableScene { promises.push(loadCustomTexture(this.load, texture)); } } - return Promise.all(promises) + return Promise.all(promises); } - loadSelectSceneCharacters() : Promise { + loadSelectSceneCharacters(): Promise { const textures = this.getTextures(); const promises: Promise[] = []; if (textures) { @@ -31,10 +30,10 @@ export abstract class AbstractCharacterScene extends ResizableScene { promises.push(loadCustomTexture(this.load, texture)); } } - return Promise.all(promises) + return Promise.all(promises); } - private getTextures() : CharacterTexture[]|undefined{ + private getTextures(): CharacterTexture[] | undefined { const localUser = localUserStore.getLocalUser(); return localUser?.textures; } diff --git a/front/src/Phaser/Login/ResizableScene.ts b/front/src/Phaser/Login/ResizableScene.ts index d06cb66c..90613744 100644 --- a/front/src/Phaser/Login/ResizableScene.ts +++ b/front/src/Phaser/Login/ResizableScene.ts @@ -1,4 +1,4 @@ -import {Scene} from "phaser"; +import { Scene } from "phaser"; import DOMElement = Phaser.GameObjects.DOMElement; export abstract class ResizableScene extends Scene { @@ -11,13 +11,10 @@ export abstract class ResizableScene extends Scene { * @param defaultWidth The width of the DOM element. We try to compute it but it may not be available if called from "create". */ public centerXDomElement(object: DOMElement, defaultWidth: number): void { - object.x = (this.scale.width / 2) - - ( - object - && object.node - && object.node.getBoundingClientRect().width > 0 - ? (object.node.getBoundingClientRect().width / 2 / this.scale.zoom) - : (defaultWidth / this.scale.zoom) - ); + object.x = + this.scale.width / 2 - + (object && object.node && object.node.getBoundingClientRect().width > 0 + ? object.node.getBoundingClientRect().width / 2 / this.scale.zoom + : defaultWidth / this.scale.zoom); } } diff --git a/front/src/Phaser/Login/SelectCharacterMobileScene.ts b/front/src/Phaser/Login/SelectCharacterMobileScene.ts index 0d8e49d5..c04d6fb3 100644 --- a/front/src/Phaser/Login/SelectCharacterMobileScene.ts +++ b/front/src/Phaser/Login/SelectCharacterMobileScene.ts @@ -1,14 +1,13 @@ import { SelectCharacterScene } from "./SelectCharacterScene"; export class SelectCharacterMobileScene extends SelectCharacterScene { - - create(){ + create() { super.create(); this.onResize(); this.selectedRectangle.destroy(); } - protected defineSetupPlayer(num: number){ + protected defineSetupPlayer(num: number) { const deltaX = 30; const deltaY = 2; let [playerX, playerY] = this.getCharacterPosition(); @@ -16,48 +15,44 @@ export class SelectCharacterMobileScene extends SelectCharacterScene { let playerScale = 1.5; let playerOpacity = 1; - if( this.currentSelectUser !== num ){ + if (this.currentSelectUser !== num) { playerVisible = false; } - if( num === (this.currentSelectUser + 1) ){ + if (num === this.currentSelectUser + 1) { playerY -= deltaY; playerX += deltaX; playerScale = 0.8; playerOpacity = 0.6; playerVisible = true; } - if( num === (this.currentSelectUser + 2) ){ + if (num === this.currentSelectUser + 2) { playerY -= deltaY; - playerX += (deltaX * 2); + playerX += deltaX * 2; playerScale = 0.8; playerOpacity = 0.6; playerVisible = true; } - if( num === (this.currentSelectUser - 1) ){ + if (num === this.currentSelectUser - 1) { playerY -= deltaY; playerX -= deltaX; playerScale = 0.8; playerOpacity = 0.6; playerVisible = true; } - if( num === (this.currentSelectUser - 2) ){ + if (num === this.currentSelectUser - 2) { playerY -= deltaY; - playerX -= (deltaX * 2); + playerX -= deltaX * 2; playerScale = 0.8; playerOpacity = 0.6; playerVisible = true; } - return {playerX, playerY, playerScale, playerOpacity, playerVisible} + return { playerX, playerY, playerScale, playerOpacity, playerVisible }; } - /** + /** * Returns pixel position by on column and row number */ - protected getCharacterPosition(): [number, number] { - return [ - this.game.renderer.width / 2, - this.game.renderer.height / 3 - ]; - } - + protected getCharacterPosition(): [number, number] { + return [this.game.renderer.width / 2, this.game.renderer.height / 3]; + } } diff --git a/front/src/Phaser/Player/Animation.ts b/front/src/Phaser/Player/Animation.ts index ea8d2308..cf13e087 100644 --- a/front/src/Phaser/Player/Animation.ts +++ b/front/src/Phaser/Player/Animation.ts @@ -1,13 +1,10 @@ - export enum PlayerAnimationDirections { - Down = 'down', - Left = 'left', - Up = 'up', - Right = 'right', + Down = "down", + Left = "left", + Up = "up", + Right = "right", } export enum PlayerAnimationTypes { - Walk = 'walk', - Idle = 'idle', + Walk = "walk", + Idle = "idle", } - - diff --git a/front/src/Phaser/Reconnecting/WAError.ts b/front/src/Phaser/Reconnecting/WAError.ts index cdc433b6..abc71f6c 100644 --- a/front/src/Phaser/Reconnecting/WAError.ts +++ b/front/src/Phaser/Reconnecting/WAError.ts @@ -3,13 +3,13 @@ export class WAError extends Error { private _subTitle: string; private _details: string; - constructor (title: string, subTitle: string, details: string) { - super(title+' - '+subTitle+' - '+details); + constructor(title: string, subTitle: string, details: string) { + super(title + " - " + subTitle + " - " + details); this._title = title; this._subTitle = subTitle; this._details = details; // Set the prototype explicitly. - Object.setPrototypeOf (this, WAError.prototype); + Object.setPrototypeOf(this, WAError.prototype); } get title(): string { diff --git a/front/src/Phaser/Services/HdpiManager.ts b/front/src/Phaser/Services/HdpiManager.ts index 33f7e3a8..116f6816 100644 --- a/front/src/Phaser/Services/HdpiManager.ts +++ b/front/src/Phaser/Services/HdpiManager.ts @@ -1,4 +1,3 @@ - interface Size { width: number; height: number; @@ -23,14 +22,14 @@ export class HdpiManager { * * @param realPixelScreenSize */ - public getOptimalGameSize(realPixelScreenSize: Size): { game: Size, real: Size } { + public getOptimalGameSize(realPixelScreenSize: Size): { game: Size; real: Size } { const realPixelNumber = realPixelScreenSize.width * realPixelScreenSize.height; // If the screen has not a definition small enough to match the minimum number of pixels we want to display, // let's make the canvas the size of the screen (in real pixels) if (realPixelNumber <= this.minRecommendedGamePixelsNumber) { return { game: realPixelScreenSize, - real: realPixelScreenSize + real: realPixelScreenSize, }; } @@ -49,8 +48,8 @@ export class HdpiManager { real: { width: realPixelScreenSize.width, height: realPixelScreenSize.height, - } - } + }, + }; } const gameWidth = Math.ceil(realPixelScreenSize.width / optimalZoomLevel / this._zoomModifier); @@ -58,8 +57,12 @@ export class HdpiManager { // Let's ensure we display a minimum of pixels, even if crazily zoomed in. if (gameWidth * gameHeight < this.absoluteMinPixelNumber) { - const minGameHeight = Math.sqrt(this.absoluteMinPixelNumber * realPixelScreenSize.height / realPixelScreenSize.width); - const minGameWidth = Math.sqrt(this.absoluteMinPixelNumber * realPixelScreenSize.width / realPixelScreenSize.height); + const minGameHeight = Math.sqrt( + (this.absoluteMinPixelNumber * realPixelScreenSize.height) / realPixelScreenSize.width + ); + const minGameWidth = Math.sqrt( + (this.absoluteMinPixelNumber * realPixelScreenSize.width) / realPixelScreenSize.height + ); // Let's reset the zoom modifier (WARNING this is a SIDE EFFECT in a getter) this._zoomModifier = realPixelScreenSize.width / minGameWidth / optimalZoomLevel; @@ -72,9 +75,8 @@ export class HdpiManager { real: { width: realPixelScreenSize.width, height: realPixelScreenSize.height, - } - } - + }, + }; } return { @@ -85,8 +87,8 @@ export class HdpiManager { real: { width: Math.ceil(realPixelScreenSize.width / optimalZoomLevel) * optimalZoomLevel, height: Math.ceil(realPixelScreenSize.height / optimalZoomLevel) * optimalZoomLevel, - } - } + }, + }; } /** @@ -95,7 +97,7 @@ export class HdpiManager { private getOptimalZoomLevel(realPixelNumber: number): number { const result = Math.sqrt(realPixelNumber / this.minRecommendedGamePixelsNumber); if (1.5 <= result && result < 2) { - return 1.5 + return 1.5; } else { return Math.floor(result); } diff --git a/front/src/Phaser/Services/WaScaleManager.ts b/front/src/Phaser/Services/WaScaleManager.ts index abfd2a8b..5ceaeb71 100644 --- a/front/src/Phaser/Services/WaScaleManager.ts +++ b/front/src/Phaser/Services/WaScaleManager.ts @@ -1,10 +1,9 @@ -import {HdpiManager} from "./HdpiManager"; +import { HdpiManager } from "./HdpiManager"; import ScaleManager = Phaser.Scale.ScaleManager; -import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager"; -import type {Game} from "../Game/Game"; -import {ResizableScene} from "../Login/ResizableScene"; -import {HtmlUtils} from "../../WebRtc/HtmlUtils"; - +import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; +import type { Game } from "../Game/Game"; +import { ResizableScene } from "../Login/ResizableScene"; +import { HtmlUtils } from "../../WebRtc/HtmlUtils"; class WaScaleManager { private hdpiManager: HdpiManager; @@ -23,26 +22,29 @@ class WaScaleManager { } public applyNewSize() { - const {width, height} = coWebsiteManager.getGameSize(); + const { width, height } = coWebsiteManager.getGameSize(); let devicePixelRatio = 1; if (window.devicePixelRatio) { devicePixelRatio = window.devicePixelRatio; } - const { game: gameSize, real: realSize } = this.hdpiManager.getOptimalGameSize({width: width * devicePixelRatio, height: height * devicePixelRatio}); + const { game: gameSize, real: realSize } = this.hdpiManager.getOptimalGameSize({ + width: width * devicePixelRatio, + height: height * devicePixelRatio, + }); this.actualZoom = realSize.width / gameSize.width / devicePixelRatio; - this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio) + this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio); this.scaleManager.resize(gameSize.width, gameSize.height); // Override bug in canvas resizing in Phaser. Let's resize the canvas ourselves const style = this.scaleManager.canvas.style; - style.width = Math.ceil(realSize.width / devicePixelRatio) + 'px'; - style.height = Math.ceil(realSize.height / devicePixelRatio) + 'px'; + style.width = Math.ceil(realSize.width / devicePixelRatio) + "px"; + style.height = Math.ceil(realSize.height / devicePixelRatio) + "px"; // Resize the game element at the same size at the canvas - const gameStyle = HtmlUtils.getElementByIdOrFail('game').style; + const gameStyle = HtmlUtils.getElementByIdOrFail("game").style; gameStyle.width = style.width; gameStyle.height = style.height; @@ -70,7 +72,7 @@ class WaScaleManager { this._saveZoom = this.hdpiManager.zoomModifier; } - public restoreZoom(): void{ + public restoreZoom(): void { this.hdpiManager.zoomModifier = this._saveZoom; this.applyNewSize(); } @@ -81,7 +83,6 @@ class WaScaleManager { public get uiScalingFactor(): number { return this.actualZoom > 1 ? 1 : 1.2; } - } -export const waScaleManager = new WaScaleManager(640*480, 196*196); +export const waScaleManager = new WaScaleManager(640 * 480, 196 * 196); diff --git a/front/src/Phaser/UserInput/PinchManager.ts b/front/src/Phaser/UserInput/PinchManager.ts index 3174c6ad..47d5716b 100644 --- a/front/src/Phaser/UserInput/PinchManager.ts +++ b/front/src/Phaser/UserInput/PinchManager.ts @@ -1,6 +1,6 @@ -import {Pinch} from "phaser3-rex-plugins/plugins/gestures.js"; -import {waScaleManager} from "../Services/WaScaleManager"; -import {GameScene} from "../Game/GameScene"; +import { Pinch } from "phaser3-rex-plugins/plugins/gestures.js"; +import { waScaleManager } from "../Services/WaScaleManager"; +import { GameScene } from "../Game/GameScene"; export class PinchManager { private scene: Phaser.Scene; @@ -15,18 +15,18 @@ export class PinchManager { // We are smoothing its value with previous values to prevent the flicking. let smoothPinch = 1; - this.pinch.on('pinchstart', () => { + this.pinch.on("pinchstart", () => { smoothPinch = 1; }); - - this.pinch.on('pinch', (pinch:any) => { // eslint-disable-line + // eslint-disable-next-line + this.pinch.on("pinch", (pinch: any) => { if (pinch.scaleFactor > 1.2 || pinch.scaleFactor < 0.8) { // Pinch too fast! Probably a bad measure. return; } - smoothPinch = 3/5*smoothPinch + 2/5*pinch.scaleFactor; + smoothPinch = (3 / 5) * smoothPinch + (2 / 5) * pinch.scaleFactor; if (this.scene instanceof GameScene) { this.scene.zoomByFactor(smoothPinch); } else { diff --git a/front/src/Stores/ConsoleGlobalMessageManagerStore.ts b/front/src/Stores/ConsoleGlobalMessageManagerStore.ts index 1fa04bfe..01534766 100644 --- a/front/src/Stores/ConsoleGlobalMessageManagerStore.ts +++ b/front/src/Stores/ConsoleGlobalMessageManagerStore.ts @@ -2,4 +2,4 @@ import { writable } from "svelte/store"; export const consoleGlobalMessageManagerVisibleStore = writable(false); -export const consoleGlobalMessageManagerFocusStore = writable(false); \ No newline at end of file +export const consoleGlobalMessageManagerFocusStore = writable(false); diff --git a/front/src/Stores/ErrorStore.ts b/front/src/Stores/ErrorStore.ts index 2f1e3e40..b7fb2e31 100644 --- a/front/src/Stores/ErrorStore.ts +++ b/front/src/Stores/ErrorStore.ts @@ -1,4 +1,4 @@ -import {writable} from "svelte/store"; +import { writable } from "svelte/store"; /** * A store that contains a list of error messages to be displayed. @@ -8,7 +8,7 @@ function createErrorStore() { return { subscribe, - addErrorMessage: (e: string|Error): void => { + addErrorMessage: (e: string | Error): void => { update((messages: string[]) => { let message: string; if (e instanceof Error) { @@ -26,7 +26,7 @@ function createErrorStore() { }, clearMessages: (): void => { set([]); - } + }, }; } diff --git a/front/src/Stores/Errors/BrowserTooOldError.ts b/front/src/Stores/Errors/BrowserTooOldError.ts index bf934443..92409335 100644 --- a/front/src/Stores/Errors/BrowserTooOldError.ts +++ b/front/src/Stores/Errors/BrowserTooOldError.ts @@ -1,8 +1,10 @@ export class BrowserTooOldError extends Error { - static NAME = 'BrowserTooOldError'; + static NAME = "BrowserTooOldError"; constructor() { - super('Unable to access your camera or microphone. Your browser is too old. Please consider upgrading your browser or try using a recent version of Chrome.'); + super( + "Unable to access your camera or microphone. Your browser is too old. Please consider upgrading your browser or try using a recent version of Chrome." + ); this.name = BrowserTooOldError.NAME; } } diff --git a/front/src/Stores/Errors/WebviewOnOldIOS.ts b/front/src/Stores/Errors/WebviewOnOldIOS.ts index 06c03f0e..42370237 100644 --- a/front/src/Stores/Errors/WebviewOnOldIOS.ts +++ b/front/src/Stores/Errors/WebviewOnOldIOS.ts @@ -1,8 +1,10 @@ export class WebviewOnOldIOS extends Error { - static NAME = 'WebviewOnOldIOS'; + static NAME = "WebviewOnOldIOS"; constructor() { - super('Your iOS version cannot use video/audio in the browser unless you are using Safari. Please switch to Safari or upgrade iOS to 14.3 or above.'); + super( + "Your iOS version cannot use video/audio in the browser unless you are using Safari. Please switch to Safari or upgrade iOS to 14.3 or above." + ); this.name = WebviewOnOldIOS.NAME; } } diff --git a/front/src/Stores/SelectCharacterStore.ts b/front/src/Stores/SelectCharacterStore.ts index 094eaef3..0c84a031 100644 --- a/front/src/Stores/SelectCharacterStore.ts +++ b/front/src/Stores/SelectCharacterStore.ts @@ -1,3 +1,3 @@ import { derived, writable, Writable } from "svelte/store"; -export const selectCharacterSceneVisibleStore = writable(false); \ No newline at end of file +export const selectCharacterSceneVisibleStore = writable(false); diff --git a/front/src/Stores/SoundPlayingStore.ts b/front/src/Stores/SoundPlayingStore.ts index cf1d681c..36fd5d77 100644 --- a/front/src/Stores/SoundPlayingStore.ts +++ b/front/src/Stores/SoundPlayingStore.ts @@ -4,7 +4,7 @@ import { writable } from "svelte/store"; * A store that contains the URL of the sound currently playing */ function createSoundPlayingStore() { - const { subscribe, set, update } = writable(null); + const { subscribe, set, update } = writable(null); return { subscribe, @@ -13,9 +13,7 @@ function createSoundPlayingStore() { }, soundEnded: () => { set(null); - } - - + }, }; } diff --git a/front/src/Touch/TouchScreenManager.ts b/front/src/Touch/TouchScreenManager.ts index dcb56ded..ee2a135a 100644 --- a/front/src/Touch/TouchScreenManager.ts +++ b/front/src/Touch/TouchScreenManager.ts @@ -1,16 +1,14 @@ - class TouchScreenManager { - - readonly supportTouchScreen:boolean; - + readonly supportTouchScreen: boolean; + constructor() { this.supportTouchScreen = this.detectTouchscreen(); } //found here: https://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript#4819886 detectTouchscreen(): boolean { - return (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)); + return "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; } } -export const touchScreenManager = new TouchScreenManager(); \ No newline at end of file +export const touchScreenManager = new TouchScreenManager(); diff --git a/front/src/WebRtc/DeviceUtils.ts b/front/src/WebRtc/DeviceUtils.ts index 91a3dc31..5113fc72 100644 --- a/front/src/WebRtc/DeviceUtils.ts +++ b/front/src/WebRtc/DeviceUtils.ts @@ -1,12 +1,9 @@ export function isIOS(): boolean { - return [ - 'iPad Simulator', - 'iPhone Simulator', - 'iPod Simulator', - 'iPad', - 'iPhone', - 'iPod' - ].includes(navigator.platform) + return ( + ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"].includes( + navigator.platform + ) || // iPad on iOS 13 detection - || (navigator.userAgent.includes("Mac") && "ontouchend" in document) + (navigator.userAgent.includes("Mac") && "ontouchend" in document) + ); } diff --git a/front/src/rex-plugins.d.ts b/front/src/rex-plugins.d.ts index 8c8a9fc1..9884d425 100644 --- a/front/src/rex-plugins.d.ts +++ b/front/src/rex-plugins.d.ts @@ -1,16 +1,16 @@ -declare module 'phaser3-rex-plugins/plugins/virtualjoystick.js' { +declare module "phaser3-rex-plugins/plugins/virtualjoystick.js" { const content: any; // eslint-disable-line export default content; } -declare module 'phaser3-rex-plugins/plugins/gestures-plugin.js' { +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' { +declare module "phaser3-rex-plugins/plugins/webfontloader-plugin.js" { const content: any; // eslint-disable-line export default content; } -declare module 'phaser3-rex-plugins/plugins/outlinepipeline-plugin.js' { +declare module "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js" { import GameObject = Phaser.GameObjects.GameObject; class OutlinePipelinePlugin { @@ -21,6 +21,6 @@ declare module 'phaser3-rex-plugins/plugins/outlinepipeline-plugin.js' { export default OutlinePipelinePlugin; } -declare module 'phaser3-rex-plugins/plugins/gestures.js' { +declare module "phaser3-rex-plugins/plugins/gestures.js" { export const Pinch: any; // eslint-disable-line } From 76362e81e8dc3359b099ea26a6ede96196c58e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 6 Sep 2021 16:06:49 +0200 Subject: [PATCH 16/16] Adding a dedicated doc for variables --- docs/maps/api-state.md | 41 +++-------------------------- docs/maps/variables.md | 59 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 37 deletions(-) create mode 100644 docs/maps/variables.md diff --git a/docs/maps/api-state.md b/docs/maps/api-state.md index 1cc4f7fb..a8ee5589 100644 --- a/docs/maps/api-state.md +++ b/docs/maps/api-state.md @@ -14,7 +14,7 @@ WA.state.onVariableChange(key : string).subscribe((data: unknown) => {}) : Subsc WA.state.[any property]: unknown ``` -These methods and properties can be used to save, load and track changes in variables related to the current room. +These methods and properties can be used to save, load and track changes in [variables related to the current room](variables.md). Variables stored in `WA.state` can be any value that is serializable in JSON. @@ -63,44 +63,11 @@ that you get the expected type). For security reasons, the list of variables you are allowed to access and modify is **restricted** (otherwise, anyone on your map could set any data). Variables storage is subject to an authorization process. Read below to learn more. -### Declaring allowed keys +## Defining a variable -In order to declare allowed keys related to a room, you need to add **objects** in an "object layer" of the map. - -Each object will represent a variable. - -
-
- -
-
- -The name of the variable is the name of the object. -The object **type** MUST be **variable**. - -You can set a default value for the object in the `default` property. - -### Persisting variables state - -Use the `persist` property to save the state of the variable in database. If `persist` is false, the variable will stay -in the memory of the WorkAdventure servers but will be wiped out of the memory as soon as the room is empty (or if the -server restarts). - -{.alert.alert-info} -Do not use `persist` for highly dynamic values that have a short life spawn. - -### Managing access rights to variables - -With `readableBy` and `writableBy`, you control who can read of write in this variable. The property accepts a string -representing a "tag". Anyone having this "tag" can read/write in the variable. - -{.alert.alert-warning} -`readableBy` and `writableBy` are specific to the "online" version of WorkAdventure because the notion of tags -is not available unless you have an "admin" server (that is not part of the self-hosted version of WorkAdventure). - -Finally, the `jsonSchema` property can contain [a complete JSON schema](https://json-schema.org/) to validate the content of the variable. -Trying to set a variable to a value that is not compatible with the schema will fail. +Out of the box, you cannot edit *any* variable. Variables MUST be declared in the map. +Check the [dedicated variables page](variables.md) to learn how to declare a variable in a map. ## Tracking variables changes diff --git a/docs/maps/variables.md b/docs/maps/variables.md new file mode 100644 index 00000000..17e803d9 --- /dev/null +++ b/docs/maps/variables.md @@ -0,0 +1,59 @@ +{.section-title.accent.text-primary} +# Variables + +Maps can contain **variables**. Variables are piece of information that store some data. In computer science, we like +to say variables are storing the "state" of the room. + +- Variables are shared amongst all players in a given room. When the value of a variable changes for one player, it changes + for everyone. +- Variables are **invisible**. There are plenty of ways they can act on the room, but by default, you don't see them. + +## Declaring a variable + +In order to declare allowed variables in a room, you need to add **objects** in an "object layer" of the map. + +Each object will represent a variable. + +
+
+ +
+
+ +The name of the variable is the name of the object. +The object **type** MUST be **variable**. + +You can set a default value for the object in the `default` property. + +## Persisting variables state + +Use the `persist` property to save the state of the variable in database. If `persist` is false, the variable will stay +in the memory of the WorkAdventure servers but will be wiped out of the memory as soon as the room is empty (or if the +server restarts). + +{.alert.alert-info} +Do not use `persist` for highly dynamic values that have a short life spawn. + +## Managing access rights to variables + +With `readableBy` and `writableBy`, you control who can read of write in this variable. The property accepts a string +representing a "tag". Anyone having this "tag" can read/write in the variable. + +{.alert.alert-warning} +`readableBy` and `writableBy` are specific to the "online" version of WorkAdventure because the notion of tags +is not available unless you have an "admin" server (that is not part of the self-hosted version of WorkAdventure). + +In a future release, the `jsonSchema` property will contain [a complete JSON schema](https://json-schema.org/) to validate the content of the variable. +Trying to set a variable to a value that is not compatible with the schema will fail. + +## Using variables + +There are plenty of ways to use variables in WorkAdventure: + +- Using the [scripting API](api-state.md), you can read, edit or track the content of variables. +- Using the [Action zones](https://workadventu.re/map-building-extra/generic-action-zones.md), you can set the value of a variable when someone is entering or leaving a zone +- By [binding variable values to properties in the map](https://workadventu.re/map-building-extra/variable-to-property-binding.md) +- By [using automatically generated configuration screens](https://workadventu.re/map-building-extra/automatic-configuration.md) to create forms to edit the value of variables + +In general, variables can be used by third party libraries that you can embed in your map to add extra features. +A good example of such a library is the ["Scripting API Extra" library](https://workadventu.re/map-building-extra/about.md)