diff --git a/front/package.json b/front/package.json index 4a0ea649..a52193b2 100644 --- a/front/package.json +++ b/front/package.json @@ -57,6 +57,7 @@ "simple-peer": "^9.11.0", "socket.io-client": "^2.3.0", "standardized-audio-context": "^25.2.4", + "ts-deferred": "^1.0.4", "ts-proto": "^1.96.0", "typesafe-i18n": "^2.59.0", "uuidv4": "^6.2.10", diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 37d92b89..65e4c190 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -18,6 +18,7 @@ import { createColorStore } from "../../Stores/OutlineColorStore"; import type { OutlineableInterface } from "../Game/OutlineableInterface"; import type CancelablePromise from "cancelable-promise"; import { TalkIcon } from "../Components/TalkIcon"; +import { Deferred } from "ts-deferred"; const playerNameY = -25; @@ -50,6 +51,11 @@ export abstract class Character extends Container implements OutlineableInterfac private readonly outlineColorStoreUnsubscribe: Unsubscriber; private texturePromise: CancelablePromise | undefined; + /** + * A deferred promise that resolves when the texture of the character is actually displayed. + */ + private textureLoadedDeferred = new Deferred(); + constructor( scene: GameScene, x: number, @@ -78,6 +84,7 @@ export abstract class Character extends Container implements OutlineableInterfac this.addTextures(textures, frame); this.invisible = false; this.playAnimation(direction, moving); + this.textureLoadedDeferred.resolve(); return this.getSnapshot().then((htmlImageElementSrc) => { this._pictureStore.set(htmlImageElementSrc); }); @@ -92,11 +99,20 @@ export abstract class Character extends Container implements OutlineableInterfac id: "eyes_23", img: "resources/customisation/character_eyes/character_eyes23.png", }, - ]).then((textures) => { - this.addTextures(textures, frame); - this.invisible = false; - this.playAnimation(direction, moving); - }); + ]) + .then((textures) => { + this.addTextures(textures, frame); + this.invisible = false; + this.playAnimation(direction, moving); + this.textureLoadedDeferred.resolve(); + return this.getSnapshot().then((htmlImageElementSrc) => { + this._pictureStore.set(htmlImageElementSrc); + }); + }) + .catch((e) => { + this.textureLoadedDeferred.reject(e); + throw e; + }); }) .finally(() => { this.texturePromise = undefined; @@ -517,4 +533,13 @@ export abstract class Character extends Container implements OutlineableInterfac public characterFarAwayOutline(): void { this.outlineColorStore.characterFarAway(); } + + /** + * Returns a promise that resolves as soon as a texture is displayed for the user. + * The promise will return when the required texture is loaded OR when the fallback texture is loaded (in case + * the required texture could not be loaded). + */ + public getTextureLoadedPromise(): PromiseLike { + return this.textureLoadedDeferred.promise; + } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 02c6101a..4ce35372 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -702,7 +702,11 @@ export class GameScene extends DirtyScene { } }); - Promise.all([this.connectionAnswerPromise as Promise, ...scriptPromises]) + Promise.all([ + this.connectionAnswerPromise as Promise, + ...scriptPromises, + this.CurrentPlayer.getTextureLoadedPromise() as Promise, + ]) .then(() => { this.scene.wake(); }) diff --git a/front/yarn.lock b/front/yarn.lock index c7263531..4c6d813d 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -2900,6 +2900,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +ts-deferred@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/ts-deferred/-/ts-deferred-1.0.4.tgz#58145ebaeef5b8f2a290b8cec3d060839f9489c7" + integrity sha1-WBReuu71uPKikLjOw9Bgg5+Uicc= + ts-node@^10.4.0: version "10.4.0" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7"