merged develop
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
|
||||
import { DirtyScene } from "../Game/DirtyScene";
|
||||
import { gameManager } from "../Game/GameManager";
|
||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import Image = Phaser.GameObjects.Image;
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
|
||||
const LogoNameIndex: string = "logoLoading";
|
||||
const TextName: string = "Loading...";
|
||||
const LogoResource: string = "static/images/logo.png";
|
||||
const LogoFrame: ImageFrameConfig = { frameWidth: 310, frameHeight: 60 };
|
||||
|
||||
const loadingBarHeight: number = 16;
|
||||
const padding: number = 5;
|
||||
@@ -14,9 +16,15 @@ export class Loader {
|
||||
private progress!: Phaser.GameObjects.Graphics;
|
||||
private progressAmount: number = 0;
|
||||
private logo: Phaser.GameObjects.Image | undefined;
|
||||
private logoPoweredBy: Phaser.GameObjects.Image | undefined;
|
||||
private poweredByLogo: Phaser.GameObjects.Image | undefined;
|
||||
private loadingText: Phaser.GameObjects.Text | null = null;
|
||||
private logoNameIndex!: string;
|
||||
private superLoad: SuperLoaderPlugin;
|
||||
|
||||
public constructor(private scene: Phaser.Scene) {}
|
||||
public constructor(private scene: Phaser.Scene) {
|
||||
this.superLoad = new SuperLoaderPlugin(scene);
|
||||
}
|
||||
|
||||
public addLoader(): void {
|
||||
// If there is nothing to load, do not display the loader.
|
||||
@@ -24,43 +32,53 @@ export class Loader {
|
||||
return;
|
||||
}
|
||||
|
||||
const logoResource = gameManager.currentStartedRoom.loadingLogo ?? "static/images/logo.png";
|
||||
this.logoNameIndex = "logoLoading" + logoResource;
|
||||
|
||||
const loadingBarWidth: number = Math.floor(this.scene.game.renderer.width / 3);
|
||||
|
||||
const promiseLoadLogoTexture = new Promise<Phaser.GameObjects.Image>((res) => {
|
||||
if (this.scene.load.textureManager.exists(LogoNameIndex)) {
|
||||
return res(
|
||||
(this.logo = this.scene.add.image(
|
||||
this.scene.game.renderer.width / 2,
|
||||
this.scene.game.renderer.height / 2 - 150,
|
||||
LogoNameIndex
|
||||
))
|
||||
);
|
||||
} else {
|
||||
//add loading if logo image is not ready
|
||||
this.loadingText = this.scene.add.text(
|
||||
//add loading if logo image until logo image is ready
|
||||
this.loadingText = this.scene.add.text(
|
||||
this.scene.game.renderer.width / 2,
|
||||
this.scene.game.renderer.height / 2 - 50,
|
||||
TextName
|
||||
);
|
||||
|
||||
const logoPromise = this.superLoad.image(this.logoNameIndex, logoResource);
|
||||
logoPromise
|
||||
.then((texture) => {
|
||||
this.logo = this.scene.add.image(
|
||||
this.scene.game.renderer.width / 2,
|
||||
this.scene.game.renderer.height / 2 - 50,
|
||||
TextName
|
||||
this.scene.game.renderer.height / 2 - 150,
|
||||
texture
|
||||
);
|
||||
}
|
||||
this.scene.load.spritesheet(LogoNameIndex, LogoResource, LogoFrame);
|
||||
this.scene.load.once(`filecomplete-spritesheet-${LogoNameIndex}`, () => {
|
||||
if (this.loadingText) {
|
||||
this.loadingText.destroy();
|
||||
}
|
||||
return res(
|
||||
(this.logo = this.scene.add.image(
|
||||
|
||||
this.loadingText?.destroy();
|
||||
})
|
||||
.catch((e) => console.warn("Could not load logo: ", logoResource, e));
|
||||
|
||||
let poweredByLogoPromise: CancelablePromise<Texture> | undefined;
|
||||
if (gameManager.currentStartedRoom.loadingLogo) {
|
||||
poweredByLogoPromise = this.superLoad.image(
|
||||
"poweredByLogo",
|
||||
"static/images/Powered_By_WorkAdventure_Small.png"
|
||||
);
|
||||
poweredByLogoPromise
|
||||
.then((texture) => {
|
||||
this.poweredByLogo = this.scene.add.image(
|
||||
this.scene.game.renderer.width / 2,
|
||||
this.scene.game.renderer.height / 2 - 150,
|
||||
LogoNameIndex
|
||||
))
|
||||
this.scene.game.renderer.height - 50,
|
||||
texture
|
||||
);
|
||||
})
|
||||
.catch((e) =>
|
||||
console.warn('Could not load image "static/images/Powered_By_WorkAdventure_Small.png"', e)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.progressContainer = this.scene.add.graphics();
|
||||
this.progress = this.scene.add.graphics();
|
||||
this.progressContainer.fillStyle(0x444444, 0.8);
|
||||
this.progress = this.scene.add.graphics();
|
||||
|
||||
this.resize();
|
||||
|
||||
@@ -68,26 +86,35 @@ export class Loader {
|
||||
this.progressAmount = value;
|
||||
this.drawProgress();
|
||||
});
|
||||
|
||||
const resizeFunction = this.resize.bind(this);
|
||||
this.scene.scale.on(Phaser.Scale.Events.RESIZE, resizeFunction);
|
||||
|
||||
this.scene.load.on("complete", () => {
|
||||
if (this.loadingText) {
|
||||
this.loadingText.destroy();
|
||||
}
|
||||
promiseLoadLogoTexture
|
||||
.then((resLoadingImage: Phaser.GameObjects.Image) => {
|
||||
resLoadingImage.destroy();
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
logoPromise.cancel();
|
||||
poweredByLogoPromise?.cancel();
|
||||
|
||||
this.logo?.destroy();
|
||||
this.poweredByLogo?.destroy();
|
||||
|
||||
this.progress.destroy();
|
||||
this.progressContainer.destroy();
|
||||
if (this.scene instanceof DirtyScene) {
|
||||
this.scene.markDirty();
|
||||
}
|
||||
this.scene.scale.off(Phaser.Scale.Events.RESIZE, resizeFunction);
|
||||
});
|
||||
}
|
||||
|
||||
public removeLoader(): void {
|
||||
if (this.scene.load.textureManager.exists(LogoNameIndex)) {
|
||||
this.scene.load.textureManager.remove(LogoNameIndex);
|
||||
if (this.scene.load.textureManager.exists(this.logoNameIndex)) {
|
||||
this.scene.load.textureManager.remove(this.logoNameIndex);
|
||||
}
|
||||
if (this.scene.load.textureManager.exists("poweredByLogo")) {
|
||||
this.scene.load.textureManager.remove("poweredByLogo");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +141,11 @@ export class Loader {
|
||||
this.logo.x = this.scene.game.renderer.width / 2;
|
||||
this.logo.y = this.scene.game.renderer.height / 2 - 150;
|
||||
}
|
||||
|
||||
if (this.poweredByLogo) {
|
||||
this.poweredByLogo.x = this.scene.game.renderer.width / 2;
|
||||
this.poweredByLogo.y = this.scene.game.renderer.height - 40;
|
||||
}
|
||||
}
|
||||
|
||||
private drawProgress() {
|
||||
|
||||
@@ -57,8 +57,8 @@ export class SoundMeter {
|
||||
this.context = context;
|
||||
this.analyser = this.context.createAnalyser();
|
||||
|
||||
this.analyser.fftSize = 2048;
|
||||
const bufferLength = this.analyser.fftSize;
|
||||
this.analyser.fftSize = 256;
|
||||
const bufferLength = this.analyser.frequencyBinCount;
|
||||
this.dataArray = new Uint8Array(bufferLength);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import type { GameScene } from "../Game/GameScene";
|
||||
import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes";
|
||||
import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
||||
import { isSilentStore } from "../../Stores/MediaStore";
|
||||
import { lazyLoadPlayerCharacterTextures, loadAllDefaultModels } from "./PlayerTexturesLoadingManager";
|
||||
import { lazyLoadPlayerCharacterTextures } from "./PlayerTexturesLoadingManager";
|
||||
import { TexturesHelper } from "../Helpers/TexturesHelper";
|
||||
import type { PictureStore } from "../../Stores/PictureStore";
|
||||
import { Unsubscriber, Writable, writable } from "svelte/store";
|
||||
@@ -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<string[] | void> | undefined;
|
||||
|
||||
/**
|
||||
* A deferred promise that resolves when the texture of the character is actually displayed.
|
||||
*/
|
||||
private textureLoadedDeferred = new Deferred<void>();
|
||||
|
||||
constructor(
|
||||
scene: GameScene,
|
||||
x: number,
|
||||
@@ -78,16 +84,35 @@ 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);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
return lazyLoadPlayerCharacterTextures(scene.load, ["color_22", "eyes_23"]).then((textures) => {
|
||||
this.addTextures(textures, frame);
|
||||
this.invisible = false;
|
||||
this.playAnimation(direction, moving);
|
||||
});
|
||||
return lazyLoadPlayerCharacterTextures(scene.superLoad, [
|
||||
{
|
||||
id: "color_22",
|
||||
img: "resources/customisation/character_color/character_color21.png",
|
||||
},
|
||||
{
|
||||
id: "eyes_23",
|
||||
img: "resources/customisation/character_eyes/character_eyes23.png",
|
||||
},
|
||||
])
|
||||
.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;
|
||||
@@ -508,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<void> {
|
||||
return this.textureLoadedDeferred.promise;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,450 +1,110 @@
|
||||
//The list of all the player textures, both the default models and the partial textures used for customization
|
||||
|
||||
import { WokaList, WokaPartType } from "../../Messages/JsonMessages/PlayerTextures";
|
||||
|
||||
export interface BodyResourceDescriptionListInterface {
|
||||
[key: string]: BodyResourceDescriptionInterface;
|
||||
}
|
||||
|
||||
export interface BodyResourceDescriptionInterface {
|
||||
name: string;
|
||||
id: 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" },
|
||||
|
||||
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" },
|
||||
/**
|
||||
* Temporary object to map layers to the old "level" concept.
|
||||
*/
|
||||
export const mapLayerToLevel = {
|
||||
woka: -1,
|
||||
body: 0,
|
||||
eyes: 1,
|
||||
hair: 2,
|
||||
clothes: 3,
|
||||
hat: 4,
|
||||
accessory: 5,
|
||||
};
|
||||
|
||||
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" },
|
||||
};
|
||||
export enum PlayerTexturesKey {
|
||||
Accessory = "accessory",
|
||||
Body = "body",
|
||||
Clothes = "clothes",
|
||||
Eyes = "eyes",
|
||||
Hair = "hair",
|
||||
Hat = "hat",
|
||||
Woka = "woka",
|
||||
}
|
||||
|
||||
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" },
|
||||
};
|
||||
export class PlayerTextures {
|
||||
private PLAYER_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||
private COLOR_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||
private EYES_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||
private HAIR_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||
private CLOTHES_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||
private HATS_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||
private ACCESSORIES_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||
private LAYERS: BodyResourceDescriptionListInterface[] = [];
|
||||
|
||||
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" },
|
||||
};
|
||||
public loadPlayerTexturesMetadata(metadata: WokaList): void {
|
||||
this.mapTexturesMetadataIntoResources(metadata);
|
||||
}
|
||||
|
||||
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" },
|
||||
};
|
||||
public getTexturesResources(key: PlayerTexturesKey): BodyResourceDescriptionListInterface {
|
||||
switch (key) {
|
||||
case PlayerTexturesKey.Accessory:
|
||||
return this.ACCESSORIES_RESOURCES;
|
||||
case PlayerTexturesKey.Body:
|
||||
return this.COLOR_RESOURCES;
|
||||
case PlayerTexturesKey.Clothes:
|
||||
return this.CLOTHES_RESOURCES;
|
||||
case PlayerTexturesKey.Eyes:
|
||||
return this.EYES_RESOURCES;
|
||||
case PlayerTexturesKey.Hair:
|
||||
return this.HAIR_RESOURCES;
|
||||
case PlayerTexturesKey.Hat:
|
||||
return this.HATS_RESOURCES;
|
||||
case PlayerTexturesKey.Woka:
|
||||
return this.PLAYER_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
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" },
|
||||
};
|
||||
public getLayers(): BodyResourceDescriptionListInterface[] {
|
||||
return this.LAYERS;
|
||||
}
|
||||
|
||||
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" },
|
||||
};
|
||||
private mapTexturesMetadataIntoResources(metadata: WokaList): void {
|
||||
this.PLAYER_RESOURCES = this.getMappedResources(metadata.woka);
|
||||
this.COLOR_RESOURCES = this.getMappedResources(metadata.body);
|
||||
this.EYES_RESOURCES = this.getMappedResources(metadata.eyes);
|
||||
this.HAIR_RESOURCES = this.getMappedResources(metadata.hair);
|
||||
this.CLOTHES_RESOURCES = this.getMappedResources(metadata.clothes);
|
||||
this.HATS_RESOURCES = this.getMappedResources(metadata.hat);
|
||||
this.ACCESSORIES_RESOURCES = this.getMappedResources(metadata.accessory);
|
||||
|
||||
export const LAYERS: BodyResourceDescriptionListInterface[] = [
|
||||
COLOR_RESOURCES,
|
||||
EYES_RESOURCES,
|
||||
HAIR_RESOURCES,
|
||||
CLOTHES_RESOURCES,
|
||||
HATS_RESOURCES,
|
||||
ACCESSORIES_RESOURCES,
|
||||
];
|
||||
this.LAYERS = [
|
||||
this.COLOR_RESOURCES,
|
||||
this.EYES_RESOURCES,
|
||||
this.HAIR_RESOURCES,
|
||||
this.CLOTHES_RESOURCES,
|
||||
this.HATS_RESOURCES,
|
||||
this.ACCESSORIES_RESOURCES,
|
||||
];
|
||||
}
|
||||
|
||||
private getMappedResources(category: WokaPartType): BodyResourceDescriptionListInterface {
|
||||
const resources: BodyResourceDescriptionListInterface = {};
|
||||
if (!category) {
|
||||
return {};
|
||||
}
|
||||
for (const collection of category.collections) {
|
||||
for (const texture of collection.textures) {
|
||||
resources[texture.id] = { id: texture.id, img: texture.url };
|
||||
}
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
|
||||
export const OBJECTS: BodyResourceDescriptionInterface[] = [
|
||||
{ name: "teleportation", img: "resources/objects/teleportation.png" },
|
||||
{ id: "teleportation", img: "resources/objects/teleportation.png" },
|
||||
];
|
||||
|
||||
@@ -1,129 +1,69 @@
|
||||
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
||||
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
||||
import { BodyResourceDescriptionInterface, LAYERS, PLAYER_RESOURCES } from "./PlayerTextures";
|
||||
import { BodyResourceDescriptionInterface, mapLayerToLevel, PlayerTextures, PlayerTexturesKey } from "./PlayerTextures";
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
|
||||
export interface FrameConfig {
|
||||
frameWidth: number;
|
||||
frameHeight: number;
|
||||
}
|
||||
|
||||
export const loadAllLayers = (load: LoaderPlugin): BodyResourceDescriptionInterface[][] => {
|
||||
export const loadAllLayers = (
|
||||
load: LoaderPlugin,
|
||||
playerTextures: PlayerTextures
|
||||
): BodyResourceDescriptionInterface[][] => {
|
||||
const returnArray: BodyResourceDescriptionInterface[][] = [];
|
||||
LAYERS.forEach((layer) => {
|
||||
playerTextures.getLayers().forEach((layer) => {
|
||||
const layerArray: BodyResourceDescriptionInterface[] = [];
|
||||
Object.values(layer).forEach((textureDescriptor) => {
|
||||
layerArray.push(textureDescriptor);
|
||||
load.spritesheet(textureDescriptor.name, textureDescriptor.img, { frameWidth: 32, frameHeight: 32 });
|
||||
load.spritesheet(textureDescriptor.id, textureDescriptor.img, { frameWidth: 32, frameHeight: 32 });
|
||||
});
|
||||
returnArray.push(layerArray);
|
||||
});
|
||||
return returnArray;
|
||||
};
|
||||
export const loadAllDefaultModels = (load: LoaderPlugin): BodyResourceDescriptionInterface[] => {
|
||||
const returnArray = Object.values(PLAYER_RESOURCES);
|
||||
export const loadAllDefaultModels = (
|
||||
load: LoaderPlugin,
|
||||
playerTextures: PlayerTextures
|
||||
): BodyResourceDescriptionInterface[] => {
|
||||
const returnArray = Object.values(playerTextures.getTexturesResources(PlayerTexturesKey.Woka));
|
||||
returnArray.forEach((playerResource: BodyResourceDescriptionInterface) => {
|
||||
load.spritesheet(playerResource.name, playerResource.img, { frameWidth: 32, frameHeight: 32 });
|
||||
load.spritesheet(playerResource.id, playerResource.img, { frameWidth: 32, frameHeight: 32 });
|
||||
});
|
||||
return returnArray;
|
||||
};
|
||||
|
||||
export const loadCustomTexture = (
|
||||
loaderPlugin: LoaderPlugin,
|
||||
texture: CharacterTexture
|
||||
): CancelablePromise<BodyResourceDescriptionInterface> => {
|
||||
const name = "customCharacterTexture" + texture.id;
|
||||
const playerResourceDescriptor: BodyResourceDescriptionInterface = { name, img: texture.url, level: texture.level };
|
||||
return createLoadingPromise(loaderPlugin, playerResourceDescriptor, {
|
||||
export const loadWokaTexture = (
|
||||
superLoaderPlugin: SuperLoaderPlugin,
|
||||
texture: BodyResourceDescriptionInterface
|
||||
): CancelablePromise<Texture> => {
|
||||
return superLoaderPlugin.spritesheet(texture.id, texture.img, {
|
||||
frameWidth: 32,
|
||||
frameHeight: 32,
|
||||
});
|
||||
};
|
||||
|
||||
export const lazyLoadPlayerCharacterTextures = (
|
||||
loadPlugin: LoaderPlugin,
|
||||
texturekeys: Array<string | BodyResourceDescriptionInterface>
|
||||
superLoaderPlugin: SuperLoaderPlugin,
|
||||
textures: BodyResourceDescriptionInterface[]
|
||||
): CancelablePromise<string[]> => {
|
||||
const promisesList: CancelablePromise<unknown>[] = [];
|
||||
texturekeys.forEach((textureKey: string | BodyResourceDescriptionInterface) => {
|
||||
try {
|
||||
//TODO refactor
|
||||
const playerResourceDescriptor = getRessourceDescriptor(textureKey);
|
||||
if (playerResourceDescriptor && !loadPlugin.textureManager.exists(playerResourceDescriptor.name)) {
|
||||
promisesList.push(
|
||||
createLoadingPromise(loadPlugin, playerResourceDescriptor, {
|
||||
frameWidth: 32,
|
||||
frameHeight: 32,
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
let returnPromise: CancelablePromise<Array<string | BodyResourceDescriptionInterface>>;
|
||||
if (promisesList.length > 0) {
|
||||
loadPlugin.start();
|
||||
returnPromise = CancelablePromise.all(promisesList).then(() => texturekeys);
|
||||
} else {
|
||||
returnPromise = CancelablePromise.resolve(texturekeys);
|
||||
const promisesList: CancelablePromise<Texture>[] = [];
|
||||
for (const texture of textures) {
|
||||
promisesList.push(
|
||||
superLoaderPlugin.spritesheet(texture.id, texture.img, {
|
||||
frameWidth: 32,
|
||||
frameHeight: 32,
|
||||
})
|
||||
);
|
||||
}
|
||||
const returnPromise: CancelablePromise<Texture[]> = CancelablePromise.all(promisesList);
|
||||
|
||||
//If the loading fail, we render the default model instead.
|
||||
return returnPromise.then((keys) =>
|
||||
keys.map((key) => {
|
||||
return typeof key !== "string" ? key.name : key;
|
||||
return returnPromise.then(() =>
|
||||
textures.map((key) => {
|
||||
return key.id;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export const getRessourceDescriptor = (
|
||||
textureKey: string | BodyResourceDescriptionInterface
|
||||
): BodyResourceDescriptionInterface => {
|
||||
if (typeof textureKey !== "string" && textureKey.img) {
|
||||
return textureKey;
|
||||
}
|
||||
const textureName: string = typeof textureKey === "string" ? textureKey : textureKey.name;
|
||||
const playerResource = PLAYER_RESOURCES[textureName];
|
||||
if (playerResource !== undefined) return playerResource;
|
||||
|
||||
for (let i = 0; i < LAYERS.length; i++) {
|
||||
const playerResource = LAYERS[i][textureName];
|
||||
if (playerResource !== undefined) return playerResource;
|
||||
}
|
||||
throw new Error("Could not find a data for texture " + textureName);
|
||||
};
|
||||
|
||||
export const createLoadingPromise = (
|
||||
loadPlugin: LoaderPlugin,
|
||||
playerResourceDescriptor: BodyResourceDescriptionInterface,
|
||||
frameConfig: FrameConfig
|
||||
) => {
|
||||
return new CancelablePromise<BodyResourceDescriptionInterface>((res, rej, cancel) => {
|
||||
if (loadPlugin.textureManager.exists(playerResourceDescriptor.name)) {
|
||||
return res(playerResourceDescriptor);
|
||||
}
|
||||
|
||||
cancel(() => {
|
||||
loadPlugin.off("loaderror");
|
||||
loadPlugin.off("filecomplete-spritesheet-" + playerResourceDescriptor.name);
|
||||
return;
|
||||
});
|
||||
|
||||
loadPlugin.spritesheet(playerResourceDescriptor.name, playerResourceDescriptor.img, frameConfig);
|
||||
const errorCallback = (file: { src: string }) => {
|
||||
if (file.src !== playerResourceDescriptor.img) return;
|
||||
console.error("failed loading player resource: ", playerResourceDescriptor);
|
||||
rej(playerResourceDescriptor);
|
||||
loadPlugin.off("filecomplete-spritesheet-" + playerResourceDescriptor.name, successCallback);
|
||||
loadPlugin.off("loaderror", errorCallback);
|
||||
};
|
||||
const successCallback = () => {
|
||||
loadPlugin.off("loaderror", errorCallback);
|
||||
res(playerResourceDescriptor);
|
||||
};
|
||||
|
||||
loadPlugin.once("filecomplete-spritesheet-" + playerResourceDescriptor.name, successCallback);
|
||||
loadPlugin.on("loaderror", errorCallback);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { requestVisitCardsStore } from "../../Stores/GameStore";
|
||||
import { ActionsMenuData, actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
||||
import { ActionsMenuAction, ActionsMenuData, actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
||||
import { Character } from "../Entity/Character";
|
||||
import type { GameScene } from "../Game/GameScene";
|
||||
import type { PointInterface } from "../../Connexion/ConnexionModels";
|
||||
@@ -8,21 +8,28 @@ import type { Unsubscriber } from "svelte/store";
|
||||
import type { ActivatableInterface } from "../Game/ActivatableInterface";
|
||||
import type CancelablePromise from "cancelable-promise";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import { blackListManager } from "../../WebRtc/BlackListManager";
|
||||
import { showReportScreenStore } from "../../Stores/ShowReportScreenStore";
|
||||
|
||||
export enum RemotePlayerEvent {
|
||||
Clicked = "Clicked",
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing the sprite of a remote player (a player that plays on another computer)
|
||||
*/
|
||||
export class RemotePlayer extends Character implements ActivatableInterface {
|
||||
public userId: number;
|
||||
public readonly userId: number;
|
||||
public readonly userUuid: string;
|
||||
public readonly activationRadius: number;
|
||||
|
||||
private registeredActions: { actionName: string; callback: Function }[];
|
||||
private visitCardUrl: string | null;
|
||||
private isActionsMenuInitialized: boolean = false;
|
||||
private actionsMenuStoreUnsubscriber: Unsubscriber;
|
||||
|
||||
constructor(
|
||||
userId: number,
|
||||
userUuid: string,
|
||||
Scene: GameScene,
|
||||
x: number,
|
||||
y: number,
|
||||
@@ -39,10 +46,9 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
||||
|
||||
//set data
|
||||
this.userId = userId;
|
||||
this.userUuid = userUuid;
|
||||
this.visitCardUrl = visitCardUrl;
|
||||
this.registeredActions = [];
|
||||
this.registerDefaultActionsMenuActions();
|
||||
this.setClickable(this.registeredActions.length > 0);
|
||||
this.setClickable(this.getDefaultActionsMenuActions().length > 0);
|
||||
this.activationRadius = activationRadius ?? 96;
|
||||
this.actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value: ActionsMenuData | undefined) => {
|
||||
this.isActionsMenuInitialized = value ? true : false;
|
||||
@@ -63,17 +69,19 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
||||
}
|
||||
}
|
||||
|
||||
public registerActionsMenuAction(action: { actionName: string; callback: Function }): void {
|
||||
this.registeredActions.push(action);
|
||||
this.updateIsClickable();
|
||||
public registerActionsMenuAction(action: ActionsMenuAction): void {
|
||||
actionsMenuStore.addAction({
|
||||
...action,
|
||||
priority: action.priority ?? 0,
|
||||
callback: () => {
|
||||
action.callback();
|
||||
actionsMenuStore.clear();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public unregisterActionsMenuAction(actionName: string) {
|
||||
const index = this.registeredActions.findIndex((action) => action.actionName === actionName);
|
||||
if (index !== -1) {
|
||||
this.registeredActions.splice(index, 1);
|
||||
}
|
||||
this.updateIsClickable();
|
||||
actionsMenuStore.removeAction(actionName);
|
||||
}
|
||||
|
||||
public activate(): void {
|
||||
@@ -90,37 +98,52 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
||||
return this.isClickable();
|
||||
}
|
||||
|
||||
private updateIsClickable(): void {
|
||||
this.setClickable(this.registeredActions.length > 0);
|
||||
}
|
||||
|
||||
private toggleActionsMenu(): void {
|
||||
if (this.isActionsMenuInitialized) {
|
||||
actionsMenuStore.clear();
|
||||
return;
|
||||
}
|
||||
actionsMenuStore.initialize(this.playerName);
|
||||
for (const action of this.registeredActions) {
|
||||
actionsMenuStore.addAction(action.actionName, action.callback);
|
||||
for (const action of this.getDefaultActionsMenuActions()) {
|
||||
actionsMenuStore.addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
private registerDefaultActionsMenuActions(): void {
|
||||
private getDefaultActionsMenuActions(): ActionsMenuAction[] {
|
||||
const actions: ActionsMenuAction[] = [];
|
||||
if (this.visitCardUrl) {
|
||||
this.registeredActions.push({
|
||||
actions.push({
|
||||
actionName: LL.woka.menu.businessCard(),
|
||||
protected: true,
|
||||
priority: 1,
|
||||
callback: () => {
|
||||
requestVisitCardsStore.set(this.visitCardUrl);
|
||||
actionsMenuStore.clear();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
actions.push({
|
||||
actionName: blackListManager.isBlackListed(this.userUuid)
|
||||
? LL.report.block.unblock()
|
||||
: LL.report.block.block(),
|
||||
protected: true,
|
||||
priority: -1,
|
||||
style: "is-error",
|
||||
callback: () => {
|
||||
showReportScreenStore.set({ userId: this.userId, userName: this.name });
|
||||
actionsMenuStore.clear();
|
||||
},
|
||||
});
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private bindEventHandlers(): void {
|
||||
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
|
||||
if (event.downElement.nodeName === "CANVAS" && event.leftButtonDown()) {
|
||||
this.toggleActionsMenu();
|
||||
this.emit(RemotePlayerEvent.Clicked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { EnableCameraSceneName } from "../Login/EnableCameraScene";
|
||||
import { LoginSceneName } from "../Login/LoginScene";
|
||||
import { SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||
import { GameScene } from "./GameScene";
|
||||
import { EmptySceneName } from "../Login/EmptyScene";
|
||||
|
||||
/**
|
||||
* This class should be responsible for any scene starting/stopping
|
||||
@@ -19,7 +20,7 @@ export class GameManager {
|
||||
private companion: string | null;
|
||||
private startRoom!: Room;
|
||||
private cameraSetup?: { video: unknown; audio: unknown };
|
||||
currentGameSceneName: string | null = null;
|
||||
private currentGameSceneName: string | null = null;
|
||||
// Note: this scenePlugin is the scenePlugin of the EntryScene. We should always provide a key in methods called on this scenePlugin.
|
||||
private scenePlugin!: Phaser.Scenes.ScenePlugin;
|
||||
|
||||
@@ -32,7 +33,14 @@ export class GameManager {
|
||||
|
||||
public async init(scenePlugin: Phaser.Scenes.ScenePlugin): Promise<string> {
|
||||
this.scenePlugin = scenePlugin;
|
||||
this.startRoom = await connectionManager.initGameConnexion();
|
||||
const result = await connectionManager.initGameConnexion();
|
||||
if (result instanceof URL) {
|
||||
window.location.assign(result.toString());
|
||||
// window.location.assign is not immediate and Javascript keeps running after.
|
||||
// so we need to redirect to an empty Phaser scene, waiting for the redirection to take place
|
||||
return EmptySceneName;
|
||||
}
|
||||
this.startRoom = result;
|
||||
this.loadMap(this.startRoom);
|
||||
|
||||
//If player name was not set show login scene with player name
|
||||
|
||||
@@ -126,19 +126,7 @@ export class GameMap {
|
||||
for (let y = 0; y < this.map.height; y += 1) {
|
||||
const row: number[] = [];
|
||||
for (let x = 0; x < this.map.width; x += 1) {
|
||||
row.push(this.isCollidingAt(x, y) ? 1 : 0);
|
||||
}
|
||||
grid.push(row);
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
|
||||
public getWalkingCostGrid(): number[][] {
|
||||
const grid: number[][] = [];
|
||||
for (let y = 0; y < this.map.height; y += 1) {
|
||||
const row: number[] = [];
|
||||
for (let x = 0; x < this.map.width; x += 1) {
|
||||
row.push(this.getWalkingCostAt(x, y));
|
||||
row.push(this.isCollidingAt(x, y) ? 1 : this.isExitTile(x, y) ? 2 : 0);
|
||||
}
|
||||
grid.push(row);
|
||||
}
|
||||
@@ -355,8 +343,7 @@ export class GameMap {
|
||||
return false;
|
||||
}
|
||||
|
||||
private getWalkingCostAt(x: number, y: number): number {
|
||||
const bigCost = 100;
|
||||
private isExitTile(x: number, y: number): boolean {
|
||||
for (const layer of this.phaserLayers) {
|
||||
if (!layer.visible) {
|
||||
continue;
|
||||
@@ -369,16 +356,16 @@ export class GameMap {
|
||||
tile &&
|
||||
(tile.properties[GameMapProperties.EXIT_URL] || tile.properties[GameMapProperties.EXIT_SCENE_URL])
|
||||
) {
|
||||
return bigCost;
|
||||
return true;
|
||||
}
|
||||
for (const property of layer.layer.properties) {
|
||||
//@ts-ignore
|
||||
if (property.name && property.name === "exitUrl") {
|
||||
return bigCost;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
private triggerAllProperties(): void {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { soundManager } from "./SoundManager";
|
||||
import { SharedVariablesManager } from "./SharedVariablesManager";
|
||||
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
||||
|
||||
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||
import { lazyLoadPlayerCharacterTextures } from "../Entity/PlayerTexturesLoadingManager";
|
||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||
import { iframeListener } from "../../Api/IframeListener";
|
||||
import { DEBUG_MODE, JITSI_URL, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
||||
@@ -30,7 +30,7 @@ import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||
import { SimplePeer } from "../../WebRtc/SimplePeer";
|
||||
import { Loader } from "../Components/Loader";
|
||||
import { RemotePlayer } from "../Entity/RemotePlayer";
|
||||
import { RemotePlayer, RemotePlayerEvent } from "../Entity/RemotePlayer";
|
||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||
import { PlayerAnimationDirections } from "../Player/Animation";
|
||||
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
|
||||
@@ -98,6 +98,10 @@ import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
||||
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
||||
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||
import type { VideoPeer } from "../../WebRtc/VideoPeer";
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import { Deferred } from "ts-deferred";
|
||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface | null;
|
||||
reconnecting: boolean;
|
||||
@@ -163,13 +167,9 @@ export class GameScene extends DirtyScene {
|
||||
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
||||
public connection: RoomConnection | undefined;
|
||||
private simplePeer!: SimplePeer;
|
||||
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
||||
private connectionAnswerPromiseResolve!: (
|
||||
value: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>
|
||||
) => void;
|
||||
private connectionAnswerPromiseDeferred: Deferred<RoomJoinedMessageInterface>;
|
||||
// A promise that will resolve when the "create" method is called (signaling loading is ended)
|
||||
private createPromise: Promise<void>;
|
||||
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
|
||||
private createPromiseDeferred: Deferred<void>;
|
||||
private iframeSubscriptionList!: Array<Subscription>;
|
||||
private peerStoreUnsubscribe!: Unsubscriber;
|
||||
private emoteUnsubscribe!: Unsubscriber;
|
||||
@@ -221,6 +221,7 @@ export class GameScene extends DirtyScene {
|
||||
private lastCameraEvent: WasCameraUpdatedEvent | undefined;
|
||||
private firstCameraUpdateSent: boolean = false;
|
||||
private currentPlayerGroupId?: number;
|
||||
public readonly superLoad: SuperLoaderPlugin;
|
||||
|
||||
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
|
||||
super({
|
||||
@@ -233,13 +234,10 @@ export class GameScene extends DirtyScene {
|
||||
this.MapUrlFile = MapUrlFile;
|
||||
this.roomUrl = room.key;
|
||||
|
||||
this.createPromise = new Promise<void>((resolve, reject): void => {
|
||||
this.createPromiseResolve = resolve;
|
||||
});
|
||||
this.connectionAnswerPromise = new Promise<RoomJoinedMessageInterface>((resolve, reject): void => {
|
||||
this.connectionAnswerPromiseResolve = resolve;
|
||||
});
|
||||
this.createPromiseDeferred = new Deferred<void>();
|
||||
this.connectionAnswerPromiseDeferred = new Deferred<RoomJoinedMessageInterface>();
|
||||
this.loader = new Loader(this);
|
||||
this.superLoad = new SuperLoaderPlugin(this);
|
||||
}
|
||||
|
||||
//hook preload scene
|
||||
@@ -247,13 +245,6 @@ export class GameScene extends DirtyScene {
|
||||
//initialize frame event of scripting API
|
||||
this.listenToIframeEvents();
|
||||
|
||||
const localUser = localUserStore.getLocalUser();
|
||||
const textures = localUser?.textures;
|
||||
if (textures) {
|
||||
for (const texture of textures) {
|
||||
loadCustomTexture(this.load, texture).catch((e) => console.error(e));
|
||||
}
|
||||
}
|
||||
this.load.image("iconTalk", "/resources/icons/icon_talking.png");
|
||||
|
||||
if (touchScreenManager.supportTouchScreen) {
|
||||
@@ -416,11 +407,11 @@ export class GameScene extends DirtyScene {
|
||||
this.load.on("complete", () => {
|
||||
// FIXME: the factory might fail because the resources might not be loaded yet...
|
||||
// We would need to add a loader ended event in addition to the createPromise
|
||||
this.createPromise
|
||||
this.createPromiseDeferred.promise
|
||||
.then(async () => {
|
||||
itemFactory.create(this);
|
||||
|
||||
const roomJoinedAnswer = await this.connectionAnswerPromise;
|
||||
const roomJoinedAnswer = await this.connectionAnswerPromiseDeferred.promise;
|
||||
|
||||
for (const object of objectsOfType) {
|
||||
// TODO: we should pass here a factory to create sprites (maybe?)
|
||||
@@ -574,7 +565,6 @@ export class GameScene extends DirtyScene {
|
||||
this.pathfindingManager = new PathfindingManager(
|
||||
this,
|
||||
this.gameMap.getCollisionGrid(),
|
||||
this.gameMap.getWalkingCostGrid(),
|
||||
this.gameMap.getTileDimensions()
|
||||
);
|
||||
|
||||
@@ -618,7 +608,7 @@ export class GameScene extends DirtyScene {
|
||||
}
|
||||
}
|
||||
|
||||
this.createPromiseResolve();
|
||||
this.createPromiseDeferred.resolve();
|
||||
// Now, let's load the script, if any
|
||||
const scripts = this.getScriptUrls(this.mapFile);
|
||||
const disableModuleMode = this.getProperty(this.mapFile, GameMapProperties.SCRIPT_DISABLE_MODULE_SUPPORT) as
|
||||
@@ -644,7 +634,7 @@ export class GameScene extends DirtyScene {
|
||||
}
|
||||
|
||||
const talkIconVolumeTreshold = 10;
|
||||
let oldPeerNumber = 0;
|
||||
const oldPeers = new Map<number, VideoPeer>();
|
||||
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
||||
this.volumeStoreUnsubscribers.forEach((unsubscribe) => unsubscribe());
|
||||
this.volumeStoreUnsubscribers.clear();
|
||||
@@ -661,10 +651,17 @@ export class GameScene extends DirtyScene {
|
||||
}
|
||||
|
||||
const newPeerNumber = peers.size;
|
||||
if (newPeerNumber > oldPeerNumber) {
|
||||
if (newPeerNumber > oldPeers.size) {
|
||||
this.playSound("audio-webrtc-in");
|
||||
} else if (newPeerNumber < oldPeerNumber) {
|
||||
} else if (newPeerNumber < oldPeers.size) {
|
||||
this.playSound("audio-webrtc-out");
|
||||
const oldPeersKeys = oldPeers.keys();
|
||||
const newPeersKeys = Array.from(peers.keys());
|
||||
for (const oldKey of oldPeersKeys) {
|
||||
if (!newPeersKeys.includes(oldKey)) {
|
||||
this.MapPlayersByKey.get(oldKey)?.showTalkIcon(false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newPeerNumber > 0) {
|
||||
if (!this.localVolumeStoreUnsubscriber) {
|
||||
@@ -682,7 +679,10 @@ export class GameScene extends DirtyScene {
|
||||
this.localVolumeStoreUnsubscriber = undefined;
|
||||
}
|
||||
}
|
||||
oldPeerNumber = newPeerNumber;
|
||||
oldPeers.clear();
|
||||
for (const [key, val] of peers) {
|
||||
oldPeers.set(key, val);
|
||||
}
|
||||
});
|
||||
|
||||
this.emoteUnsubscribe = emoteStore.subscribe((emote) => {
|
||||
@@ -715,7 +715,11 @@ export class GameScene extends DirtyScene {
|
||||
this.currentPlayerGroupId = groupId;
|
||||
});
|
||||
|
||||
Promise.all([this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises])
|
||||
Promise.all([
|
||||
this.connectionAnswerPromiseDeferred.promise as Promise<unknown>,
|
||||
...scriptPromises,
|
||||
this.CurrentPlayer.getTextureLoadedPromise() as Promise<unknown>,
|
||||
])
|
||||
.then(() => {
|
||||
this.scene.wake();
|
||||
})
|
||||
@@ -752,6 +756,14 @@ export class GameScene extends DirtyScene {
|
||||
.then((onConnect: OnConnectInterface) => {
|
||||
this.connection = onConnect.connection;
|
||||
|
||||
lazyLoadPlayerCharacterTextures(this.superLoad, onConnect.room.characterLayers)
|
||||
.then((layers) => {
|
||||
this.currentPlayerTexturesResolve(layers);
|
||||
})
|
||||
.catch((e) => {
|
||||
this.currentPlayerTexturesReject(e);
|
||||
});
|
||||
|
||||
playersStore.connectToRoomConnection(this.connection);
|
||||
userIsAdminStore.set(this.connection.hasTag("admin"));
|
||||
|
||||
@@ -878,7 +890,7 @@ export class GameScene extends DirtyScene {
|
||||
);
|
||||
|
||||
//this.initUsersPosition(roomJoinedMessage.users);
|
||||
this.connectionAnswerPromiseResolve(onConnect.room);
|
||||
this.connectionAnswerPromiseDeferred.resolve(onConnect.room);
|
||||
// Analyze tags to find if we are admin. If yes, show console.
|
||||
|
||||
if (this.scene.isSleeping()) {
|
||||
@@ -1122,6 +1134,23 @@ ${escapedMessage}
|
||||
})
|
||||
);
|
||||
|
||||
this.iframeSubscriptionList.push(
|
||||
iframeListener.addActionsMenuKeyToRemotePlayerStream.subscribe((data) => {
|
||||
this.MapPlayersByKey.get(data.id)?.registerActionsMenuAction({
|
||||
actionName: data.actionKey,
|
||||
callback: () => {
|
||||
iframeListener.sendActionsMenuActionClickedEvent({ actionName: data.actionKey, id: data.id });
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
this.iframeSubscriptionList.push(
|
||||
iframeListener.removeActionsMenuKeyFromRemotePlayerEvent.subscribe((data) => {
|
||||
this.MapPlayersByKey.get(data.id)?.unregisterActionsMenuAction(data.actionKey);
|
||||
})
|
||||
);
|
||||
|
||||
this.iframeSubscriptionList.push(
|
||||
iframeListener.trackCameraUpdateStream.subscribe(() => {
|
||||
if (!this.firstCameraUpdateSent) {
|
||||
@@ -1280,7 +1309,7 @@ ${escapedMessage}
|
||||
iframeListener.registerAnswerer("getState", async () => {
|
||||
// The sharedVariablesManager is not instantiated before the connection is established. So we need to wait
|
||||
// for the connection to send back the answer.
|
||||
await this.connectionAnswerPromise;
|
||||
await this.connectionAnswerPromiseDeferred.promise;
|
||||
return {
|
||||
mapUrl: this.MapUrlFile,
|
||||
startLayerName: this.startPositionCalculator.startLayerName,
|
||||
@@ -1303,7 +1332,7 @@ ${escapedMessage}
|
||||
})
|
||||
);
|
||||
iframeListener.registerAnswerer("loadTileset", (eventTileset) => {
|
||||
return this.connectionAnswerPromise.then(() => {
|
||||
return this.connectionAnswerPromiseDeferred.promise.then(() => {
|
||||
const jsonTilesetDir = eventTileset.url.substr(0, eventTileset.url.lastIndexOf("/"));
|
||||
//Initialise the firstgid to 1 because if there is no tileset in the tilemap, the firstgid will be 1
|
||||
let newFirstgid = 1;
|
||||
@@ -1466,7 +1495,7 @@ ${escapedMessage}
|
||||
phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
|
||||
}
|
||||
}
|
||||
this.pathfindingManager.setCollisionGrid(this.gameMap.getCollisionGrid(), this.gameMap.getWalkingCostGrid());
|
||||
this.pathfindingManager.setCollisionGrid(this.gameMap.getCollisionGrid());
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
@@ -1548,7 +1577,7 @@ ${escapedMessage}
|
||||
this.messageSubscription?.unsubscribe();
|
||||
this.userInputManager.destroy();
|
||||
this.pinchManager?.destroy();
|
||||
this.emoteManager.destroy();
|
||||
this.emoteManager?.destroy();
|
||||
this.cameraManager.destroy();
|
||||
this.peerStoreUnsubscribe();
|
||||
this.emoteUnsubscribe();
|
||||
@@ -1614,6 +1643,8 @@ ${escapedMessage}
|
||||
}
|
||||
})
|
||||
.catch((reason) => console.warn(reason));
|
||||
|
||||
urlManager.clearHashParameter();
|
||||
} catch (err) {
|
||||
console.warn(`Cannot proceed with moveTo command:\n\t-> ${err}`);
|
||||
}
|
||||
@@ -1705,16 +1736,23 @@ ${escapedMessage}
|
||||
}
|
||||
}
|
||||
|
||||
// The promise that will resolve to the current player texture. This will be available only after connection is established.
|
||||
private currentPlayerTexturesResolve!: (value: string[]) => void;
|
||||
private currentPlayerTexturesReject!: (reason: unknown) => void;
|
||||
private currentPlayerTexturesPromise: CancelablePromise<string[]> = new CancelablePromise((resolve, reject) => {
|
||||
this.currentPlayerTexturesResolve = resolve;
|
||||
this.currentPlayerTexturesReject = reject;
|
||||
});
|
||||
|
||||
private createCurrentPlayer() {
|
||||
//TODO create animation moving between exit and start
|
||||
const texturesPromise = lazyLoadPlayerCharacterTextures(this.load, this.characterLayers);
|
||||
try {
|
||||
this.CurrentPlayer = new Player(
|
||||
this,
|
||||
this.startPositionCalculator.startPosition.x,
|
||||
this.startPositionCalculator.startPosition.y,
|
||||
this.playerName,
|
||||
texturesPromise,
|
||||
this.currentPlayerTexturesPromise,
|
||||
PlayerAnimationDirections.Down,
|
||||
false,
|
||||
this.companion,
|
||||
@@ -1898,9 +1936,10 @@ ${escapedMessage}
|
||||
return;
|
||||
}
|
||||
|
||||
const texturesPromise = lazyLoadPlayerCharacterTextures(this.load, addPlayerData.characterLayers);
|
||||
const texturesPromise = lazyLoadPlayerCharacterTextures(this.superLoad, addPlayerData.characterLayers);
|
||||
const player = new RemotePlayer(
|
||||
addPlayerData.userId,
|
||||
addPlayerData.userUuid,
|
||||
this,
|
||||
addPlayerData.position.x,
|
||||
addPlayerData.position.y,
|
||||
@@ -1928,6 +1967,10 @@ ${escapedMessage}
|
||||
this.activatablesManager.handlePointerOutActivatableObject();
|
||||
this.markDirty();
|
||||
});
|
||||
|
||||
player.on(RemotePlayerEvent.Clicked, () => {
|
||||
iframeListener.sendRemotePlayerClickedEvent({ id: player.userId });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2070,8 +2113,6 @@ ${escapedMessage}
|
||||
right: camera.scrollX + camera.width,
|
||||
bottom: camera.scrollY + camera.height,
|
||||
});
|
||||
|
||||
this.loader.resize();
|
||||
}
|
||||
|
||||
private getObjectLayerData(objectName: string): ITiledMapObject | undefined {
|
||||
|
||||
@@ -1,41 +1,18 @@
|
||||
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 { BodyResourceDescriptionInterface, PlayerTexturesKey } from "../Entity/PlayerTextures";
|
||||
import { loadWokaTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||
import type CancelablePromise from "cancelable-promise";
|
||||
import { PlayerTextures } from "../Entity/PlayerTextures";
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||
|
||||
export abstract class AbstractCharacterScene extends ResizableScene {
|
||||
loadCustomSceneSelectCharacters(): Promise<BodyResourceDescriptionInterface[]> {
|
||||
const textures = this.getTextures();
|
||||
const promises: CancelablePromise<BodyResourceDescriptionInterface>[] = [];
|
||||
if (textures) {
|
||||
for (const texture of textures) {
|
||||
if (texture.level === -1) {
|
||||
continue;
|
||||
}
|
||||
promises.push(loadCustomTexture(this.load, texture));
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
protected playerTextures: PlayerTextures;
|
||||
protected superLoad: SuperLoaderPlugin;
|
||||
|
||||
loadSelectSceneCharacters(): Promise<BodyResourceDescriptionInterface[]> {
|
||||
const textures = this.getTextures();
|
||||
const promises: CancelablePromise<BodyResourceDescriptionInterface>[] = [];
|
||||
if (textures) {
|
||||
for (const texture of textures) {
|
||||
if (texture.level !== -1) {
|
||||
continue;
|
||||
}
|
||||
promises.push(loadCustomTexture(this.load, texture));
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
private getTextures(): CharacterTexture[] | undefined {
|
||||
const localUser = localUserStore.getLocalUser();
|
||||
return localUser?.textures;
|
||||
constructor(params: { key: string }) {
|
||||
super(params);
|
||||
this.playerTextures = new PlayerTextures();
|
||||
this.superLoad = new SuperLoaderPlugin(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import { CustomizedCharacter } from "../Entity/CustomizedCharacter";
|
||||
import { get } from "svelte/store";
|
||||
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
|
||||
import { wokaList } from "../../Messages/JsonMessages/PlayerTextures";
|
||||
|
||||
export const CustomizeSceneName = "CustomizeScene";
|
||||
|
||||
@@ -40,25 +42,28 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.loadCustomSceneSelectCharacters()
|
||||
.then((bodyResourceDescriptions) => {
|
||||
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
|
||||
if (
|
||||
bodyResourceDescription.level == undefined ||
|
||||
bodyResourceDescription.level < 0 ||
|
||||
bodyResourceDescription.level > 5
|
||||
) {
|
||||
throw new Error("Texture level is null");
|
||||
}
|
||||
this.layers[bodyResourceDescription.level].unshift(bodyResourceDescription);
|
||||
});
|
||||
this.lazyloadingAttempt = true;
|
||||
})
|
||||
const wokaMetadataKey = "woka-list" + gameManager.currentStartedRoom.href;
|
||||
this.cache.json.remove(wokaMetadataKey);
|
||||
this.superLoad
|
||||
.json(
|
||||
wokaMetadataKey,
|
||||
`${PUSHER_URL}/woka/list?roomUrl=` + encodeURIComponent(gameManager.currentStartedRoom.href),
|
||||
undefined,
|
||||
{
|
||||
responseType: "text",
|
||||
headers: {
|
||||
Authorization: localUserStore.getAuthToken() ?? "",
|
||||
},
|
||||
withCredentials: true,
|
||||
},
|
||||
(key, type, data) => {
|
||||
this.playerTextures.loadPlayerTexturesMetadata(wokaList.parse(data));
|
||||
|
||||
this.layers = loadAllLayers(this.load, this.playerTextures);
|
||||
this.lazyloadingAttempt = false;
|
||||
}
|
||||
)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
this.layers = loadAllLayers(this.load);
|
||||
this.lazyloadingAttempt = false;
|
||||
|
||||
//this function must stay at the end of preload function
|
||||
this.loader.addLoader();
|
||||
}
|
||||
@@ -192,13 +197,13 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
const children: Array<string> = new Array<string>();
|
||||
for (let j = 0; j <= layerNumber; j++) {
|
||||
if (j === layerNumber) {
|
||||
children.push(this.layers[j][selectedItem].name);
|
||||
children.push(this.layers[j][selectedItem].id);
|
||||
} else {
|
||||
const layer = this.selectedLayers[j];
|
||||
if (layer === undefined) {
|
||||
continue;
|
||||
}
|
||||
children.push(this.layers[j][layer].name);
|
||||
children.push(this.layers[j][layer].id);
|
||||
}
|
||||
}
|
||||
return children;
|
||||
@@ -276,7 +281,7 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
let i = 0;
|
||||
for (const layerItem of this.selectedLayers) {
|
||||
if (layerItem !== undefined) {
|
||||
layers.push(this.layers[i][layerItem].name);
|
||||
layers.push(this.layers[i][layerItem].id);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -287,14 +292,14 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
analyticsClient.validationWoka("CustomizeWoka");
|
||||
|
||||
gameManager.setCharacterLayers(layers);
|
||||
this.scene.sleep(CustomizeSceneName);
|
||||
this.scene.stop(CustomizeSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
gameManager.tryResumingGame(EnableCameraSceneName);
|
||||
customCharacterSceneVisibleStore.set(false);
|
||||
}
|
||||
|
||||
public backToPreviousScene() {
|
||||
this.scene.sleep(CustomizeSceneName);
|
||||
this.scene.stop(CustomizeSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
this.scene.run(SelectCharacterSceneName);
|
||||
customCharacterSceneVisibleStore.set(false);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Scene } from "phaser";
|
||||
|
||||
export const EmptySceneName = "EmptyScene";
|
||||
|
||||
export class EmptyScene extends Scene {
|
||||
constructor() {
|
||||
super({
|
||||
key: EmptySceneName,
|
||||
});
|
||||
}
|
||||
|
||||
preload() {}
|
||||
|
||||
create() {}
|
||||
|
||||
update(time: number, delta: number): void {}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import { ReconnectingTextures } from "../Reconnecting/ReconnectingScene";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import { get } from "svelte/store";
|
||||
import { localeDetector } from "../../i18n/locales";
|
||||
import { PlayerTextures } from "../Entity/PlayerTextures";
|
||||
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
|
||||
|
||||
export const EntrySceneName = "EntryScene";
|
||||
|
||||
@@ -15,6 +17,8 @@ export const EntrySceneName = "EntryScene";
|
||||
* and to route to the next correct scene.
|
||||
*/
|
||||
export class EntryScene extends Scene {
|
||||
private localeLoaded: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
key: EntrySceneName,
|
||||
@@ -30,6 +34,10 @@ export class EntryScene extends Scene {
|
||||
}
|
||||
|
||||
create() {
|
||||
this.loadLocale();
|
||||
}
|
||||
|
||||
private loadLocale(): void {
|
||||
localeDetector()
|
||||
.then(() => {
|
||||
gameManager
|
||||
|
||||
@@ -28,7 +28,10 @@ export class LoginScene extends ResizableScene {
|
||||
gameManager.currentStartedRoom &&
|
||||
gameManager.currentStartedRoom.authenticationMandatory
|
||||
) {
|
||||
connectionManager.loadOpenIDScreen();
|
||||
const redirect = connectionManager.loadOpenIDScreen();
|
||||
if (redirect !== null) {
|
||||
window.location.assign(redirect.toString());
|
||||
}
|
||||
loginSceneVisibleIframeStore.set(true);
|
||||
}
|
||||
loginSceneVisibleStore.set(true);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { CustomizeSceneName } from "./CustomizeScene";
|
||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import { loadAllDefaultModels } from "../Entity/PlayerTexturesLoadingManager";
|
||||
import { Loader } from "../Components/Loader";
|
||||
import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
|
||||
import { BodyResourceDescriptionInterface, PlayerTextures } from "../Entity/PlayerTextures";
|
||||
import { AbstractCharacterScene } from "./AbstractCharacterScene";
|
||||
import { areCharacterLayersValid } from "../../Connexion/LocalUser";
|
||||
import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
||||
@@ -14,6 +14,9 @@ import { selectCharacterSceneVisibleStore } from "../../Stores/SelectCharacterSt
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
|
||||
import { customizeAvailableStore } from "../../Stores/SelectCharacterSceneStore";
|
||||
import { wokaList } from "../../Messages/JsonMessages/PlayerTextures";
|
||||
|
||||
//todo: put this constants in a dedicated file
|
||||
export const SelectCharacterSceneName = "SelectCharacterScene";
|
||||
@@ -38,25 +41,39 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
key: SelectCharacterSceneName,
|
||||
});
|
||||
this.loader = new Loader(this);
|
||||
this.playerTextures = new PlayerTextures();
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.loadSelectSceneCharacters()
|
||||
.then((bodyResourceDescriptions) => {
|
||||
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
|
||||
this.playerModels.push(bodyResourceDescription);
|
||||
});
|
||||
this.lazyloadingAttempt = true;
|
||||
})
|
||||
const wokaMetadataKey = "woka-list" + gameManager.currentStartedRoom.href;
|
||||
this.cache.json.remove(wokaMetadataKey);
|
||||
|
||||
this.superLoad
|
||||
.json(
|
||||
wokaMetadataKey,
|
||||
`${PUSHER_URL}/woka/list?roomUrl=` + encodeURIComponent(gameManager.currentStartedRoom.href),
|
||||
undefined,
|
||||
{
|
||||
responseType: "text",
|
||||
headers: {
|
||||
Authorization: localUserStore.getAuthToken() ?? "",
|
||||
},
|
||||
withCredentials: true,
|
||||
},
|
||||
(key, type, data) => {
|
||||
this.playerTextures.loadPlayerTexturesMetadata(wokaList.parse(data));
|
||||
this.playerModels = loadAllDefaultModels(this.load, this.playerTextures);
|
||||
this.lazyloadingAttempt = false;
|
||||
}
|
||||
)
|
||||
.catch((e) => console.error(e));
|
||||
this.playerModels = loadAllDefaultModels(this.load);
|
||||
this.lazyloadingAttempt = false;
|
||||
|
||||
//this function must stay at the end of preload function
|
||||
this.loader.addLoader();
|
||||
}
|
||||
|
||||
create() {
|
||||
customizeAvailableStore.set(this.isCustomizationAvailable());
|
||||
selectCharacterSceneVisibleStore.set(true);
|
||||
this.events.addListener("wake", () => {
|
||||
waScaleManager.saveZoom();
|
||||
@@ -130,16 +147,16 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
const playerResource = this.playerModels[i];
|
||||
|
||||
//check already exist texture
|
||||
if (this.players.find((c) => c.texture.key === playerResource.name)) {
|
||||
if (this.players.find((c) => c.texture.key === playerResource.id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const [middleX, middleY] = this.getCharacterPosition();
|
||||
const player = this.physics.add.sprite(middleX, middleY, playerResource.name, 0);
|
||||
const player = this.physics.add.sprite(middleX, middleY, playerResource.id, 0);
|
||||
this.setUpPlayer(player, i);
|
||||
this.anims.create({
|
||||
key: playerResource.name,
|
||||
frames: this.anims.generateFrameNumbers(playerResource.name, { start: 0, end: 11 }),
|
||||
key: playerResource.id,
|
||||
frames: this.anims.generateFrameNumbers(playerResource.id, { start: 0, end: 11 }),
|
||||
frameRate: 8,
|
||||
repeat: -1,
|
||||
});
|
||||
@@ -164,7 +181,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
this.currentSelectUser = 0;
|
||||
}
|
||||
this.selectedPlayer = this.players[this.currentSelectUser];
|
||||
this.selectedPlayer.play(this.playerModels[this.currentSelectUser].name);
|
||||
this.selectedPlayer.play(this.playerModels[this.currentSelectUser].id);
|
||||
}
|
||||
|
||||
protected moveUser() {
|
||||
@@ -247,9 +264,9 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
}
|
||||
|
||||
protected updateSelectedPlayer(): void {
|
||||
this.selectedPlayer?.anims.pause(this.selectedPlayer?.anims.currentAnim.frames[0]);
|
||||
this.selectedPlayer?.anims?.pause(this.selectedPlayer?.anims.currentAnim.frames[0]);
|
||||
const player = this.players[this.currentSelectUser];
|
||||
player.play(this.playerModels[this.currentSelectUser].name);
|
||||
player?.play(this.playerModels[this.currentSelectUser].id);
|
||||
this.selectedPlayer = player;
|
||||
localUserStore.setPlayerCharacterIndex(this.currentSelectUser);
|
||||
}
|
||||
@@ -274,4 +291,13 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
//move position of user
|
||||
this.moveUser();
|
||||
}
|
||||
|
||||
private isCustomizationAvailable(): boolean {
|
||||
for (const layer of this.playerTextures.getLayers()) {
|
||||
if (Object.keys(layer).length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export class Player extends Character {
|
||||
speed?: number
|
||||
): Promise<{ x: number; y: number; cancelled: boolean }> {
|
||||
const isPreviousPathInProgress = this.pathToFollow !== undefined && this.pathToFollow.length > 0;
|
||||
// take collider offset into consideraton
|
||||
// take collider offset into consideration
|
||||
this.pathToFollow = this.adjustPathToFollowToColliderBounds(path);
|
||||
this.pathWalkingSpeed = speed;
|
||||
return new Promise((resolve) => {
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import { Scene } from "phaser";
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
|
||||
/**
|
||||
* A wrapper around Phaser LoaderPlugin. Each method returns a (cancelable) Promise that resolves as soon as
|
||||
* the file is loaded.
|
||||
*
|
||||
* As a bonus, if the scene is destroyed BEFORE the promise resolves, the promise is canceled automatically.
|
||||
* So there is no risk of trying to add a resource on a closed scene.
|
||||
*/
|
||||
export class SuperLoaderPlugin {
|
||||
constructor(private scene: Scene) {}
|
||||
|
||||
public spritesheet(
|
||||
key: string,
|
||||
url: string,
|
||||
frameConfig?: Phaser.Types.Loader.FileTypes.ImageFrameConfig,
|
||||
xhrSettings?: Phaser.Types.Loader.XHRSettingsObject
|
||||
) {
|
||||
return this.loadResource<Texture>(
|
||||
() => {
|
||||
this.scene.load.spritesheet(key, url, frameConfig, xhrSettings);
|
||||
},
|
||||
key,
|
||||
url,
|
||||
() => {
|
||||
if (this.scene.load.textureManager.exists(key)) {
|
||||
return this.scene.load.textureManager.get(key);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
"spritesheet"
|
||||
);
|
||||
}
|
||||
|
||||
public image(key: string, url: string, xhrSettings?: Phaser.Types.Loader.XHRSettingsObject) {
|
||||
return this.loadResource<Texture>(
|
||||
() => {
|
||||
this.scene.load.image(key, url, xhrSettings);
|
||||
},
|
||||
key,
|
||||
url,
|
||||
() => {
|
||||
if (this.scene.load.textureManager.exists(key)) {
|
||||
return this.scene.load.textureManager.get(key);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
"image"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @param url
|
||||
* @param dataKey
|
||||
* @param xhrSettings
|
||||
* @param immediateCallback The function returns a promise BUT the "then" promise will be triggered after the current Javascript thread finishes. In case of Phaser loader, this can be a problem if you want to add additional resources to the loader in the callback. The "immediateCallback" triggers directly in the
|
||||
*/
|
||||
public json(
|
||||
key: string,
|
||||
url: string,
|
||||
dataKey?: string,
|
||||
xhrSettings?: Phaser.Types.Loader.XHRSettingsObject,
|
||||
immediateCallback?: (key: string, type: string, data: unknown) => void
|
||||
) {
|
||||
return this.loadResource<unknown>(
|
||||
() => {
|
||||
this.scene.load.json(key, url, dataKey, xhrSettings);
|
||||
},
|
||||
key,
|
||||
url,
|
||||
() => {
|
||||
if (this.scene.load.cacheManager.json.exists(key)) {
|
||||
return this.scene.load.cacheManager.json.get(key);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
"json",
|
||||
immediateCallback
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callback The function that calls the loader to load a resource
|
||||
* @param key The key of the resource to be loaded
|
||||
* @param fromCache A function that checks in the cache if the resource is already available
|
||||
* @param type The type of resource loaded
|
||||
* @param immediateCallback The function returns a promise BUT the "then" promise will be triggered after the current Javascript thread finishes. In case of Phaser loader, this can be a problem if you want to add additional resources to the loader in the callback. The "immediateCallback" triggers directly in the
|
||||
* @private
|
||||
*/
|
||||
private loadResource<T>(
|
||||
callback: () => void,
|
||||
key: string,
|
||||
url: string,
|
||||
fromCache: () => T | undefined,
|
||||
type: string,
|
||||
immediateCallback?: (key: string, type: string, data: unknown) => void
|
||||
): CancelablePromise<T> {
|
||||
// If for some reason, the "url" is empty, let's reject the promise.
|
||||
if (!url) {
|
||||
console.error("Tried to load an empty " + type + ". URL is missing.");
|
||||
return CancelablePromise.reject(Error("Failed loading " + type + ": URL is empty"));
|
||||
}
|
||||
|
||||
return new CancelablePromise<T>((res, rej, cancel) => {
|
||||
if (this.scene.scene.settings.status === Phaser.Scenes.DESTROYED) {
|
||||
rej(new Error("Trying to load a " + type + " in a Scene that is already destroyed."));
|
||||
}
|
||||
|
||||
const resource = fromCache();
|
||||
if (resource !== undefined) {
|
||||
return res(resource);
|
||||
}
|
||||
|
||||
let destroySceneEventRegistered = false;
|
||||
|
||||
const unloadCallbacks = () => {
|
||||
this.scene.load.off("filecomplete-" + type + "-" + key, successCallback);
|
||||
this.scene.load.off("loaderror", errorCallback);
|
||||
if (destroySceneEventRegistered) {
|
||||
this.scene.events.off(Phaser.Scenes.Events.DESTROY, unloadCallbacks);
|
||||
}
|
||||
};
|
||||
|
||||
const errorCallback = (file: { src: string }) => {
|
||||
if (file.src !== url) return;
|
||||
console.error("Failed loading " + type + ": ", url);
|
||||
rej(new Error('Failed loading "+type+": "' + url + '"'));
|
||||
unloadCallbacks();
|
||||
};
|
||||
|
||||
const successCallback = (key: string, type: string, data: unknown) => {
|
||||
this.scene.load.off("loaderror", errorCallback);
|
||||
this.scene.events.off(Phaser.Scenes.Events.DESTROY, unloadCallbacks);
|
||||
const resource = fromCache();
|
||||
if (!resource) {
|
||||
return rej(new Error("Newly loaded resource not available in cache"));
|
||||
}
|
||||
res(resource);
|
||||
|
||||
// The "then" callbacks registered on the promise are not executed immediately when "res" is called.
|
||||
// Instead, they are called after the current JS thread finishes.
|
||||
// In some cases, we want the callbacks to execute right now. In particular if we load a map / json file
|
||||
// that contains references to other files that needs to be loaded.
|
||||
if (immediateCallback) {
|
||||
immediateCallback(key, type, data);
|
||||
}
|
||||
console.log("Resolve done for ", url);
|
||||
};
|
||||
|
||||
cancel(() => {
|
||||
unloadCallbacks();
|
||||
});
|
||||
|
||||
callback();
|
||||
|
||||
this.scene.load.once("filecomplete-" + type + "-" + key, successCallback);
|
||||
this.scene.load.on("loaderror", errorCallback);
|
||||
if (this.scene.scene.settings.status > Phaser.Scenes.LOADING) {
|
||||
// When the scene is destroyed, let's remove our callbacks.
|
||||
// We only need to register this destroy event is the scene is not in loading state (otherwise, Phaser
|
||||
// will take care of that for us).
|
||||
destroySceneEventRegistered = true;
|
||||
this.scene.events.once(Phaser.Scenes.Events.DESTROY, unloadCallbacks);
|
||||
|
||||
// Let's start the loader if we are no more in the scene loading state
|
||||
this.scene.load.start();
|
||||
// Due to a bug, if the loader is already started, additional items are not added.... unless we
|
||||
// explicitly call the "update" method.
|
||||
this.scene.load.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user