From 45e254b93177f402d0781412d7daeed130025eb3 Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Wed, 13 Apr 2022 14:31:18 +0200 Subject: [PATCH 01/72] visible indicator for hero. Using images in order to fix graphic circles glitching out during movement --- .../icons/icon_status_indicator_inside.png | Bin 0 -> 123 bytes .../icons/icon_status_indicator_outline.png | Bin 0 -> 5422 bytes .../src/Phaser/Components/PlayerStatusDot.ts | 51 ++- front/src/Phaser/Entity/Character.ts | 6 +- front/src/Phaser/Game/GameScene.ts | 7 +- front/src/Phaser/Game/PlayerMovement.ts | 1 - front/src/Phaser/Helpers/TexturesHelper.ts | 16 + front/src/Phaser/Player/Player.ts | 1 - maps/tests/index.html | 8 + maps/tests/status_indicator.json | 322 ++++++++++++++++++ 10 files changed, 389 insertions(+), 23 deletions(-) create mode 100644 front/public/resources/icons/icon_status_indicator_inside.png create mode 100644 front/public/resources/icons/icon_status_indicator_outline.png create mode 100644 maps/tests/status_indicator.json diff --git a/front/public/resources/icons/icon_status_indicator_inside.png b/front/public/resources/icons/icon_status_indicator_inside.png new file mode 100644 index 0000000000000000000000000000000000000000..29a2daad7bed626d30170202016c23836202670e GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1SHiab7}%9#^NA%Cx&(BWL|<~(j9#r85lP9 zbN@+X1@buyJR*x382Ao@Fyrz36)8YL0Z$jl5Q*^QAN?#HkN*7UXSh8<|6(j(+isv7 NgQu&X%Q~loCIJ2U9}oZl literal 0 HcmV?d00001 diff --git a/front/public/resources/icons/icon_status_indicator_outline.png b/front/public/resources/icons/icon_status_indicator_outline.png new file mode 100644 index 0000000000000000000000000000000000000000..67f86ec5dfded15555651f98b29199bf105bf95c GIT binary patch literal 5422 zcmeHKc|25m8z1S~>C!8bWg3K-eVFCWAPk14Y;`S>Gc#w##4Kh8V_Ix2s7Q+~J$@BOct&zU*rS-#Kne4pp{JLhBtEb`IU zG1Gy;VEPPSuOR4OLwRT^e|xTu_`+a6+*O2x%7TC-xL6|M^5a0bELjY~K{=lbgURnc z3ylyCkqq8-&gW{+v(4_4j80c*o_I^%9=W5;(p^&PW|r}Xy+6Hml||4zi$^Jw;k|Ao z7By#!m;bLtGt4hb=c$-8)9Ia=*x4r5wWf4eQCsuAj#eYbH+R;$-1tlJUgjC!E`BV1={mUe z)tH+@9dUY73)Q-%M&k6#w3{jBtY({DKSRH9V`+D%smL|WGivW{M^J9qdlu9E1j?0b!p5l#4RgE z?;nnOsojyrklbum$600XO`*K) zY)(Ap1wOE}INxuF?1+hPn&$LVbndjwZrkgClxj>Q%EPH}6Vg0w$Y%w!aFRr9n>3 zxu)mqdo?g^bFyfigB`g`9XU(IRq`{e1(lm4;tnxlPV*hFg+J5UyXVYk*QuStvj&#& z(UYdhgZ7Qy#RNk?JhLGAiBmf_QtOm)qo4oMs54iNFBvJ1JnCBP=DrzqTWXZCatliTwe7LoH)+HGk5oQXs~22Lt|&M`FH6(5o!d}5aQ(qk)9ydz#1};eTQkJ&MhlFH1^N?# z9$F0*b@{BBIW`H}`<_gkE*z%~)P@O{jM-g%fqgrZdwNN4Ef*MHaY4s`vGZof*)?q! zGy}K)X#eI(!HvaT_Ed*UmAN)@veV2?ACoBj8OaavqkR>3EF27nd$R`98nd-uP#0&f zyApS_`T#YzsJ9{DlG&q8vUxQYX%3@ay@|df8sLG-iv~?kevQ+mE{inC^%^eAlOD3J zz7x@as6+5_boZ=0*k!wxXBbic^A%#vhMhzA&7Mb1KF6zfKebxJtzS9ZTdN^%tuCc3 zbvXD(@wCGxi}dLWJ;iKvZ~^;3_~;Vz0rk0|TPkC7);7h}JkV8mySr|Ui{9;Jv@Mlz zn9eKBypCVkDrf4K`B=yFgn=Q6r4O!IkK@3^UFp}Pr9bxQr4-#;^y=+UEcQUWY2w6D zatPWHWspKzAL}76D68zha{PC1A>0b-XL0HRS1>f{V!dkp>e_H`U~t9*+pwM?V)`29 zg!8k`lgrzuPEtzvWlw&{SEQ{|w742a&LC6|I+`_ce{GGqP1Nb8)n7ky{9K+(vu>Hq zI^HW>l>406pFIpgYVzzG38f8JIqQz6+-h?&Ot?uH`%ff#Q%U>QoWxs4yk*DAZ<|)M z&2ne?3D(E?ybz+b`L*E>}tHBC$CN!D^MG;UAuSo^F1qTPWb#SEbY6$jG|~uY+4^W z?Bf&ZmOo_lp3E7cDaHo5N%*n(Z==@Rboh5YYY_%V7Y^Kb(d{8RyK(ga=Ml3y3vvYL z_;9HBW<`{KB`@YEo}Lu^l=*6)UZWO&a%NW$Xcsg8-SvT&rk2|GO(TwMF$mKaW<1r~ zT%a+DNqg7ewvbS^*{+gTk@7;}@-Y7GBv#)rx;I6;EN^Q=cXAjErnZ*v=^4QA^!&KX zLwkGC>O7inqq}+Y^7iafq(S13@ht(xPTAQcKjV$jB`1x;6ELSobqfhL4yc^;*oKDO z=EE5qPgEIHrNhV6`Ud;U1`)RJ(GDjw|LUo+8X2YycdL2qzYv1QsFfFjWqnxe?g-=B z<%aHBt6>*yxlgi2SsHsDJhgN^*G*5(e|_4`$M^DXz2{j?(uG8)KK;G|rvE_QVsox7 zW3H>6C4MlyDRk&o2 z`)xioe0jO))mTSDW@4CPPcVk>tB`=fibWx8MJ$`lLAbfF76UbjcF@#bXAY_9|CfH*+Lg&d$Yz!!2vNz%`%5WWBmmH|pWu`UEMi9p6+p)V1K#eOzg3QDBV zEGkj47!;1A(kL54fy#lX1(cHt0jT6qH55+?2*^Z|5RoX3hEOI2S9+=j98Uev7GJ&; zvPf3W{M6J3gYh4(J}iPbzDfm$s|J?>us;Nm0*N3;6$tYCpkl`WLLLaM@TrmdDChq} zy8sYFWU;U$B$3R)BMBrI91O7Ei(9DR>M5Jyk4Pxu!o>OGW<=A5@jW7n=a&_dy12 zF3?_u{pNZF#K1Qhf1j@JbbS*8-(>uKy8dr; z>3n|O0fo>LP!jYqlav1RJ@g`^!SeUs}w$KEJhAkkcg*MbnOPBtesbyBZ9)o?dlU0uB~WuAt4s!ZE^S-v_f X#dNwRQfyNU8N(R#MP5}N(dqvMrG8J& literal 0 HcmV?d00001 diff --git a/front/src/Phaser/Components/PlayerStatusDot.ts b/front/src/Phaser/Components/PlayerStatusDot.ts index af893b2f..4e09451a 100644 --- a/front/src/Phaser/Components/PlayerStatusDot.ts +++ b/front/src/Phaser/Components/PlayerStatusDot.ts @@ -1,36 +1,46 @@ import { Easing } from "../../types"; -export class PlayerStatusDot extends Phaser.GameObjects.Container { - private graphics: Phaser.GameObjects.Graphics; +export enum PlayerStatus { + Online = "Online", + Silenced = "Silenced", + Away = "Away", +} - private away: boolean; +export class PlayerStatusDot extends Phaser.GameObjects.Container { + private statusImage: Phaser.GameObjects.Image; + private statusImageOutline: Phaser.GameObjects.Image; + + private status: PlayerStatus; private readonly COLORS = { - // online: 0x00ff00, - // away: 0xffff00, online: 0x8cc43f, onlineOutline: 0x427a25, away: 0xf5931e, awayOutline: 0x875d13, + silenced: 0xe74c3c, + silencedOutline: 0xc0392b, }; constructor(scene: Phaser.Scene, x: number, y: number) { super(scene, x, y); - this.away = false; + this.status = PlayerStatus.Online; + + this.statusImage = this.scene.add.image(0, 0, "iconStatusIndicatorInside"); + this.statusImageOutline = this.scene.add.image(0, 0, "iconStatusIndicatorOutline"); + + this.add([this.statusImage, this.statusImageOutline]); - this.graphics = this.scene.add.graphics(); - this.add(this.graphics); this.redraw(); this.scene.add.existing(this); } - public setAway(away: boolean = true, instant: boolean = false): void { - if (this.away === away) { + public setStatus(status: PlayerStatus, instant: boolean = false): void { + if (this.status === status) { return; } - this.away = away; + this.status = status; if (instant) { this.redraw(); } else { @@ -56,10 +66,19 @@ export class PlayerStatusDot extends Phaser.GameObjects.Container { } private redraw(): void { - this.graphics.clear(); - this.graphics.fillStyle(this.away ? this.COLORS.away : this.COLORS.online); - this.graphics.lineStyle(1, this.away ? this.COLORS.awayOutline : this.COLORS.onlineOutline); - this.graphics.fillCircle(0, 0, 3); - this.graphics.strokeCircle(0, 0, 3); + const colors = this.getColors(); + this.statusImage.setTintFill(colors.filling); + this.statusImageOutline.setTintFill(colors.outline); + } + + private getColors(): { filling: number; outline: number } { + switch (this.status) { + case PlayerStatus.Online: + return { filling: this.COLORS.online, outline: this.COLORS.onlineOutline }; + case PlayerStatus.Away: + return { filling: this.COLORS.away, outline: this.COLORS.awayOutline }; + case PlayerStatus.Silenced: + return { filling: this.COLORS.silenced, outline: this.COLORS.silencedOutline }; + } } } diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 681efd29..0982351e 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -19,7 +19,7 @@ import type { OutlineableInterface } from "../Game/OutlineableInterface"; import type CancelablePromise from "cancelable-promise"; import { TalkIcon } from "../Components/TalkIcon"; import { Deferred } from "ts-deferred"; -import { PlayerStatusDot } from "../Components/PlayerStatusDot"; +import { PlayerStatus, PlayerStatusDot } from "../Components/PlayerStatusDot"; const playerNameY = -25; const interactiveRadius = 35; @@ -236,8 +236,8 @@ export abstract class Character extends Container implements OutlineableInterfac this.talkIcon.show(show, forceClose); } - public setAwayStatus(away: boolean = true, instant: boolean = false): void { - this.statusDot.setAway(away, instant); + public setStatus(status: PlayerStatus, instant: boolean = false): void { + this.statusDot.setStatus(status, instant); } public addCompanion(name: string, texturePromise?: CancelablePromise): void { diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index a2bd5279..5fa11d4b 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -102,6 +102,7 @@ import { Deferred } from "ts-deferred"; import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin"; import { PlayerDetailsUpdatedMessage } from "../../Messages/ts-proto-generated/protos/messages"; import { privacyShutdownStore } from "../../Stores/PrivacyShutdownStore"; +import { PlayerStatus } from "../Components/PlayerStatusDot"; export interface GameSceneInitInterface { initPosition: PointInterface | null; reconnecting: boolean; @@ -250,6 +251,8 @@ export class GameScene extends DirtyScene { this.listenToIframeEvents(); this.load.image("iconTalk", "/resources/icons/icon_talking.png"); + this.load.image("iconStatusIndicatorInside", "/resources/icons/icon_status_indicator_inside.png"); + this.load.image("iconStatusIndicatorOutline", "/resources/icons/icon_status_indicator_outline.png"); if (touchScreenManager.supportTouchScreen) { this.load.image(joystickBaseKey, joystickBaseImg); @@ -1954,7 +1957,7 @@ ${escapedMessage} player.setApiOutlineColor(addPlayerData.outlineColor); } if (addPlayerData.away !== undefined) { - player.setAwayStatus(addPlayerData.away, true); + player.setStatus(addPlayerData.away ? PlayerStatus.Away : PlayerStatus.Online, true); } this.MapPlayers.add(player); this.MapPlayersByKey.set(player.userId, player); @@ -2106,7 +2109,7 @@ ${escapedMessage} character.showTalkIcon(message.details?.showVoiceIndicator); } if (message.details?.away !== undefined) { - character.setAwayStatus(message.details?.away); + character.setStatus(message.details?.away ? PlayerStatus.Away : PlayerStatus.Online); } } diff --git a/front/src/Phaser/Game/PlayerMovement.ts b/front/src/Phaser/Game/PlayerMovement.ts index fc14078d..80b4ddcc 100644 --- a/front/src/Phaser/Game/PlayerMovement.ts +++ b/front/src/Phaser/Game/PlayerMovement.ts @@ -34,7 +34,6 @@ export class PlayerMovement { const y = (this.endPosition.y - this.startPosition.y) * ((tick - this.startTick) / (this.endTick - this.startTick)) + this.startPosition.y; - //console.log('Computed position ', x, y) return { x, y, diff --git a/front/src/Phaser/Helpers/TexturesHelper.ts b/front/src/Phaser/Helpers/TexturesHelper.ts index 6c0f1aab..4476461f 100644 --- a/front/src/Phaser/Helpers/TexturesHelper.ts +++ b/front/src/Phaser/Helpers/TexturesHelper.ts @@ -67,4 +67,20 @@ export class TexturesHelper { rectangleTexture.generateTexture(textureKey, width, height); rectangleTexture.destroy(); } + + public static createCircleTexture( + scene: Phaser.Scene, + textureKey: string, + radius: number, + color: number, + outlineColor?: number, + outlineThickness?: number + ): void { + const circleTexture = scene.add.graphics().fillStyle(color, 1).fillCircle(radius, radius, radius); + if (outlineColor) { + circleTexture.lineStyle(outlineThickness ?? 1, outlineColor).strokeCircle(radius, radius, radius); + } + circleTexture.generateTexture(textureKey, radius * 2, radius * 2); + circleTexture.destroy(); + } } diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index cae7b496..65e423a4 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -28,7 +28,6 @@ export class Player extends Character { companionTexturePromise?: CancelablePromise ) { super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise); - this.statusDot.setVisible(false); //the current player model should be push away by other players to prevent conflict this.getBody().setImmovable(false); } diff --git a/maps/tests/index.html b/maps/tests/index.html index e625aa6d..c7db9456 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -471,6 +471,14 @@ Away mode settings + + + Success Failure Pending + + + Test Status Indicator + + diff --git a/front/src/Components/MyCamera.svelte b/front/src/Components/MyCamera.svelte index 7f97ff22..8ddda1a9 100644 --- a/front/src/Components/MyCamera.svelte +++ b/front/src/Components/MyCamera.svelte @@ -1,10 +1,11 @@ diff --git a/front/src/Components/MyCamera.svelte b/front/src/Components/MyCamera.svelte index 8ddda1a9..8f4b2094 100644 --- a/front/src/Components/MyCamera.svelte +++ b/front/src/Components/MyCamera.svelte @@ -1,11 +1,10 @@
@@ -44,9 +37,9 @@

{detailsStylized}{#if $errorScreenStore.type === "retry"}

{/if}

- {#if ($errorScreenStore.type === "retry" && $errorScreenStore.canRetryManual) || ($errorScreenStore.type === "unauthorized" && $errorScreenStore.urlToRedirect && $errorScreenStore.buttonTitle) || ($errorScreenStore.type === "redirect" && (window.history.length > 2 || $errorScreenStore.urlToRedirect))} + {#if $errorScreenStore.type === "retry" && $errorScreenStore.canRetryManual} {/if} diff --git a/front/src/Components/images/external-link.png b/front/src/Components/images/external-link.png deleted file mode 100644 index 52fca4ed38534972759e400790239bf642198fc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10701 zcmeAS@N?(olHy`uVBq!ia0y~yU=0W2NDeljNXA<0p9~BN44y8IAr*7p+;Pl}4is^{ z_+5*cqs75P@JeF{i?4u45Ran3p(kOou9Bg5FKtiB*5!C!7x_tU&t3+GhTR6n>C;&l zcFf{06lGv|cjQb@G!sM2+1KXL%s}%Q{@8z-};zHi3t<{#S{qQ7joR#jyAKy2={sQoc~3=dYZ81QZUUbjuBAUo~Zo@-Ub z77xTK#Xx1zXrVM(CIeH!Xq7aY7iduwG)=x}abtBONFy zc)9|XQ4993WtMqy?fJ6hM-r+|ke& zO$?)Xfoes;hV(R^BQoe)pm2B8B7CpS!1TzGn!?=RKO51z_!{?Adn{|H$42z0ClHAWa3cYubr z2OIa`t?K;4g{PvjCB=b`YltrSxQfAG^Y^-0Gu?v=PMnTkhWeBZ{}uz%NQe&&7J=A)xDz#ts$wt!OkXemEh%F`q-?2zDP z*k^P8%xq1ICx3^GrC>@)ZQ3vb%8=*wA>rc62N&};#-=l;7z*I0g6*8I^Xi^kRpIK=v0}5O77q0>>)6(o14?T^H*k9Hd3KH~m L^>bP0l+XkKddGK2 diff --git a/front/src/Phaser/Login/EntryScene.ts b/front/src/Phaser/Login/EntryScene.ts index 02579af1..dce7216d 100644 --- a/front/src/Phaser/Login/EntryScene.ts +++ b/front/src/Phaser/Login/EntryScene.ts @@ -49,9 +49,9 @@ export class EntryScene extends Scene { .catch((err) => { const errorType = isErrorApiData.safeParse(err?.response?.data); if (errorType.success) { - if (errorType.data.type === 'unauthorized') { + if (errorType.data.type === "unauthorized") { void connectionManager.logout(); - } else if (errorType.data.type === 'redirect') { + } else if (errorType.data.type === "redirect") { window.location.assign(errorType.data.urlToRedirect); } else errorScreenStore.setError(err?.response?.data); } else { diff --git a/front/src/Stores/ErrorScreenStore.ts b/front/src/Stores/ErrorScreenStore.ts index a9081b21..564afb92 100644 --- a/front/src/Stores/ErrorScreenStore.ts +++ b/front/src/Stores/ErrorScreenStore.ts @@ -10,7 +10,7 @@ function createErrorScreenStore() { return { subscribe, setError: (e: ErrorScreenMessage): void => { - set(e) + set(e); }, }; } diff --git a/messages/JsonMessages/ErrorApiData.ts b/messages/JsonMessages/ErrorApiData.ts index e9ea4e55..0fbf3db7 100644 --- a/messages/JsonMessages/ErrorApiData.ts +++ b/messages/JsonMessages/ErrorApiData.ts @@ -43,9 +43,4 @@ export const isErrorApiData = z.discriminatedUnion("type", [ isErrorApiUnauthorizedData, ]); -export type ErrorApiErrorData = z.infer; -export type ErrorApiRetryData = z.infer; -export type ErrorApiRedirectData = z.infer; -export type ErrorApiUnauthorizedData = z.infer; - export type ErrorApiData = z.infer; diff --git a/pusher/package.json b/pusher/package.json index 22f6960e..cbd5375e 100644 --- a/pusher/package.json +++ b/pusher/package.json @@ -40,6 +40,7 @@ }, "homepage": "https://github.com/thecodingmachine/workadventure#readme", "dependencies": { + "@anatine/zod-openapi": "^1.3.0", "axios": "^0.21.2", "circular-json": "^0.5.9", "debug": "^4.3.1", @@ -48,6 +49,7 @@ "hyper-express": "^5.8.1", "jsonwebtoken": "^8.5.1", "mkdirp": "^1.0.4", + "openapi3-ts": "^2.0.2", "openid-client": "^4.7.4", "prom-client": "^12.0.0", "qs": "^6.10.3", diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 3912d951..d985261a 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -247,7 +247,6 @@ export class IoSocketController { const IPAddress = req.getHeader("x-forwarded-for"); const locale = req.getHeader("accept-language"); - const roomId = query.roomId; try { if (typeof roomId !== "string") { @@ -345,7 +344,7 @@ export class IoSocketController { reason: null, status: 500, message: err?.response?.data, - roomId: roomId + roomId: roomId, } as UpgradeFailedData, websocketKey, websocketProtocol, diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index 1476e89a..5bbfe32c 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -59,9 +59,10 @@ import { ErrorApiData, isErrorApiErrorData, isErrorApiRedirectData, - isErrorApiRetryData, isErrorApiUnauthorizedData + isErrorApiRetryData, + isErrorApiUnauthorizedData, } from "../Messages/JsonMessages/ErrorApiData"; -import {BoolValue, Int32Value, StringValue} from "google-protobuf/google/protobuf/wrappers_pb"; +import { BoolValue, Int32Value, StringValue } from "google-protobuf/google/protobuf/wrappers_pb"; const debug = Debug("socket"); @@ -681,20 +682,22 @@ export class SocketManager implements ZoneEventListener { public emitErrorScreenMessage(client: compressors.WebSocket, errorApi: ErrorApiData) { const errorMessage = new ErrorScreenMessage(); errorMessage.setType(errorApi.type); - if(errorApi.type == 'retry' || errorApi.type == 'error'){ + if (errorApi.type == "retry" || errorApi.type == "error") { errorMessage.setCode(new StringValue().setValue(errorApi.code)); errorMessage.setTitle(new StringValue().setValue(errorApi.title)); errorMessage.setSubtitle(new StringValue().setValue(errorApi.subtitle)); errorMessage.setDetails(new StringValue().setValue(errorApi.details)); errorMessage.setImage(new StringValue().setValue(errorApi.image)); } - if(errorApi.type == 'retry') { + if (errorApi.type == "retry") { if (errorApi.buttonTitle) errorMessage.setButtontitle(new StringValue().setValue(errorApi.buttonTitle)); - if (errorApi.canRetryManual !== undefined) errorMessage.setCanretrymanual(new BoolValue().setValue(errorApi.canRetryManual)); - if (errorApi.timeToRetry) errorMessage.setTimetoretry(new Int32Value().setValue(Number(errorApi.timeToRetry))); + if (errorApi.canRetryManual !== undefined) + errorMessage.setCanretrymanual(new BoolValue().setValue(errorApi.canRetryManual)); + if (errorApi.timeToRetry) + errorMessage.setTimetoretry(new Int32Value().setValue(Number(errorApi.timeToRetry))); } - if(errorApi.type == 'redirect' && errorApi.urlToRedirect) errorMessage.setUrltoredirect(new StringValue().setValue(errorApi.urlToRedirect)); - + if (errorApi.type == "redirect" && errorApi.urlToRedirect) + errorMessage.setUrltoredirect(new StringValue().setValue(errorApi.urlToRedirect)); const serverToClientMessage = new ServerToClientMessage(); serverToClientMessage.setErrorscreenmessage(errorMessage); From de6cbd7c0aa6393d57410c5be1111128aab67ddc Mon Sep 17 00:00:00 2001 From: CEC Date: Thu, 21 Apr 2022 14:49:41 +0200 Subject: [PATCH 40/72] Fix lint issues --- messages/JsonMessages/ErrorApiData.ts | 8 ++++---- pusher/src/Services/SocketManager.ts | 8 +------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/messages/JsonMessages/ErrorApiData.ts b/messages/JsonMessages/ErrorApiData.ts index 0fbf3db7..bb029159 100644 --- a/messages/JsonMessages/ErrorApiData.ts +++ b/messages/JsonMessages/ErrorApiData.ts @@ -7,7 +7,7 @@ import { z } from "zod"; export const isErrorApiErrorData = z.object({ // @ts-ignore - type: z.literal('error'), + type: z.literal("error"), code: z.string(), title: z.string(), subtitle: z.string(), @@ -16,7 +16,7 @@ export const isErrorApiErrorData = z.object({ }); export const isErrorApiRetryData = z.object({ - type: z.literal('retry'), + type: z.literal("retry"), code: z.string(), title: z.string(), subtitle: z.string(), @@ -28,12 +28,12 @@ export const isErrorApiRetryData = z.object({ }); export const isErrorApiRedirectData = z.object({ - type: z.literal('redirect'), + type: z.literal("redirect"), urlToRedirect: z.string(), }); export const isErrorApiUnauthorizedData = z.object({ - type: z.literal('unauthorized'), + type: z.literal("unauthorized"), }); export const isErrorApiData = z.discriminatedUnion("type", [ diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index 5bbfe32c..9386824a 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -55,13 +55,7 @@ import { ExAdminSocketInterface } from "../Model/Websocket/ExAdminSocketInterfac import { compressors } from "hyper-express"; import { isMapDetailsData } from "../Messages/JsonMessages/MapDetailsData"; import { adminService } from "./AdminService"; -import { - ErrorApiData, - isErrorApiErrorData, - isErrorApiRedirectData, - isErrorApiRetryData, - isErrorApiUnauthorizedData, -} from "../Messages/JsonMessages/ErrorApiData"; +import { ErrorApiData } from "../Messages/JsonMessages/ErrorApiData"; import { BoolValue, Int32Value, StringValue } from "google-protobuf/google/protobuf/wrappers_pb"; const debug = Debug("socket"); From 1575368e528948cbab4fcc066b0ce37f3a5245ae Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Thu, 21 Apr 2022 16:21:18 +0200 Subject: [PATCH 41/72] green for jitsi --- front/src/Phaser/Components/PlayerStatusDot.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/src/Phaser/Components/PlayerStatusDot.ts b/front/src/Phaser/Components/PlayerStatusDot.ts index 585f6360..d85cce86 100644 --- a/front/src/Phaser/Components/PlayerStatusDot.ts +++ b/front/src/Phaser/Components/PlayerStatusDot.ts @@ -11,7 +11,7 @@ export class PlayerStatusDot extends Phaser.GameObjects.Container { [AvailabilityStatus.AWAY]: { filling: 0xf5931e, outline: 0x875d13 }, [AvailabilityStatus.ONLINE]: { filling: 0x8cc43f, outline: 0x427a25 }, [AvailabilityStatus.SILENT]: { filling: 0xe74c3c, outline: 0xc0392b }, - [AvailabilityStatus.JITSI]: { filling: 0x74b9ff, outline: 0x0984e3 }, + [AvailabilityStatus.JITSI]: { filling: 0x8cc43f, outline: 0x427a25 }, [AvailabilityStatus.UNRECOGNIZED]: { filling: 0xffffff, outline: 0xffffff }, [AvailabilityStatus.UNCHANGED]: { filling: 0xffffff, outline: 0xffffff }, }; From 530254e0e024bb45446918a57c5acac142387bee Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Fri, 22 Apr 2022 14:35:57 +0200 Subject: [PATCH 42/72] do not subscribe to silentStore if not needed --- front/src/Components/CameraControls.svelte | 29 ++++++++-------------- front/src/Components/MyCamera.svelte | 11 ++------ 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/front/src/Components/CameraControls.svelte b/front/src/Components/CameraControls.svelte index 8b617f2e..fad3c3c1 100644 --- a/front/src/Components/CameraControls.svelte +++ b/front/src/Components/CameraControls.svelte @@ -13,7 +13,6 @@ import lockImg from "./images/lock.svg"; import { LayoutMode } from "../WebRtc/LayoutManager"; import { peerStore } from "../Stores/PeerStore"; - import { onDestroy } from "svelte"; import { embedScreenLayout } from "../Stores/EmbedScreensStore"; import { followRoleStore, followStateStore, followUsersStore } from "../Stores/FollowStore"; import { gameManager } from "../Phaser/Game/GameManager"; @@ -22,7 +21,7 @@ const gameScene = gameManager.getCurrentGameScene(); function screenSharingClick(): void { - if (isSilent) return; + if ($silentStore) return; if ($requestedScreenSharingState === true) { requestedScreenSharingState.disableScreenSharing(); } else { @@ -31,7 +30,7 @@ } function cameraClick(): void { - if (isSilent) return; + if ($silentStore) return; if ($requestedCameraState === true) { requestedCameraState.disableWebcam(); } else { @@ -40,7 +39,7 @@ } function microphoneClick(): void { - if (isSilent) return; + if ($silentStore) return; if ($requestedMicrophoneState === true) { requestedMicrophoneState.disableMicrophone(); } else { @@ -75,12 +74,6 @@ function lockClick() { gameScene.connection?.emitLockGroup(!$currentPlayerGroupLockStateStore); } - - let isSilent: boolean; - const unsubscribeIsSilent = silentStore.subscribe((silent) => { - isSilent = silent; - }); - onDestroy(unsubscribeIsSilent);
@@ -94,7 +87,7 @@
@@ -103,7 +96,7 @@
@@ -113,26 +106,26 @@
- {#if $requestedScreenSharingState && !isSilent} + {#if $requestedScreenSharingState && !$silentStore} Start screen sharing {:else} Stop screen sharing {/if}
-
- {#if $requestedCameraState && !isSilent} +
+ {#if $requestedCameraState && !$silentStore} Turn on webcam {:else} Turn off webcam {/if}
-
- {#if $requestedMicrophoneState && !isSilent} +
+ {#if $requestedMicrophoneState && !$silentStore} Turn on microphone {:else} Turn off microphone diff --git a/front/src/Components/MyCamera.svelte b/front/src/Components/MyCamera.svelte index 8f4b2094..d72a8eee 100644 --- a/front/src/Components/MyCamera.svelte +++ b/front/src/Components/MyCamera.svelte @@ -20,11 +20,6 @@ unsubscribeLocalStreamStore(); }); - let isSilent: boolean; - const unsubscribeIsSilent = silentStore.subscribe((silent) => { - isSilent = silent; - }); - let cameraContainer: HTMLDivElement; onMount(() => { @@ -40,16 +35,14 @@ } }); }); - - onDestroy(unsubscribeIsSilent);
- {#if isSilent} + {#if $silentStore}
{$LL.camera.my.silentZone()}
{:else if $localStreamStore.type === "success" && $localStreamStore.stream}
diff --git a/front/src/Components/Menu/SettingsSubMenu.svelte b/front/src/Components/Menu/SettingsSubMenu.svelte index 41fd425a..b08a645c 100644 --- a/front/src/Components/Menu/SettingsSubMenu.svelte +++ b/front/src/Components/Menu/SettingsSubMenu.svelte @@ -28,12 +28,12 @@ let previewCameraPrivacySettings = valueCameraPrivacySettings; let previewMicrophonePrivacySettings = valueMicrophonePrivacySettings; - function saveSetting() { + async function saveSetting() { let change = false; if (valueLocale !== previewValueLocale) { previewValueLocale = valueLocale; - setCurrentLocale(valueLocale as Locales); + await setCurrentLocale(valueLocale as Locales); } if (valueVideo !== previewValueVideo) { @@ -174,7 +174,7 @@
diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index d01c39a6..bd305413 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -363,15 +363,13 @@ class ConnectionManager { if (locale) { try { - if (locales.indexOf(locale) == -1) { - locales.forEach((l) => { - if (l.startsWith(locale.split("-")[0])) { - setCurrentLocale(l); - return; - } - }); + if (locales.indexOf(locale) !== -1) { + await setCurrentLocale(locale as Locales); } else { - setCurrentLocale(locale as Locales); + const nonRegionSpecificLocale = locales.find((l) => l.startsWith(locale.split("-")[0])); + if (nonRegionSpecificLocale) { + await setCurrentLocale(nonRegionSpecificLocale); + } } } catch (err) { console.warn("Could not set locale", err); diff --git a/front/src/Phaser/Entity/RemotePlayer.ts b/front/src/Phaser/Entity/RemotePlayer.ts index f820b578..ae0d1196 100644 --- a/front/src/Phaser/Entity/RemotePlayer.ts +++ b/front/src/Phaser/Entity/RemotePlayer.ts @@ -4,7 +4,7 @@ import { Character } from "../Entity/Character"; import type { GameScene } from "../Game/GameScene"; import type { PointInterface } from "../../Connexion/ConnexionModels"; import type { PlayerAnimationDirections } from "../Player/Animation"; -import type { Unsubscriber } from "svelte/store"; +import { get, Unsubscriber } from "svelte/store"; import type { ActivatableInterface } from "../Game/ActivatableInterface"; import type CancelablePromise from "cancelable-promise"; import LL from "../../i18n/i18n-svelte"; @@ -113,7 +113,7 @@ export class RemotePlayer extends Character implements ActivatableInterface { const actions: ActionsMenuAction[] = []; if (this.visitCardUrl) { actions.push({ - actionName: LL.woka.menu.businessCard(), + actionName: get(LL).woka.menu.businessCard(), protected: true, priority: 1, callback: () => { @@ -125,8 +125,8 @@ export class RemotePlayer extends Character implements ActivatableInterface { actions.push({ actionName: blackListManager.isBlackListed(this.userUuid) - ? LL.report.block.unblock() - : LL.report.block.block(), + ? get(LL).report.block.unblock() + : get(LL).report.block.block(), protected: true, priority: -1, style: "is-error", diff --git a/front/src/i18n/.gitignore b/front/src/i18n/.gitignore index 19f1f0f5..e2c9bddb 100644 --- a/front/src/i18n/.gitignore +++ b/front/src/i18n/.gitignore @@ -1,3 +1 @@ -i18n-svelte.ts -i18n-types.ts -i18n-util.ts \ No newline at end of file +i18n-*.ts diff --git a/front/src/i18n/de-DE/index.ts b/front/src/i18n/de-DE/index.ts index a72ecc1f..7c0dfb5b 100644 --- a/front/src/i18n/de-DE/index.ts +++ b/front/src/i18n/de-DE/index.ts @@ -16,8 +16,6 @@ import trigger from "./trigger"; const de_DE: Translation = { ...(en_US as Translation), - language: "Deutsch", - country: "Deutschland", audio, camera, chat, diff --git a/front/src/i18n/en-US/index.ts b/front/src/i18n/en-US/index.ts index b1a0e422..c0e018a2 100644 --- a/front/src/i18n/en-US/index.ts +++ b/front/src/i18n/en-US/index.ts @@ -14,8 +14,6 @@ import emoji from "./emoji"; import trigger from "./trigger"; const en_US: BaseTranslation = { - language: "English", - country: "United States", audio, camera, chat, diff --git a/front/src/i18n/formatters.ts b/front/src/i18n/formatters.ts index 00695fd6..da775944 100644 --- a/front/src/i18n/formatters.ts +++ b/front/src/i18n/formatters.ts @@ -1,8 +1,8 @@ -import type { AsyncFormattersInitializer } from "typesafe-i18n"; +import type { FormattersInitializer } from "typesafe-i18n"; import type { Locales, Formatters } from "./i18n-types"; // eslint-disable-next-line @typescript-eslint/require-await -export const initFormatters: AsyncFormattersInitializer = async () => { +export const initFormatters: FormattersInitializer = async () => { const formatters: Formatters = { // add your formatter functions here }; diff --git a/front/src/i18n/fr-FR/index.ts b/front/src/i18n/fr-FR/index.ts index 77acbb4a..c378a3bb 100644 --- a/front/src/i18n/fr-FR/index.ts +++ b/front/src/i18n/fr-FR/index.ts @@ -16,8 +16,6 @@ import trigger from "./trigger"; const fr_FR: Translation = { ...(en_US as Translation), - language: "Français", - country: "France", audio, camera, chat, diff --git a/front/src/i18n/locales.ts b/front/src/i18n/locales.ts index bff2f8e6..c18a1e5b 100644 --- a/front/src/i18n/locales.ts +++ b/front/src/i18n/locales.ts @@ -1,52 +1,44 @@ import { detectLocale, navigatorDetector, initLocalStorageDetector } from "typesafe-i18n/detectors"; import { FALLBACK_LOCALE } from "../Enum/EnvironmentVariable"; -import { initI18n, setLocale } from "./i18n-svelte"; +import { setLocale } from "./i18n-svelte"; import type { Locales } from "./i18n-types"; -import { baseLocale, getTranslationForLocale, locales } from "./i18n-util"; +import { baseLocale, locales } from "./i18n-util"; +import { loadLocaleAsync } from "./i18n-util.async"; -const fallbackLocale = FALLBACK_LOCALE || baseLocale; +const fallbackLocale = (FALLBACK_LOCALE || baseLocale) as Locales; const localStorageProperty = "language"; export const localeDetector = async () => { const exist = localStorage.getItem(localStorageProperty); - let detectedLocale: Locales = fallbackLocale as Locales; + let detectedLocale: Locales = fallbackLocale; if (exist) { const localStorageDetector = initLocalStorageDetector(localStorageProperty); - detectedLocale = detectLocale(fallbackLocale, locales, localStorageDetector) as Locales; + detectedLocale = detectLocale(fallbackLocale, locales, localStorageDetector); } else { - detectedLocale = detectLocale(fallbackLocale, locales, navigatorDetector) as Locales; + detectedLocale = detectLocale(fallbackLocale, locales, navigatorDetector); } - await initI18n(detectedLocale); + await setCurrentLocale(detectedLocale); }; -export const setCurrentLocale = (locale: Locales) => { +export const setCurrentLocale = async (locale: Locales) => { localStorage.setItem(localStorageProperty, locale); - setLocale(locale).catch(() => { - console.log("Cannot reload the locale!"); - }); + await loadLocaleAsync(locale); + setLocale(locale); }; -export type DisplayableLocale = { id: Locales; language: string; country: string }; +export const displayableLocales: { id: Locales; language: string; region: string }[] = locales.map((locale) => { + const [language, region] = locale.split("-"); -function getDisplayableLocales() { - const localesObject: DisplayableLocale[] = []; - locales.forEach((locale) => { - getTranslationForLocale(locale) - .then((translations) => { - localesObject.push({ - id: locale, - language: translations.language, - country: translations.country, - }); - }) - .catch((error) => { - console.log(error); - }); - }); + // backwards compatibility + if (!Intl.DisplayNames) { + return { id: locale, language, region }; + } - return localesObject; -} - -export const displayableLocales = getDisplayableLocales(); + return { + id: locale, + language: new Intl.DisplayNames(locale, { type: "language" }).of(language), + region: new Intl.DisplayNames(locale, { type: "region" }).of(region), + }; +}); diff --git a/front/src/i18n/zh-CN/index.ts b/front/src/i18n/zh-CN/index.ts index 23e2a24c..58816346 100644 --- a/front/src/i18n/zh-CN/index.ts +++ b/front/src/i18n/zh-CN/index.ts @@ -16,8 +16,6 @@ import trigger from "./trigger"; const zh_CN: Translation = { ...(en_US as Translation), - language: "中文", - country: "中国", audio, camera, chat, diff --git a/front/tsconfig.json b/front/tsconfig.json index edb99eb5..e5ac9819 100644 --- a/front/tsconfig.json +++ b/front/tsconfig.json @@ -8,7 +8,7 @@ "moduleResolution": "node", //"module": "CommonJS", "module": "ESNext", - "target": "ES2017", + "target": "ES2020", "declaration": false, "downlevelIteration": true, "jsx": "react", diff --git a/front/yarn.lock b/front/yarn.lock index 142e6c2c..f2b5e14d 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -2991,10 +2991,10 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typesafe-i18n@^2.59.0: - version "2.59.0" - resolved "https://registry.yarnpkg.com/typesafe-i18n/-/typesafe-i18n-2.59.0.tgz#09a9a32e61711418d927a389fa52e1c06a5fa5c4" - integrity sha512-Qv3Mrwmb8b73VNzQDPHPECzwymdBRVyDiZ3w2qnp4c2iv/7TGuiJegNHT/l3MooEN7IPbSpc5tbXw2x3MbGtFg== +typesafe-i18n@^5.3.5: + version "5.3.5" + resolved "https://registry.yarnpkg.com/typesafe-i18n/-/typesafe-i18n-5.3.5.tgz#8561648a2be0df660404aa087993f3eee584cb87" + integrity sha512-ZjCCQ2lCyyvUThtxJblXoxwpr62paOjMRi/Kia1PSEh3gRfwPvEorABS0zTdF6lZ75MQXoz0WqtobChVjkO5mQ== typescript@*: version "4.3.2" From a50f7a7e9bc285ab282c22183fb805392eff1853 Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Mon, 25 Apr 2022 14:36:05 +0200 Subject: [PATCH 53/72] addressed some of the requests --- .../Components/CustomizeWoka/CustomWokaPreviewer.ts | 3 +-- front/src/Phaser/Components/Ui/IconButton.ts | 3 ++- front/src/Phaser/Login/CustomizeScene.ts | 9 +++++---- front/src/Phaser/Login/SelectCharacterScene.ts | 2 ++ 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts b/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts index 98836960..1aa3aeb8 100644 --- a/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts +++ b/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts @@ -62,8 +62,7 @@ export class CustomWokaPreviewer extends Phaser.GameObjects.Container { this.turnIcon = this.scene.add .image(this.background.displayWidth * 0.35, this.background.displayHeight * 0.35, "iconTurn") .setScale(0.25) - .setTintFill(0xffffff) - .setAlpha(0.5); + .setAlpha(0.75); this.drawFrame(); this.setSize(this.SIZE, this.SIZE); diff --git a/front/src/Phaser/Components/Ui/IconButton.ts b/front/src/Phaser/Components/Ui/IconButton.ts index 2fdc9cfd..61fa7ca5 100644 --- a/front/src/Phaser/Components/Ui/IconButton.ts +++ b/front/src/Phaser/Components/Ui/IconButton.ts @@ -6,6 +6,7 @@ export interface IconButtonConfig { hover: IconButtonAppearanceConfig; pressed: IconButtonAppearanceConfig; selected: IconButtonAppearanceConfig; + iconScale?: number; } export interface IconButtonAppearanceConfig { @@ -34,7 +35,7 @@ export class IconButton extends Phaser.GameObjects.Container { this.config = config; this.background = this.scene.add.graphics(); - this.icon = this.scene.add.image(0, 0, this.config.iconTextureKey); + this.icon = this.scene.add.image(0, 0, this.config.iconTextureKey).setScale(config.iconScale ?? 1); this.drawBackground(this.config.idle); this.add([this.background, this.icon]); diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index 201c4db8..1fd4aae5 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -213,15 +213,16 @@ export class CustomizeScene extends AbstractCharacterScene { ), [CustomWokaBodyPart.Body]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconBody")), [CustomWokaBodyPart.Clothes]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconClothes")), - [CustomWokaBodyPart.Eyes]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconEyes")), + [CustomWokaBodyPart.Eyes]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconEyes", 0.7)), [CustomWokaBodyPart.Hair]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconHair")), [CustomWokaBodyPart.Hat]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconHat")), }; } - private getDefaultIconButtonConfig(iconTextureKey: string): IconButtonConfig { + private getDefaultIconButtonConfig(iconTextureKey: string, iconScale?: number): IconButtonConfig { return { iconTextureKey, + iconScale, width: 25, height: 25, idle: { @@ -420,7 +421,7 @@ export class CustomizeScene extends AbstractCharacterScene { private handleRandomizeButtonOnResize(): void { const x = - this.customWokaPreviewer.x + + this.customWokaPreviewer.x - (this.customWokaPreviewer.displayWidth - this.randomizeButton.displayWidth) * 0.5; const y = this.customWokaPreviewer.y + @@ -431,7 +432,7 @@ export class CustomizeScene extends AbstractCharacterScene { private handleFinishButtonOnResize(): void { const x = - this.customWokaPreviewer.x - + this.customWokaPreviewer.x + (this.customWokaPreviewer.displayWidth - this.randomizeButton.displayWidth) * 0.5; const y = this.customWokaPreviewer.y + diff --git a/front/src/Phaser/Login/SelectCharacterScene.ts b/front/src/Phaser/Login/SelectCharacterScene.ts index 30323463..4f1316b0 100644 --- a/front/src/Phaser/Login/SelectCharacterScene.ts +++ b/front/src/Phaser/Login/SelectCharacterScene.ts @@ -18,6 +18,7 @@ import { DraggableGrid } from "@home-based-studio/phaser3-utils"; import { WokaSlot } from "../Components/SelectWoka/WokaSlot"; import { DraggableGridEvent } from "@home-based-studio/phaser3-utils/lib/utils/gui/containers/grids/DraggableGrid"; import { wokaList } from "../../Messages/JsonMessages/PlayerTextures"; +import { myCameraVisibilityStore } from "../../Stores/MyCameraStoreVisibility"; //todo: put this constants in a dedicated file export const SelectCharacterSceneName = "SelectCharacterScene"; @@ -133,6 +134,7 @@ export class SelectCharacterScene extends AbstractCharacterScene { return; } this.selectedWoka = null; + myCameraVisibilityStore.set(false); this.scene.sleep(SelectCharacterSceneName); this.scene.run(CustomizeSceneName); selectCharacterSceneVisibleStore.set(false); From 310036e8329113aad59bf3d45e80853908e1d4f0 Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Mon, 25 Apr 2022 15:05:22 +0200 Subject: [PATCH 54/72] more style changes --- .../CustomizeWoka/CustomWokaPreviewer.ts | 6 +++--- front/src/Phaser/Login/CustomizeScene.ts | 14 +++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts b/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts index 1aa3aeb8..91f9c715 100644 --- a/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts +++ b/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts @@ -61,7 +61,7 @@ export class CustomWokaPreviewer extends Phaser.GameObjects.Container { this.frame = this.scene.add.graphics(); this.turnIcon = this.scene.add .image(this.background.displayWidth * 0.35, this.background.displayHeight * 0.35, "iconTurn") - .setScale(0.25) + .setScale(0.2) .setAlpha(0.75); this.drawFrame(); @@ -129,11 +129,11 @@ export class CustomWokaPreviewer extends Phaser.GameObjects.Container { this.changeAnimation(direction, moving); this.turnIconTween?.stop(); - this.turnIcon.setScale(0.25); + this.turnIcon.setScale(0.2); this.turnIconTween = this.scene.tweens.add({ targets: [this.turnIcon], duration: 100, - scale: 0.2, + scale: 0.15, yoyo: true, ease: Easing.SineEaseIn, }); diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index 1fd4aae5..6ac3079e 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -154,7 +154,14 @@ export class CustomizeScene extends AbstractCharacterScene { if (this.textures.getTextureKeys().includes(`floorTexture${i}`)) { continue; } - TexturesHelper.createFloorRectangleTexture(this, `floorTexture${i}`, 50, 50, "floorTiles", i); + TexturesHelper.createFloorRectangleTexture( + this, + `floorTexture${i}`, + WokaBodyPartSlot.SIZE, + WokaBodyPartSlot.SIZE, + "floorTiles", + i + ); } } @@ -328,13 +335,14 @@ export class CustomizeScene extends AbstractCharacterScene { } private handleCustomWokaPreviewerOnResize(): void { + const ratio = innerHeight / innerWidth; this.customWokaPreviewer.x = this.cameras.main.worldView.x + this.cameras.main.width / 2; - this.customWokaPreviewer.y = this.customWokaPreviewer.displayHeight * 0.5 + 10; + this.customWokaPreviewer.y = this.customWokaPreviewer.displayHeight * 0.5 + (ratio > 1.6 ? 40 : 10); } private handleBodyPartButtonsOnResize(): void { const ratio = innerHeight / innerWidth; - const slotDimension = 50; + const slotDimension = WokaBodyPartSlot.SIZE; for (const part in this.bodyPartsButtons) { this.bodyPartsButtons[part as CustomWokaBodyPart].setDisplaySize(slotDimension, slotDimension); From bc219d0139a43a05a3d3e046bd4ac3ff5196188c Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Mon, 25 Apr 2022 15:36:46 +0200 Subject: [PATCH 55/72] preserve current WOKA when getting into customization --- front/src/Phaser/Login/CustomizeScene.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index 6ac3079e..b86358f8 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -94,6 +94,15 @@ export class CustomizeScene extends AbstractCharacterScene { } public create(): void { + const savedWokaLayers = gameManager.getCharacterLayers(); + if (savedWokaLayers && savedWokaLayers.length !== 0) { + this.selectedLayers = []; + for (let i = 0; i < savedWokaLayers.length; i += 1) { + this.selectedLayers.push( + this.layers[i].findIndex((item) => item.id === gameManager.getCharacterLayers()[i]) + ); + } + } waScaleManager.zoomModifier = 1; this.createSlotBackgroundTextures(); this.initializeCustomWokaPreviewer(); From 85531745c9c9afd7da7a14d93ed37a841148d150 Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Mon, 25 Apr 2022 16:53:20 +0200 Subject: [PATCH 56/72] handle error if characterLayers are not set --- front/src/Phaser/Login/CustomizeScene.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index b86358f8..bc08136e 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -94,14 +94,18 @@ export class CustomizeScene extends AbstractCharacterScene { } public create(): void { - const savedWokaLayers = gameManager.getCharacterLayers(); - if (savedWokaLayers && savedWokaLayers.length !== 0) { - this.selectedLayers = []; - for (let i = 0; i < savedWokaLayers.length; i += 1) { - this.selectedLayers.push( - this.layers[i].findIndex((item) => item.id === gameManager.getCharacterLayers()[i]) - ); + try { + const savedWokaLayers = gameManager.getCharacterLayers(); + if (savedWokaLayers && savedWokaLayers.length !== 0) { + this.selectedLayers = []; + for (let i = 0; i < savedWokaLayers.length; i += 1) { + this.selectedLayers.push( + this.layers[i].findIndex((item) => item.id === gameManager.getCharacterLayers()[i]) + ); + } } + } catch (error) { + console.warn(error); } waScaleManager.zoomModifier = 1; this.createSlotBackgroundTextures(); From 282694fc99552afc7b8f8cbc9daf583a193b4f96 Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Mon, 25 Apr 2022 16:55:34 +0200 Subject: [PATCH 57/72] change warning message --- front/src/Phaser/Login/CustomizeScene.ts | 30 ++++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index bc08136e..f07014b9 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -94,19 +94,7 @@ export class CustomizeScene extends AbstractCharacterScene { } public create(): void { - try { - const savedWokaLayers = gameManager.getCharacterLayers(); - if (savedWokaLayers && savedWokaLayers.length !== 0) { - this.selectedLayers = []; - for (let i = 0; i < savedWokaLayers.length; i += 1) { - this.selectedLayers.push( - this.layers[i].findIndex((item) => item.id === gameManager.getCharacterLayers()[i]) - ); - } - } - } catch (error) { - console.warn(error); - } + this.tryLoadLastUsedWokaLayers(); waScaleManager.zoomModifier = 1; this.createSlotBackgroundTextures(); this.initializeCustomWokaPreviewer(); @@ -162,6 +150,22 @@ export class CustomizeScene extends AbstractCharacterScene { this.scene.run(SelectCharacterSceneName); } + private tryLoadLastUsedWokaLayers(): void { + try { + const savedWokaLayers = gameManager.getCharacterLayers(); + if (savedWokaLayers && savedWokaLayers.length !== 0) { + this.selectedLayers = []; + for (let i = 0; i < savedWokaLayers.length; i += 1) { + this.selectedLayers.push( + this.layers[i].findIndex((item) => item.id === gameManager.getCharacterLayers()[i]) + ); + } + } + } catch { + console.warn("Cannot load previous WOKA"); + } + } + private createSlotBackgroundTextures(): void { for (let i = 0; i < 4; i += 1) { if (this.textures.getTextureKeys().includes(`floorTexture${i}`)) { From 44778f51f8f6efd809c2d7cce2ea2c45b71cf653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 25 Apr 2022 17:11:48 +0200 Subject: [PATCH 58/72] Adding a troubleshooting guide Migrating the troubleshooting guide from SAAS repo + adding a paragraph about issues with embedding iframes related to HTTP headers and cookie parameters. --- docs/maps/menu.php | 5 +- docs/maps/opening-a-website.md | 11 +++- docs/maps/troubleshooting.md | 94 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 docs/maps/troubleshooting.md diff --git a/docs/maps/menu.php b/docs/maps/menu.php index c8afc2c0..af8acb9f 100644 --- a/docs/maps/menu.php +++ b/docs/maps/menu.php @@ -166,7 +166,8 @@ return [ ], [ 'title' => 'Troubleshooting', - 'url' => '/map-building/troubleshooting', - 'view' => 'content.map.troubleshooting' + 'url' => '/map-building/troubleshooting.md', + 'markdown' => 'maps.troubleshooting', + 'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/troubleshooting.md', ], ]; diff --git a/docs/maps/opening-a-website.md b/docs/maps/opening-a-website.md index 52a68168..47ed1a86 100644 --- a/docs/maps/opening-a-website.md +++ b/docs/maps/opening-a-website.md @@ -18,11 +18,18 @@ In order to create a zone that opens websites: {.alert.alert-warning} A website can explicitly forbid another website from loading it in an iFrame using -the [X-Frame-Options HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options). +the [X-Frame-Options HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options). You can +read more about this common issue and possible workaround the [troubleshooting guide](troubleshooting.md#embedding-an-iframe-is-forbidden). {.alert.alert-info} As an alternative, you may also put the `openWebsite` properties on a layer (rather than putting them on an "area" object) -but we advise to stick with "area" objects for better performance! +but we advise sticking with "area" objects for better performance! + +{.alert.alert-warning} +If the website you are embedding is using cookies, those cookies must be configured with the `SameSite=none` attribute. Otherwise, +they will be ignored by the browser. If you manage to see the website you embed but cannot log into it, the `SameSite` attribute is most +likely the culprit. You can read more about this common issue and possible workaround the [troubleshooting guide](troubleshooting.md#i-cannot-log-into-my-embedded-website). + ## Integrating a Youtube video diff --git a/docs/maps/troubleshooting.md b/docs/maps/troubleshooting.md new file mode 100644 index 00000000..784d1f66 --- /dev/null +++ b/docs/maps/troubleshooting.md @@ -0,0 +1,94 @@ +{.section-title.accent.text-primary} +# Troubleshooting + +## Look at the browser console + +If your map is not displayed correctly (most notably if you are getting a black screen), open your browser console. +This is usually done by pressing the F12 key and selecting the "console" tab. + +Scan the output. Towards the end, you might see a message explaining why your map cannot be loaded. + +## Check webserver CORS settings + +If you are hosting the map you built on your own webserver and if the map does not load, please check that +[your webserver CORS settings are correctly configured](hosting.md). + +## Issues embedding a website + +When you are embedding a website in WorkAdventure (whether it is using the [`openWebsite` property](opening-a-website.md) or +the [integrated website in a map](website-in-map.md) feature or the [Scripting API](scripting.md)), WorkAdventure +will open your website using an iFrame. + +Browsers have various security measures in place, and website owners can use those measures to prevent websites from +being used inside iFrames (either partially or completely). + +In the chapters below, we will list what can possibly prevent you from embedding a website, and see what are your options. + +### Embedding an iFrame is forbidden + +The worst that can happen is that the website you are trying to embed completely denies you the authorisation. +A website owner can do that using the [`X-Frame-Options` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options), +or the newer [`Content-Security-Policy` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy). + +Take a look at the headers of the page you are trying to load. + +{.alert.alert-info} +You can view the headers of the web page you try to load in the developer tools of your browser (usually accessible using the F12 key +of your keyboard), in the network tab. Click on the top-most request and check the "Response Headers". + +Below is what you can see when opening a Youtube video page: + +![](images/x-frame-options.png) + +`X-Frame-Options: DENY` or `X-Frame-Options: SAMEORIGIN` will prevent WorkAdventure from loading the page. +`Content-Security-Policy` header have also the potential to prevent WorkAdventure from loading the page. + +If the website you are trying to embed has one of these headers set, here are your options: + +- if you have control over the website or know the owner, you can contact the owner/administrator of the website and ask for an exception +- otherwise, you can look for an "embed" option. Some websites have special pages that can be embedded. For instance, + YouTube has special "embed" links that can be used to embed a video in your website. A lot of websites have the same feature (you + can usually find those links in the "share" section) + +If none of these options are available to you, as a last resort, you can use the [`openTab` property](opening-a-website.md) instead of the `openWebsite` property. +It will open your webpage in another tab instead of opening it in an iFrame. + +### I cannot log into my embedded website + +When you log into a website, the website is issuing a "cookie". The cookie is a unique identifier that allows the website +to recognize you and to identify you. To improve the privacy of their users, browsers can sometimes treat cookies +inside iFrames as "third-party cookies" and discard them. + +Cookies can come with a `SameSite` attribute. + +The `SameSite` attribute can take these values: "Lax", "Strict" or "None". The only value that allows using the +cookie inside an iFrame is "None". + +{.alert.alert-info} +The `SameSite` attribute of your cookie MUST be set to "None" if you want to be able to use this cookie from an iFrame inside WorkAdventure. + +**Default values**: + +If the "SameSite" attribute is not explicitly set, [the behaviour depends on the browser](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#browser_compatibility). +Chrome, Edge and Opera will default to "Lax". +Firefox and Safari will default to "None" (as of 2022/04/25). + +As a result, a website that does not set the `SameSite` attribute on cookies will work correctly in Firefox and Safari but +login will fail on Chrome, Edge and Opera. + +If the website you are trying to embed has the `SameSite` attribute set to a value other than "None", here are your options: + +- if you have control over the website or know the owner, you can contact the owner/administrator of the website and ask + the owner/administrator to change the `SameSite` settings. +- otherwise, you will have to use the [`openTab` property](opening-a-website.md) instead of the `openWebsite` property. + It will open your webpage in another tab instead of in an iFrame. + +## Need some help? + +
+

WorkAdventure is a constantly evolving project and there is plenty of room for improvement regarding map editing.

+

If you are facing any troubles, do not hesitate to seek help in + our Discord server or open an "issue" in the + GitHub WorkAdventure account. +

+
From 5479aea9f0f5f38be0aa300aed804b86bbb5f116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 14:40:54 +0200 Subject: [PATCH 59/72] Preventing a loop from occuring with chat API When sending a chat message from the Scripting API, the chat message is no longer sent back to the chat listener. This makes it easier to avoid infinite loops. --- front/src/Api/IframeListener.ts | 15 +++++++++++---- front/src/Api/ScriptUtils.ts | 4 ++-- front/src/Stores/ChatStore.ts | 7 +++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 345f3b41..f9f2b634 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -239,7 +239,7 @@ class IframeListener { } else if (iframeEvent.type === "cameraFollowPlayer") { this._cameraFollowPlayerStream.next(iframeEvent.data); } else if (iframeEvent.type === "chat") { - scriptUtils.sendAnonymousChat(iframeEvent.data); + scriptUtils.sendAnonymousChat(iframeEvent.data, iframe.contentWindow ?? undefined); } else if (iframeEvent.type === "openPopup") { this._openPopupStream.next(iframeEvent.data); } else if (iframeEvent.type === "closePopup") { @@ -399,13 +399,17 @@ class IframeListener { this.scripts.delete(scriptUrl); } - sendUserInputChat(message: string) { + /** + * @param message The message to dispatch + * @param exceptOrigin Don't dispatch the message to exceptOrigin (to avoid infinite loops) + */ + sendUserInputChat(message: string, exceptOrigin?: Window) { this.postMessage({ type: "userInputChat", data: { message: message, } as UserInputChatEvent, - }); + }, exceptOrigin); } sendEnterEvent(name: string) { @@ -521,8 +525,11 @@ class IframeListener { /** * Sends the message... to all allowed iframes. */ - public postMessage(message: IframeResponseEvent) { + public postMessage(message: IframeResponseEvent, exceptOrigin?: Window) { for (const iframe of this.iframes) { + if (exceptOrigin === iframe.contentWindow) { + continue; + } iframe.contentWindow?.postMessage(message, "*"); } } diff --git a/front/src/Api/ScriptUtils.ts b/front/src/Api/ScriptUtils.ts index f0a0625a..d6d70e81 100644 --- a/front/src/Api/ScriptUtils.ts +++ b/front/src/Api/ScriptUtils.ts @@ -11,9 +11,9 @@ class ScriptUtils { window.location.href = url; } - public sendAnonymousChat(chatEvent: ChatEvent) { + public sendAnonymousChat(chatEvent: ChatEvent, origin?: Window) { const userId = playersStore.addFacticePlayer(chatEvent.author); - chatMessagesStore.addExternalMessage(userId, chatEvent.message); + chatMessagesStore.addExternalMessage(userId, chatEvent.message, origin); } } diff --git a/front/src/Stores/ChatStore.ts b/front/src/Stores/ChatStore.ts index b8d4ea7b..9dfe7e42 100644 --- a/front/src/Stores/ChatStore.ts +++ b/front/src/Stores/ChatStore.ts @@ -87,7 +87,10 @@ function createChatMessagesStore() { return list; }); }, - addExternalMessage(authorId: number, text: string) { + /** + * @param origin The iframe that originated this message (if triggered from the Scripting API), or undefined otherwise. + */ + addExternalMessage(authorId: number, text: string, origin?: Window) { update((list) => { const lastMessage = list[list.length - 1]; if ( @@ -106,7 +109,7 @@ function createChatMessagesStore() { }); } - iframeListener.sendUserInputChat(text); + iframeListener.sendUserInputChat(text, origin); return list; }); chatVisibilityStore.set(true); From 5834b7e8c6c4040308d3c69f57a2522063e6d041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 14:42:08 +0200 Subject: [PATCH 60/72] Preventing a loop from occuring with chat API When sending a chat message from the Scripting API, the chat message is no longer sent back to the chat listener. This makes it easier to avoid infinite loops. --- front/src/Api/IframeListener.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index f9f2b634..31a89035 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -404,12 +404,15 @@ class IframeListener { * @param exceptOrigin Don't dispatch the message to exceptOrigin (to avoid infinite loops) */ sendUserInputChat(message: string, exceptOrigin?: Window) { - this.postMessage({ - type: "userInputChat", - data: { - message: message, - } as UserInputChatEvent, - }, exceptOrigin); + this.postMessage( + { + type: "userInputChat", + data: { + message: message, + } as UserInputChatEvent, + }, + exceptOrigin + ); } sendEnterEvent(name: string) { From 944a0729be175f364ffc3ca6441e89b99834c161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 14:45:45 +0200 Subject: [PATCH 61/72] Fixing typo in test --- maps/tests/emoji.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/maps/tests/emoji.json b/maps/tests/emoji.json index 520c7b26..3fd6dc10 100644 --- a/maps/tests/emoji.json +++ b/maps/tests/emoji.json @@ -13,7 +13,7 @@ "width":10, "x":0, "y":0 - }, + }, { "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "height":10, @@ -25,7 +25,7 @@ "width":10, "x":0, "y":0 - }, + }, { "draworder":"topdown", "id":3, @@ -40,7 +40,7 @@ { "fontfamily":"Sans Serif", "pixelsize":13, - "text":"Test:\nClick on tne WOKA name\n\nResult:\nThe tab with all emoji should be displayed\n\nTest:\nChoose on emoji and click on it\n\nResult:\nEmoji will be play at the top of your WOKA", + "text":"Test:\nClick on the WOKA name\n\nResult:\nThe tab with all emojis should be displayed\n\nTest:\nChoose on emoji and click on it\n\nResult:\nEmoji will be displayed above your WOKA", "wrap":true }, "type":"", @@ -79,4 +79,4 @@ "type":"map", "version":"1.6", "width":10 -} \ No newline at end of file +} From eaacb4b31a2e055628b6726fef954bb29e2aec4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 11:51:40 +0200 Subject: [PATCH 62/72] Updating i18n-typesafe version to 5.4.0 This should help us fix issues with watcher compiling files in a loop in dev mode. --- front/.typesafe-i18n.json | 2 +- front/package.json | 2 +- front/yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/front/.typesafe-i18n.json b/front/.typesafe-i18n.json index 2f7fe9a4..9e01cf76 100644 --- a/front/.typesafe-i18n.json +++ b/front/.typesafe-i18n.json @@ -1,5 +1,5 @@ { - "$schema": "https://unpkg.com/typesafe-i18n@5.3.5/schema/typesafe-i18n.json", + "$schema": "https://unpkg.com/typesafe-i18n@5.4.0/schema/typesafe-i18n.json", "baseLocale": "en-US", "adapter": "svelte" } \ No newline at end of file diff --git a/front/package.json b/front/package.json index eba55d46..c82786bd 100644 --- a/front/package.json +++ b/front/package.json @@ -60,7 +60,7 @@ "standardized-audio-context": "^25.2.4", "ts-deferred": "^1.0.4", "ts-proto": "^1.96.0", - "typesafe-i18n": "^5.3.5", + "typesafe-i18n": "^5.4.0", "uuidv4": "^6.2.10", "zod": "^3.14.3" }, diff --git a/front/yarn.lock b/front/yarn.lock index f2b5e14d..5e241511 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -2991,10 +2991,10 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typesafe-i18n@^5.3.5: - version "5.3.5" - resolved "https://registry.yarnpkg.com/typesafe-i18n/-/typesafe-i18n-5.3.5.tgz#8561648a2be0df660404aa087993f3eee584cb87" - integrity sha512-ZjCCQ2lCyyvUThtxJblXoxwpr62paOjMRi/Kia1PSEh3gRfwPvEorABS0zTdF6lZ75MQXoz0WqtobChVjkO5mQ== +typesafe-i18n@^5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/typesafe-i18n/-/typesafe-i18n-5.4.0.tgz#cab696160bb144c387d7cbd13f7a728aa8371777" + integrity sha512-htewpld3FzZQv3Y1G31w54bofaaKR11MCkDK0FIYuXCpX72y1G6fkXUDslqzZCyVkZWRnIhY8leviNDxLwEzRw== typescript@*: version "4.3.2" From 7b9c6167880261ec088b226b5b37b11865506a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 15:06:50 +0200 Subject: [PATCH 63/72] Fixing sound stop function in scripting API The sound "stop()" method was broken in scripting API. This commit adds the missing listener in GameScene --- front/src/Phaser/Game/GameScene.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 0d13e3d2..9d1d9f2a 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1106,6 +1106,13 @@ ${escapedMessage} }) ); + this.iframeSubscriptionList.push( + iframeListener.stopSoundStream.subscribe((stopSoundEvent) => { + const url = new URL(stopSoundEvent.url, this.MapUrlFile); + soundManager.stopSound(this.sound, url.toString()); + }) + ); + this.iframeSubscriptionList.push( iframeListener.addActionsMenuKeyToRemotePlayerStream.subscribe((data) => { this.MapPlayersByKey.get(data.id)?.registerActionsMenuAction({ From ed1efe12f23f0c3ae8077b56c9b7b94a184679a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 15:22:48 +0200 Subject: [PATCH 64/72] Adding an additional E2E test regarding iFrames and scripts --- maps/tests/index.html | 2 +- tests/tests/iframe_script.spec.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/tests/iframe_script.spec.ts diff --git a/maps/tests/index.html b/maps/tests/index.html index 370d99e6..9adba52d 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -216,7 +216,7 @@ Success Failure Pending - Test a iframe opened by a script can use Iframe API + Test a iframe opened by a script can use Iframe API (already automated in E2E tests) diff --git a/tests/tests/iframe_script.spec.ts b/tests/tests/iframe_script.spec.ts new file mode 100644 index 00000000..ab4e17ae --- /dev/null +++ b/tests/tests/iframe_script.spec.ts @@ -0,0 +1,16 @@ +import { expect, test } from '@playwright/test'; +import { login } from './utils/roles'; + +test.describe('Iframe API', () => { + test('can be called from an iframe loading a script', async ({ + page, + }) => { + await page.goto( + 'http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Metadata/cowebsiteAllowApi.json' + ); + + await login(page); + + await expect(page.locator('p.other-text')).toHaveText('The iframe opened by a script works !', {useInnerText: true}); + }); +}); From caf8a74ade426e0b1e2281e8c603c7ce5f9a9243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 16:43:59 +0200 Subject: [PATCH 65/72] Adding test to check custom menus --- maps/tests/Metadata/customMenu.js | 2 +- maps/tests/index.html | 2 +- tests/tests/iframe_script.spec.ts | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/maps/tests/Metadata/customMenu.js b/maps/tests/Metadata/customMenu.js index 7cedb632..a04cb760 100644 --- a/maps/tests/Metadata/customMenu.js +++ b/maps/tests/Metadata/customMenu.js @@ -1,7 +1,7 @@ let menuIframeApi = undefined; WA.ui.registerMenuCommand('custom callback menu', () => { - WA.nav.openTab("https://workadventu.re/"); + WA.chat.sendChatMessage('Custom menu clicked', 'Mr Robot'); }) WA.ui.registerMenuCommand('custom iframe menu', {iframe: 'customIframeMenu.html'}); diff --git a/maps/tests/index.html b/maps/tests/index.html index 9adba52d..610337ee 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -224,7 +224,7 @@ Success Failure Pending - Testing add a custom menu by scripting API + Testing add a custom menu by scripting API (already automated in E2E tests) diff --git a/tests/tests/iframe_script.spec.ts b/tests/tests/iframe_script.spec.ts index ab4e17ae..5da011d2 100644 --- a/tests/tests/iframe_script.spec.ts +++ b/tests/tests/iframe_script.spec.ts @@ -13,4 +13,26 @@ test.describe('Iframe API', () => { await expect(page.locator('p.other-text')).toHaveText('The iframe opened by a script works !', {useInnerText: true}); }); + + test('can add a custom menu by scripting API', async ({ + page, + }) => { + await page.goto( + 'http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Metadata/customMenu.json' + ); + + await login(page); + + await page.click('.menuIcon img:first-child'); + + await page.click('button:has-text("custom iframe menu")'); + + const iframeParagraph = page + .frameLocator('.menu-submenu-container iframe') + .locator('p'); + await expect(iframeParagraph).toHaveText('This is an iframe in a custom menu.'); + + await page.click('button:has-text("custom callback menu")'); + await expect(page.locator('p.other-text')).toHaveText('Custom menu clicked', {useInnerText: true}); + }); }); From d5cb6620280ceb4edd32d98e323a57ddaaf74588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 16:53:54 +0200 Subject: [PATCH 66/72] Fixing showHideLayer test --- maps/tests/Metadata/{showHideLayer.html => showHideLayer.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename maps/tests/Metadata/{showHideLayer.html => showHideLayer.php} (100%) diff --git a/maps/tests/Metadata/showHideLayer.html b/maps/tests/Metadata/showHideLayer.php similarity index 100% rename from maps/tests/Metadata/showHideLayer.html rename to maps/tests/Metadata/showHideLayer.php From 0316565f120b145be0c3e26f8320875a586875ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Apr 2022 17:03:52 +0200 Subject: [PATCH 67/72] Fixing setTiles test --- maps/tests/Metadata/{setTiles.html => setTiles.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename maps/tests/Metadata/{setTiles.html => setTiles.php} (100%) diff --git a/maps/tests/Metadata/setTiles.html b/maps/tests/Metadata/setTiles.php similarity index 100% rename from maps/tests/Metadata/setTiles.html rename to maps/tests/Metadata/setTiles.php From 97e3397398f5a93f20f38ea0f356a704f63d75fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Cardinale?= Date: Tue, 26 Apr 2022 18:17:12 +0200 Subject: [PATCH 68/72] Change type of unauthorized (#2123) * Change type of unauthorized * Fix redirect on received erroScreenMessage from API --- front/src/Components/UI/ErrorScreen.svelte | 8 +++++--- front/src/Connexion/RoomConnection.ts | 12 +++++++++--- front/src/Phaser/Login/EntryScene.ts | 5 +---- messages/JsonMessages/ErrorApiData.ts | 6 ++++++ pusher/src/Services/SocketManager.ts | 2 +- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/front/src/Components/UI/ErrorScreen.svelte b/front/src/Components/UI/ErrorScreen.svelte index bac59594..11ab8ca4 100644 --- a/front/src/Components/UI/ErrorScreen.svelte +++ b/front/src/Components/UI/ErrorScreen.svelte @@ -2,6 +2,7 @@ import { fly } from "svelte/transition"; import { errorScreenStore } from "../../Stores/ErrorScreenStore"; import { gameManager } from "../../Phaser/Game/GameManager"; + import { connectionManager } from "../../Connexion/ConnectionManager"; import { get } from "svelte/store"; import { onDestroy } from "svelte"; @@ -11,7 +12,8 @@ let errorScreen = get(errorScreenStore); function click() { - window.location.reload(); + if (errorScreen.type === "unauthorized") void connectionManager.logout(); + else window.location.reload(); } let details = errorScreen.details; let timeVar = errorScreen.timeToRetry ?? 0; @@ -37,9 +39,9 @@

{detailsStylized}{#if $errorScreenStore.type === "retry"}

{/if}

- {#if $errorScreenStore.type === "retry" && $errorScreenStore.canRetryManual} + {#if ($errorScreenStore.type === "retry" && $errorScreenStore.canRetryManual) || $errorScreenStore.type === "unauthorized"} {/if} diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 17725bdf..b220cd16 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -483,9 +483,15 @@ export class RoomConnection implements RoomConnection { } case "errorScreenMessage": { this._errorScreenMessageStream.next(message.errorScreenMessage); - if (message.errorScreenMessage.code !== "retry") this.closed = true; - console.error("An error occurred server side: " + message.errorScreenMessage.code); - errorScreenStore.setError(message.errorScreenMessage); + console.error("An error occurred server side: " + JSON.stringify(message.errorScreenMessage)); + if (message.errorScreenMessage.code !== "retry") { + this.closed = true; + } + if (message.errorScreenMessage.type === "redirect" && message.errorScreenMessage.urlToRedirect) { + window.location.assign(message.errorScreenMessage.urlToRedirect); + } else { + errorScreenStore.setError(message.errorScreenMessage); + } break; } default: { diff --git a/front/src/Phaser/Login/EntryScene.ts b/front/src/Phaser/Login/EntryScene.ts index dce7216d..68039403 100644 --- a/front/src/Phaser/Login/EntryScene.ts +++ b/front/src/Phaser/Login/EntryScene.ts @@ -6,7 +6,6 @@ import { ReconnectingTextures } from "../Reconnecting/ReconnectingScene"; import { localeDetector } from "../../i18n/locales"; import { errorScreenStore } from "../../Stores/ErrorScreenStore"; import { isErrorApiData } from "../../Messages/JsonMessages/ErrorApiData"; -import { connectionManager } from "../../Connexion/ConnectionManager"; export const EntrySceneName = "EntryScene"; @@ -49,9 +48,7 @@ export class EntryScene extends Scene { .catch((err) => { const errorType = isErrorApiData.safeParse(err?.response?.data); if (errorType.success) { - if (errorType.data.type === "unauthorized") { - void connectionManager.logout(); - } else if (errorType.data.type === "redirect") { + if (errorType.data.type === "redirect") { window.location.assign(errorType.data.urlToRedirect); } else errorScreenStore.setError(err?.response?.data); } else { diff --git a/messages/JsonMessages/ErrorApiData.ts b/messages/JsonMessages/ErrorApiData.ts index bb029159..ae8f48fa 100644 --- a/messages/JsonMessages/ErrorApiData.ts +++ b/messages/JsonMessages/ErrorApiData.ts @@ -34,6 +34,12 @@ export const isErrorApiRedirectData = z.object({ export const isErrorApiUnauthorizedData = z.object({ type: z.literal("unauthorized"), + code: z.string(), + title: z.string(), + subtitle: z.string(), + details: z.string(), + image: z.string(), + buttonTitle: z.optional(z.nullable(z.string())), }); export const isErrorApiData = z.discriminatedUnion("type", [ diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index 02e2e1b9..a697f38c 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -651,7 +651,7 @@ export class SocketManager implements ZoneEventListener { public emitErrorScreenMessage(client: compressors.WebSocket, errorApi: ErrorApiData) { const errorMessage = new ErrorScreenMessage(); errorMessage.setType(errorApi.type); - if (errorApi.type == "retry" || errorApi.type == "error") { + if (errorApi.type == "retry" || errorApi.type == "error" || errorApi.type == "unauthorized") { errorMessage.setCode(new StringValue().setValue(errorApi.code)); errorMessage.setTitle(new StringValue().setValue(errorApi.title)); errorMessage.setSubtitle(new StringValue().setValue(errorApi.subtitle)); From 99bfe11f84b40dcb2c5c3f72ff610541dc0b7903 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Tue, 26 Apr 2022 18:38:13 +0200 Subject: [PATCH 69/72] Fix embed website z-index --- .../EmbedScreens/EmbedScreensContainer.svelte | 1 - .../Layouts/PresentationLayout.svelte | 42 ++++++++++++------- .../HelpCameraSettingsPopup.svelte | 3 ++ front/src/Components/MainLayout.svelte | 10 ++--- front/style/cowebsite/_global.scss | 2 +- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte b/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte index d31aac89..95f3ef7c 100644 --- a/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte +++ b/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte @@ -19,6 +19,5 @@ padding-top: 2%; height: 100%; position: relative; - z-index: 200; } diff --git a/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte b/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte index dbf7ee71..b483f6c4 100644 --- a/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte +++ b/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte @@ -67,10 +67,11 @@ {/key} {:else if $highlightedEmbedScreen.type === "cowebsite"} {#key $highlightedEmbedScreen.embed.getId()} -
+
+
+ import("./Video/DesktopCapturerSourcePicker.svelte")} + /> + {#if $menuVisiblilityStore} {/if} @@ -120,11 +125,6 @@ import("./EmoteMenu/EmoteMenu.svelte")} /> - import("./Video/DesktopCapturerSourcePicker.svelte")} - /> - {#if hasEmbedScreen} {/if} diff --git a/front/style/cowebsite/_global.scss b/front/style/cowebsite/_global.scss index 52ca1e75..7555d9de 100644 --- a/front/style/cowebsite/_global.scss +++ b/front/style/cowebsite/_global.scss @@ -92,7 +92,7 @@ &-buffer { iframe { - z-index: 45 !important; + z-index: 201 !important; pointer-events: none !important; overflow: hidden; border: 0; From 69bf8a814b15e7beadea902aafcd1e9ee91430a8 Mon Sep 17 00:00:00 2001 From: Piotr Hanusiak Date: Wed, 27 Apr 2022 16:16:23 +0200 Subject: [PATCH 70/72] Upgrading @home-based-studio/phaser3-utils to a version that fixes the trackpad issue (#2124) Co-authored-by: Piotr 'pwh' Hanusiak --- front/package.json | 2 +- front/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/front/package.json b/front/package.json index c82786bd..e5ccede2 100644 --- a/front/package.json +++ b/front/package.json @@ -5,7 +5,7 @@ "license": "SEE LICENSE IN LICENSE.txt", "devDependencies": { "@geprog/vite-plugin-env-config": "^4.0.3", - "@home-based-studio/phaser3-utils": "^0.4.2", + "@home-based-studio/phaser3-utils": "^0.4.7", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.36", "@tsconfig/svelte": "^1.0.10", "@types/google-protobuf": "^3.7.3", diff --git a/front/yarn.lock b/front/yarn.lock index 5e241511..cfd5942f 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -77,10 +77,10 @@ resolved "https://registry.yarnpkg.com/@geprog/vite-plugin-env-config/-/vite-plugin-env-config-4.0.3.tgz#ca04bd9ad9f55fe568917db79266afe8e766e25e" integrity sha512-2HDCV+6XXJjSuBAhDWLRr111buMQ3bIZrKo3dymIhEJ4oJCC/3yDqg7HDQIn8Y8KKbsM0AtuHMZW4yz2tPBsYg== -"@home-based-studio/phaser3-utils@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@home-based-studio/phaser3-utils/-/phaser3-utils-0.4.2.tgz#b2c1815a6b51321ea8dab027b5badcf714d99fd6" - integrity sha512-S0VkAq3z0Kf0vEUUyCDes911icvc+nkUq7lGp23zD/5lk7LTGM51NswSAfel7Rm/DLY8IBxvDTBJADTf/De82w== +"@home-based-studio/phaser3-utils@^0.4.7": + version "0.4.7" + resolved "https://registry.yarnpkg.com/@home-based-studio/phaser3-utils/-/phaser3-utils-0.4.7.tgz#d0464c81cb27328657d3fd048396f6936e200c48" + integrity sha512-gYt1mkuad85uzYwHK0+wp+mrsGASV4sRZPaHZHnO8A2ofTAnX36S3PcI+BqKchdJ0I7jvBQcfh0yp1Ug0BHT+A== dependencies: phaser "3.55.1" From 9427ca8d7c6fa2b231490b9ef2f7e38f922b2017 Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Wed, 27 Apr 2022 16:25:12 +0200 Subject: [PATCH 71/72] clear activatableObjectsDistances map before setting up fresh values --- front/src/Phaser/Game/ActivatablesManager.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/front/src/Phaser/Game/ActivatablesManager.ts b/front/src/Phaser/Game/ActivatablesManager.ts index b41c5a72..7f337cda 100644 --- a/front/src/Phaser/Game/ActivatablesManager.ts +++ b/front/src/Phaser/Game/ActivatablesManager.ts @@ -76,6 +76,7 @@ export class ActivatablesManager { const currentPlayerPos = this.currentPlayer.getDirectionalActivationPosition( this.directionalActivationPositionShift ); + this.activatableObjectsDistances.clear(); for (const object of objects) { const distance = MathUtils.distanceBetween(currentPlayerPos, object.getPosition()); this.activatableObjectsDistances.set(object, distance); From f9a4bcff29b018b911be1a97390308e2619353b8 Mon Sep 17 00:00:00 2001 From: Piotr 'pwh' Hanusiak Date: Wed, 27 Apr 2022 17:08:14 +0200 Subject: [PATCH 72/72] send removeOutline flag if needed --- back/src/Model/User.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/back/src/Model/User.ts b/back/src/Model/User.ts index b103f240..d9ed323f 100644 --- a/back/src/Model/User.ts +++ b/back/src/Model/User.ts @@ -150,6 +150,9 @@ export class User implements Movable { if (this.outlineColor !== undefined) { playerDetails.setOutlinecolor(new UInt32Value().setValue(this.outlineColor)); } + if (details.getRemoveoutlinecolor()) { + playerDetails.setRemoveoutlinecolor(new BoolValue().setValue(true)); + } if (this.voiceIndicatorShown !== undefined) { playerDetails.setShowvoiceindicator(new BoolValue().setValue(this.voiceIndicatorShown)); }