Heavy changes: refactoring the pusher to always send the textures (and the front to accept them)
This commit is contained in:
parent
d65fe0ee26
commit
378a95962a
@ -103,6 +103,7 @@ export class SocketManager {
|
|||||||
const roomJoinedMessage = new RoomJoinedMessage();
|
const roomJoinedMessage = new RoomJoinedMessage();
|
||||||
roomJoinedMessage.setTagList(joinRoomMessage.getTagList());
|
roomJoinedMessage.setTagList(joinRoomMessage.getTagList());
|
||||||
roomJoinedMessage.setUserroomtoken(joinRoomMessage.getUserroomtoken());
|
roomJoinedMessage.setUserroomtoken(joinRoomMessage.getUserroomtoken());
|
||||||
|
roomJoinedMessage.setCharacterlayerList(joinRoomMessage.getCharacterlayerList());
|
||||||
|
|
||||||
for (const [itemId, item] of room.getItemsState().entries()) {
|
for (const [itemId, item] of room.getItemsState().entries()) {
|
||||||
const itemStateMessage = new ItemStateMessage();
|
const itemStateMessage = new ItemStateMessage();
|
||||||
|
@ -134,7 +134,7 @@ class ConnectionManager {
|
|||||||
console.error("Invalid data received from /register route. Data: ", data);
|
console.error("Invalid data received from /register route. Data: ", data);
|
||||||
throw new Error("Invalid data received from /register route.");
|
throw new Error("Invalid data received from /register route.");
|
||||||
}
|
}
|
||||||
this.localUser = new LocalUser(data.userUuid, data.textures, data.email);
|
this.localUser = new LocalUser(data.userUuid, data.email);
|
||||||
this.authToken = data.authToken;
|
this.authToken = data.authToken;
|
||||||
localUserStore.saveUser(this.localUser);
|
localUserStore.saveUser(this.localUser);
|
||||||
localUserStore.setAuthToken(this.authToken);
|
localUserStore.setAuthToken(this.authToken);
|
||||||
@ -214,32 +214,6 @@ class ConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null
|
this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null
|
||||||
|
|
||||||
if (this._currentRoom.textures != undefined && this._currentRoom.textures.length > 0) {
|
|
||||||
//check if texture was changed
|
|
||||||
if (this.localUser.textures.length === 0) {
|
|
||||||
this.localUser.textures = this._currentRoom.textures;
|
|
||||||
} else {
|
|
||||||
// TODO: the local store should NOT be used as a buffer for all the texture we were authorized to have. Bad idea.
|
|
||||||
// Instead, it is the responsibility of the ADMIN to return the EXACT list of textures we can have in a given context
|
|
||||||
// + this list can change over time or over rooms.
|
|
||||||
|
|
||||||
// 1- a room could forbid a particular dress code. In this case, the user MUST change its skin.
|
|
||||||
// 2- a room can allow "external skins from other maps" => important: think about fediverse! => switch to URLs? (with a whitelist mechanism?) => but what about NFTs?
|
|
||||||
|
|
||||||
// Note: stocker des URL dans le localstorage pour les utilisateurs actuels: mauvaise idée (empêche de mettre l'URL à jour dans le futur) => en même temps, problème avec le portage de user d'un serveur à l'autre
|
|
||||||
// Réfléchir à une notion de "character server" ??
|
|
||||||
|
|
||||||
this._currentRoom.textures.forEach((newTexture) => {
|
|
||||||
const alreadyExistTexture = this.localUser.textures.find((c) => newTexture.id === c.id);
|
|
||||||
if (this.localUser.textures.findIndex((c) => newTexture.id === c.id) !== -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.localUser.textures.push(newTexture);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
localUserStore.saveUser(this.localUser);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (this._currentRoom == undefined) {
|
if (this._currentRoom == undefined) {
|
||||||
return Promise.reject(new Error("Invalid URL"));
|
return Promise.reject(new Error("Invalid URL"));
|
||||||
@ -265,7 +239,7 @@ class ConnectionManager {
|
|||||||
|
|
||||||
public async anonymousLogin(isBenchmark: boolean = false): Promise<void> {
|
public async anonymousLogin(isBenchmark: boolean = false): Promise<void> {
|
||||||
const data = await axiosWithRetry.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data);
|
const data = await axiosWithRetry.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data);
|
||||||
this.localUser = new LocalUser(data.userUuid, [], data.email);
|
this.localUser = new LocalUser(data.userUuid, data.email);
|
||||||
this.authToken = data.authToken;
|
this.authToken = data.authToken;
|
||||||
if (!isBenchmark) {
|
if (!isBenchmark) {
|
||||||
// In benchmark, we don't have a local storage.
|
// In benchmark, we don't have a local storage.
|
||||||
@ -275,7 +249,7 @@ class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public initBenchmark(): void {
|
public initBenchmark(): void {
|
||||||
this.localUser = new LocalUser("", []);
|
this.localUser = new LocalUser("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public connectToRoomSocket(
|
public connectToRoomSocket(
|
||||||
@ -352,13 +326,13 @@ class ConnectionManager {
|
|||||||
throw new Error("No Auth code provided");
|
throw new Error("No Auth code provided");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { authToken, userUuid, textures, email } = await Axios.get(`${PUSHER_URL}/login-callback`, {
|
const { authToken, userUuid, email } = await Axios.get(`${PUSHER_URL}/login-callback`, {
|
||||||
params: { code, nonce, token, playUri: this.currentRoom?.key },
|
params: { code, nonce, token, playUri: this.currentRoom?.key },
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
return res.data;
|
return res.data;
|
||||||
});
|
});
|
||||||
localUserStore.setAuthToken(authToken);
|
localUserStore.setAuthToken(authToken);
|
||||||
this.localUser = new LocalUser(userUuid, textures, email);
|
this.localUser = new LocalUser(userUuid, email);
|
||||||
localUserStore.saveUser(this.localUser);
|
localUserStore.saveUser(this.localUser);
|
||||||
this.authToken = authToken;
|
this.authToken = authToken;
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import type { SignalData } from "simple-peer";
|
|||||||
import type { RoomConnection } from "./RoomConnection";
|
import type { RoomConnection } from "./RoomConnection";
|
||||||
import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTextures";
|
import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTextures";
|
||||||
import { PositionMessage_Direction } from "../Messages/ts-proto-generated/messages";
|
import { PositionMessage_Direction } from "../Messages/ts-proto-generated/messages";
|
||||||
|
import { CharacterLayer } from "../../../back/src/Model/Websocket/CharacterLayer";
|
||||||
|
|
||||||
export interface PointInterface {
|
export interface PointInterface {
|
||||||
x: number;
|
x: number;
|
||||||
@ -83,6 +84,7 @@ export interface RoomJoinedMessageInterface {
|
|||||||
//groups: GroupCreatedUpdatedMessageInterface[],
|
//groups: GroupCreatedUpdatedMessageInterface[],
|
||||||
items: { [itemId: number]: unknown };
|
items: { [itemId: number]: unknown };
|
||||||
variables: Map<string, unknown>;
|
variables: Map<string, unknown>;
|
||||||
|
characterLayers: BodyResourceDescriptionInterface[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlayGlobalMessageInterface {
|
export interface PlayGlobalMessageInterface {
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { MAX_USERNAME_LENGTH } from "../Enum/EnvironmentVariable";
|
import { MAX_USERNAME_LENGTH } from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
|
export type LayerNames = "woka" | "body" | "eyes" | "hair" | "clothes" | "hat" | "accessory";
|
||||||
|
|
||||||
export interface CharacterTexture {
|
export interface CharacterTexture {
|
||||||
id: number;
|
id: string;
|
||||||
level: number;
|
layer: LayerNames;
|
||||||
url: string;
|
url: string;
|
||||||
rights: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const maxUserNameLength: number = MAX_USERNAME_LENGTH;
|
export const maxUserNameLength: number = MAX_USERNAME_LENGTH;
|
||||||
@ -24,9 +25,5 @@ export function areCharacterLayersValid(value: string[] | null): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class LocalUser {
|
export class LocalUser {
|
||||||
constructor(
|
constructor(public readonly uuid: string, public email: string | null = null) {}
|
||||||
public readonly uuid: string,
|
|
||||||
public textures: CharacterTexture[],
|
|
||||||
public email: string | null = null
|
|
||||||
) {}
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import { isMapDetailsData } from "../Messages/JsonMessages/MapDetailsData";
|
|||||||
import { isRoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
|
import { isRoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
|
||||||
|
|
||||||
export class MapDetail {
|
export class MapDetail {
|
||||||
constructor(public readonly mapUrl: string, public readonly textures: CharacterTexture[] | undefined) {}
|
constructor(public readonly mapUrl: string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoomRedirect {
|
export interface RoomRedirect {
|
||||||
@ -25,7 +25,6 @@ export class Room {
|
|||||||
private _authenticationMandatory: boolean = DISABLE_ANONYMOUS;
|
private _authenticationMandatory: boolean = DISABLE_ANONYMOUS;
|
||||||
private _iframeAuthentication?: string = OPID_LOGIN_SCREEN_PROVIDER;
|
private _iframeAuthentication?: string = OPID_LOGIN_SCREEN_PROVIDER;
|
||||||
private _mapUrl: string | undefined;
|
private _mapUrl: string | undefined;
|
||||||
private _textures: CharacterTexture[] | undefined;
|
|
||||||
private instance: string | undefined;
|
private instance: string | undefined;
|
||||||
private readonly _search: URLSearchParams;
|
private readonly _search: URLSearchParams;
|
||||||
private _contactPage: string | undefined;
|
private _contactPage: string | undefined;
|
||||||
@ -118,7 +117,6 @@ export class Room {
|
|||||||
} else if (isMapDetailsData(data)) {
|
} else if (isMapDetailsData(data)) {
|
||||||
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
|
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
|
||||||
this._mapUrl = data.mapUrl;
|
this._mapUrl = data.mapUrl;
|
||||||
this._textures = data.textures;
|
|
||||||
this._group = data.group;
|
this._group = data.group;
|
||||||
this._authenticationMandatory =
|
this._authenticationMandatory =
|
||||||
data.authenticationMandatory != null ? data.authenticationMandatory : DISABLE_ANONYMOUS;
|
data.authenticationMandatory != null ? data.authenticationMandatory : DISABLE_ANONYMOUS;
|
||||||
@ -128,7 +126,7 @@ export class Room {
|
|||||||
this._expireOn = new Date(data.expireOn);
|
this._expireOn = new Date(data.expireOn);
|
||||||
}
|
}
|
||||||
this._canReport = data.canReport ?? false;
|
this._canReport = data.canReport ?? false;
|
||||||
return new MapDetail(data.mapUrl, data.textures);
|
return new MapDetail(data.mapUrl);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
|
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
|
||||||
}
|
}
|
||||||
@ -205,10 +203,6 @@ export class Room {
|
|||||||
return this.roomUrl.toString();
|
return this.roomUrl.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
get textures(): CharacterTexture[] | undefined {
|
|
||||||
return this._textures;
|
|
||||||
}
|
|
||||||
|
|
||||||
get mapUrl(): string {
|
get mapUrl(): string {
|
||||||
if (!this._mapUrl) {
|
if (!this._mapUrl) {
|
||||||
throw new Error("Map URL not fetched yet");
|
throw new Error("Map URL not fetched yet");
|
||||||
|
@ -20,7 +20,7 @@ import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTe
|
|||||||
import { adminMessagesService } from "./AdminMessagesService";
|
import { adminMessagesService } from "./AdminMessagesService";
|
||||||
import { connectionManager } from "./ConnectionManager";
|
import { connectionManager } from "./ConnectionManager";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import { warningContainerStore } from "../Stores/MenuStore";
|
import { menuIconVisiblilityStore, menuVisiblilityStore, warningContainerStore } from "../Stores/MenuStore";
|
||||||
import { followStateStore, followRoleStore, followUsersStore } from "../Stores/FollowStore";
|
import { followStateStore, followRoleStore, followUsersStore } from "../Stores/FollowStore";
|
||||||
import { localUserStore } from "./LocalUserStore";
|
import { localUserStore } from "./LocalUserStore";
|
||||||
import {
|
import {
|
||||||
@ -52,10 +52,14 @@ import {
|
|||||||
PositionMessage_Direction,
|
PositionMessage_Direction,
|
||||||
SetPlayerDetailsMessage as SetPlayerDetailsMessageTsProto,
|
SetPlayerDetailsMessage as SetPlayerDetailsMessageTsProto,
|
||||||
PingMessage as PingMessageTsProto,
|
PingMessage as PingMessageTsProto,
|
||||||
|
CharacterLayerMessage,
|
||||||
} from "../Messages/ts-proto-generated/messages";
|
} from "../Messages/ts-proto-generated/messages";
|
||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import { OpenPopupEvent } from "../Api/Events/OpenPopupEvent";
|
import { OpenPopupEvent } from "../Api/Events/OpenPopupEvent";
|
||||||
import { match } from "assert";
|
import { match } from "assert";
|
||||||
|
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
|
||||||
|
import { gameManager } from "../Phaser/Game/GameManager";
|
||||||
|
import { SelectCharacterScene, SelectCharacterSceneName } from "../Phaser/Login/SelectCharacterScene";
|
||||||
|
|
||||||
const manualPingDelay = 20000;
|
const manualPingDelay = 20000;
|
||||||
|
|
||||||
@ -336,12 +340,16 @@ export class RoomConnection implements RoomConnection {
|
|||||||
this.userId = roomJoinedMessage.currentUserId;
|
this.userId = roomJoinedMessage.currentUserId;
|
||||||
this.tags = roomJoinedMessage.tag;
|
this.tags = roomJoinedMessage.tag;
|
||||||
this._userRoomToken = roomJoinedMessage.userRoomToken;
|
this._userRoomToken = roomJoinedMessage.userRoomToken;
|
||||||
|
const characterLayers = roomJoinedMessage.characterLayer.map(
|
||||||
|
this.mapCharactgerLayerToBodyResourceDescription.bind(this)
|
||||||
|
);
|
||||||
|
|
||||||
this._roomJoinedMessageStream.next({
|
this._roomJoinedMessageStream.next({
|
||||||
connection: this,
|
connection: this,
|
||||||
room: {
|
room: {
|
||||||
items,
|
items,
|
||||||
variables,
|
variables,
|
||||||
|
characterLayers,
|
||||||
} as RoomJoinedMessageInterface,
|
} as RoomJoinedMessageInterface,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -351,6 +359,15 @@ export class RoomConnection implements RoomConnection {
|
|||||||
this.closed = true;
|
this.closed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "invalidTextureMessage": {
|
||||||
|
menuVisiblilityStore.set(false);
|
||||||
|
menuIconVisiblilityStore.set(false);
|
||||||
|
selectCharacterSceneVisibleStore.set(true);
|
||||||
|
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
||||||
|
|
||||||
|
this.closed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "tokenExpiredMessage": {
|
case "tokenExpiredMessage": {
|
||||||
connectionManager.logout().catch((e) => console.error(e));
|
connectionManager.logout().catch((e) => console.error(e));
|
||||||
this.closed = true; //technically, this isn't needed since loadOpenIDScreen() will do window.location.assign() but I prefer to leave it for consistency
|
this.closed = true; //technically, this isn't needed since loadOpenIDScreen() will do window.location.assign() but I prefer to leave it for consistency
|
||||||
@ -591,6 +608,15 @@ export class RoomConnection implements RoomConnection {
|
|||||||
});
|
});
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
private mapCharactgerLayerToBodyResourceDescription(
|
||||||
|
characterLayer: CharacterLayerMessage
|
||||||
|
): BodyResourceDescriptionInterface {
|
||||||
|
return {
|
||||||
|
name: characterLayer.name,
|
||||||
|
img: characterLayer.url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: move this to protobuf utils
|
// TODO: move this to protobuf utils
|
||||||
private toMessageUserJoined(message: UserJoinedMessageTsProto): MessageUserJoined {
|
private toMessageUserJoined(message: UserJoinedMessageTsProto): MessageUserJoined {
|
||||||
const position = message.position;
|
const position = message.position;
|
||||||
@ -598,12 +624,9 @@ export class RoomConnection implements RoomConnection {
|
|||||||
throw new Error("Invalid JOIN_ROOM message");
|
throw new Error("Invalid JOIN_ROOM message");
|
||||||
}
|
}
|
||||||
|
|
||||||
const characterLayers = message.characterLayers.map((characterLayer): BodyResourceDescriptionInterface => {
|
const characterLayers = message.characterLayers.map(
|
||||||
return {
|
this.mapCharactgerLayerToBodyResourceDescription.bind(this)
|
||||||
name: characterLayer.name,
|
);
|
||||||
img: characterLayer.url,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const companion = message.companion;
|
const companion = message.companion;
|
||||||
|
|
||||||
|
@ -83,7 +83,16 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
return lazyLoadPlayerCharacterTextures(scene.load, ["color_22", "eyes_23"]).then((textures) => {
|
return lazyLoadPlayerCharacterTextures(scene.load, [
|
||||||
|
{
|
||||||
|
name: "color_22",
|
||||||
|
img: "resources/customisation/character_color/character_color21.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "eyes_23",
|
||||||
|
img: "resources/customisation/character_eyes/character_eyes23.png",
|
||||||
|
},
|
||||||
|
]).then((textures) => {
|
||||||
this.addTextures(textures, frame);
|
this.addTextures(textures, frame);
|
||||||
this.invisible = false;
|
this.invisible = false;
|
||||||
this.playAnimation(direction, moving);
|
this.playAnimation(direction, moving);
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
//The list of all the player textures, both the default models and the partial textures used for customization
|
//The list of all the player textures, both the default models and the partial textures used for customization
|
||||||
|
|
||||||
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
|
|
||||||
|
|
||||||
export interface BodyResourceDescriptionListInterface {
|
export interface BodyResourceDescriptionListInterface {
|
||||||
[key: string]: BodyResourceDescriptionInterface;
|
[key: string]: BodyResourceDescriptionInterface;
|
||||||
}
|
}
|
||||||
@ -12,6 +10,19 @@ export interface BodyResourceDescriptionInterface {
|
|||||||
level?: number;
|
level?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,
|
||||||
|
};
|
||||||
|
|
||||||
enum PlayerTexturesKey {
|
enum PlayerTexturesKey {
|
||||||
Accessory = "accessory",
|
Accessory = "accessory",
|
||||||
Body = "body",
|
Body = "body",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
||||||
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
||||||
import { BodyResourceDescriptionInterface, PlayerTextures } from "./PlayerTextures";
|
import { BodyResourceDescriptionInterface, mapLayerToLevel, PlayerTextures } from "./PlayerTextures";
|
||||||
import CancelablePromise from "cancelable-promise";
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
|
||||||
export interface FrameConfig {
|
export interface FrameConfig {
|
||||||
@ -28,13 +28,11 @@ export const loadAllDefaultModels = (load: LoaderPlugin): BodyResourceDescriptio
|
|||||||
return returnArray;
|
return returnArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadCustomTexture = (
|
export const loadWokaTexture = (
|
||||||
loaderPlugin: LoaderPlugin,
|
loaderPlugin: LoaderPlugin,
|
||||||
texture: CharacterTexture
|
texture: BodyResourceDescriptionInterface
|
||||||
): CancelablePromise<BodyResourceDescriptionInterface> => {
|
): CancelablePromise<BodyResourceDescriptionInterface> => {
|
||||||
const name = "customCharacterTexture" + texture.id;
|
return createLoadingPromise(loaderPlugin, texture, {
|
||||||
const playerResourceDescriptor: BodyResourceDescriptionInterface = { name, img: texture.url, level: texture.level };
|
|
||||||
return createLoadingPromise(loaderPlugin, playerResourceDescriptor, {
|
|
||||||
frameWidth: 32,
|
frameWidth: 32,
|
||||||
frameHeight: 32,
|
frameHeight: 32,
|
||||||
});
|
});
|
||||||
@ -42,16 +40,15 @@ export const loadCustomTexture = (
|
|||||||
|
|
||||||
export const lazyLoadPlayerCharacterTextures = (
|
export const lazyLoadPlayerCharacterTextures = (
|
||||||
loadPlugin: LoaderPlugin,
|
loadPlugin: LoaderPlugin,
|
||||||
texturekeys: Array<string | BodyResourceDescriptionInterface>
|
textures: BodyResourceDescriptionInterface[]
|
||||||
): CancelablePromise<string[]> => {
|
): CancelablePromise<string[]> => {
|
||||||
const promisesList: CancelablePromise<unknown>[] = [];
|
const promisesList: CancelablePromise<unknown>[] = [];
|
||||||
texturekeys.forEach((textureKey: string | BodyResourceDescriptionInterface) => {
|
textures.forEach((texture) => {
|
||||||
try {
|
try {
|
||||||
//TODO refactor
|
//TODO refactor
|
||||||
const playerResourceDescriptor = getRessourceDescriptor(textureKey);
|
if (!loadPlugin.textureManager.exists(texture.name)) {
|
||||||
if (playerResourceDescriptor && !loadPlugin.textureManager.exists(playerResourceDescriptor.name)) {
|
|
||||||
promisesList.push(
|
promisesList.push(
|
||||||
createLoadingPromise(loadPlugin, playerResourceDescriptor, {
|
createLoadingPromise(loadPlugin, texture, {
|
||||||
frameWidth: 32,
|
frameWidth: 32,
|
||||||
frameHeight: 32,
|
frameHeight: 32,
|
||||||
})
|
})
|
||||||
@ -64,9 +61,9 @@ export const lazyLoadPlayerCharacterTextures = (
|
|||||||
let returnPromise: CancelablePromise<Array<string | BodyResourceDescriptionInterface>>;
|
let returnPromise: CancelablePromise<Array<string | BodyResourceDescriptionInterface>>;
|
||||||
if (promisesList.length > 0) {
|
if (promisesList.length > 0) {
|
||||||
loadPlugin.start();
|
loadPlugin.start();
|
||||||
returnPromise = CancelablePromise.all(promisesList).then(() => texturekeys);
|
returnPromise = CancelablePromise.all(promisesList).then(() => textures);
|
||||||
} else {
|
} else {
|
||||||
returnPromise = CancelablePromise.resolve(texturekeys);
|
returnPromise = CancelablePromise.resolve(textures);
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the loading fail, we render the default model instead.
|
//If the loading fail, we render the default model instead.
|
||||||
@ -77,23 +74,6 @@ export const lazyLoadPlayerCharacterTextures = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
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 = PlayerTextures.PLAYER_RESOURCES[textureName];
|
|
||||||
if (playerResource !== undefined) return playerResource;
|
|
||||||
|
|
||||||
for (let i = 0; i < PlayerTextures.LAYERS.length; i++) {
|
|
||||||
const playerResource = PlayerTextures.LAYERS[i][textureName];
|
|
||||||
if (playerResource !== undefined) return playerResource;
|
|
||||||
}
|
|
||||||
throw new Error("Could not find a data for texture " + textureName);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createLoadingPromise = (
|
export const createLoadingPromise = (
|
||||||
loadPlugin: LoaderPlugin,
|
loadPlugin: LoaderPlugin,
|
||||||
playerResourceDescriptor: BodyResourceDescriptionInterface,
|
playerResourceDescriptor: BodyResourceDescriptionInterface,
|
||||||
|
@ -18,7 +18,7 @@ import { soundManager } from "./SoundManager";
|
|||||||
import { SharedVariablesManager } from "./SharedVariablesManager";
|
import { SharedVariablesManager } from "./SharedVariablesManager";
|
||||||
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
||||||
|
|
||||||
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
import { lazyLoadPlayerCharacterTextures, loadWokaTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||||
import { iframeListener } from "../../Api/IframeListener";
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
import { DEBUG_MODE, JITSI_URL, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
import { DEBUG_MODE, JITSI_URL, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
||||||
@ -97,6 +97,8 @@ import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
|||||||
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
||||||
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||||
|
import { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
|
||||||
|
import CancelablePromise from "cancelable-promise";
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
reconnecting: boolean;
|
reconnecting: boolean;
|
||||||
@ -244,13 +246,6 @@ export class GameScene extends DirtyScene {
|
|||||||
//initialize frame event of scripting API
|
//initialize frame event of scripting API
|
||||||
this.listenToIframeEvents();
|
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");
|
this.load.image("iconTalk", "/resources/icons/icon_talking.png");
|
||||||
|
|
||||||
if (touchScreenManager.supportTouchScreen) {
|
if (touchScreenManager.supportTouchScreen) {
|
||||||
@ -745,6 +740,14 @@ export class GameScene extends DirtyScene {
|
|||||||
.then((onConnect: OnConnectInterface) => {
|
.then((onConnect: OnConnectInterface) => {
|
||||||
this.connection = onConnect.connection;
|
this.connection = onConnect.connection;
|
||||||
|
|
||||||
|
lazyLoadPlayerCharacterTextures(this.load, onConnect.room.characterLayers)
|
||||||
|
.then((layers) => {
|
||||||
|
this.currentPlayerTexturesResolve(layers);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
this.currentPlayerTexturesReject(e);
|
||||||
|
});
|
||||||
|
|
||||||
playersStore.connectToRoomConnection(this.connection);
|
playersStore.connectToRoomConnection(this.connection);
|
||||||
userIsAdminStore.set(this.connection.hasTag("admin"));
|
userIsAdminStore.set(this.connection.hasTag("admin"));
|
||||||
|
|
||||||
@ -1689,16 +1692,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() {
|
private createCurrentPlayer() {
|
||||||
//TODO create animation moving between exit and start
|
//TODO create animation moving between exit and start
|
||||||
const texturesPromise = lazyLoadPlayerCharacterTextures(this.load, this.characterLayers);
|
|
||||||
try {
|
try {
|
||||||
this.CurrentPlayer = new Player(
|
this.CurrentPlayer = new Player(
|
||||||
this,
|
this,
|
||||||
this.startPositionCalculator.startPosition.x,
|
this.startPositionCalculator.startPosition.x,
|
||||||
this.startPositionCalculator.startPosition.y,
|
this.startPositionCalculator.startPosition.y,
|
||||||
this.playerName,
|
this.playerName,
|
||||||
texturesPromise,
|
this.currentPlayerTexturesPromise,
|
||||||
PlayerAnimationDirections.Down,
|
PlayerAnimationDirections.Down,
|
||||||
false,
|
false,
|
||||||
this.companion,
|
this.companion,
|
||||||
|
@ -1,41 +1,45 @@
|
|||||||
import { ResizableScene } from "./ResizableScene";
|
import { ResizableScene } from "./ResizableScene";
|
||||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
|
import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
|
||||||
import { loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
import { loadWokaTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||||
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
||||||
import type CancelablePromise from "cancelable-promise";
|
import type CancelablePromise from "cancelable-promise";
|
||||||
|
import { PlayerTextures } from "../Entity/PlayerTextures";
|
||||||
|
import { Loader } from "../Components/Loader";
|
||||||
|
import { CustomizeSceneName } from "./CustomizeScene";
|
||||||
|
|
||||||
export abstract class AbstractCharacterScene extends ResizableScene {
|
export abstract class AbstractCharacterScene extends ResizableScene {
|
||||||
|
protected playerTextures: PlayerTextures;
|
||||||
|
|
||||||
|
constructor(params: { key: string }) {
|
||||||
|
super(params);
|
||||||
|
this.playerTextures = new PlayerTextures();
|
||||||
|
}
|
||||||
|
|
||||||
loadCustomSceneSelectCharacters(): Promise<BodyResourceDescriptionInterface[]> {
|
loadCustomSceneSelectCharacters(): Promise<BodyResourceDescriptionInterface[]> {
|
||||||
const textures = this.getTextures();
|
const textures = PlayerTextures.PLAYER_RESOURCES;
|
||||||
const promises: CancelablePromise<BodyResourceDescriptionInterface>[] = [];
|
const promises: CancelablePromise<BodyResourceDescriptionInterface>[] = [];
|
||||||
if (textures) {
|
if (textures) {
|
||||||
for (const texture of textures) {
|
for (const texture of Object.values(textures)) {
|
||||||
if (texture.level === -1) {
|
if (texture.level === -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
promises.push(loadCustomTexture(this.load, texture));
|
promises.push(loadWokaTexture(this.load, texture));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSelectSceneCharacters(): Promise<BodyResourceDescriptionInterface[]> {
|
loadSelectSceneCharacters(): Promise<BodyResourceDescriptionInterface[]> {
|
||||||
const textures = this.getTextures();
|
|
||||||
const promises: CancelablePromise<BodyResourceDescriptionInterface>[] = [];
|
const promises: CancelablePromise<BodyResourceDescriptionInterface>[] = [];
|
||||||
if (textures) {
|
for (const textures of PlayerTextures.LAYERS) {
|
||||||
for (const texture of textures) {
|
for (const texture of Object.values(textures)) {
|
||||||
if (texture.level !== -1) {
|
if (texture.level !== -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
promises.push(loadCustomTexture(this.load, texture));
|
promises.push(loadWokaTexture(this.load, texture));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTextures(): CharacterTexture[] | undefined {
|
|
||||||
const localUser = localUserStore.getLocalUser();
|
|
||||||
return localUser?.textures;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import Sprite = Phaser.GameObjects.Sprite;
|
|||||||
import { gameManager } from "../Game/GameManager";
|
import { gameManager } from "../Game/GameManager";
|
||||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
import { Loader } from "../Components/Loader";
|
import { Loader } from "../Components/Loader";
|
||||||
import { BodyResourceDescriptionInterface, PlayerTextures } from "../Entity/PlayerTextures";
|
import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
|
||||||
import { AbstractCharacterScene } from "./AbstractCharacterScene";
|
import { AbstractCharacterScene } from "./AbstractCharacterScene";
|
||||||
import { areCharacterLayersValid } from "../../Connexion/LocalUser";
|
import { areCharacterLayersValid } from "../../Connexion/LocalUser";
|
||||||
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
||||||
@ -32,14 +32,12 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||||||
private moveVertically: number = 0;
|
private moveVertically: number = 0;
|
||||||
|
|
||||||
private loader: Loader;
|
private loader: Loader;
|
||||||
private playerTextures: PlayerTextures;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
key: CustomizeSceneName,
|
key: CustomizeSceneName,
|
||||||
});
|
});
|
||||||
this.loader = new Loader(this);
|
this.loader = new Loader(this);
|
||||||
this.playerTextures = new PlayerTextures();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
|
@ -33,7 +33,6 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||||||
|
|
||||||
protected lazyloadingAttempt = true; //permit to update texture loaded after renderer
|
protected lazyloadingAttempt = true; //permit to update texture loaded after renderer
|
||||||
private loader: Loader;
|
private loader: Loader;
|
||||||
private playerTextures: PlayerTextures;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import "jasmine";
|
|
||||||
import { getRessourceDescriptor } from "../../../src/Phaser/Entity/PlayerTexturesLoadingManager";
|
|
||||||
|
|
||||||
describe("getRessourceDescriptor()", () => {
|
|
||||||
it(", if given a valid descriptor as parameter, should return it", () => {
|
|
||||||
const desc = getRessourceDescriptor({ name: "name", img: "url" });
|
|
||||||
expect(desc.name).toEqual("name");
|
|
||||||
expect(desc.img).toEqual("url");
|
|
||||||
});
|
|
||||||
|
|
||||||
it(", if given a string as parameter, should search through hardcoded values", () => {
|
|
||||||
const desc = getRessourceDescriptor("male1");
|
|
||||||
expect(desc.name).toEqual("male1");
|
|
||||||
expect(desc.img).toEqual("resources/characters/pipoya/Male 01-1.png");
|
|
||||||
});
|
|
||||||
|
|
||||||
it(", if given a string as parameter, should search through hardcoded values (bis)", () => {
|
|
||||||
const desc = getRessourceDescriptor("color_2");
|
|
||||||
expect(desc.name).toEqual("color_2");
|
|
||||||
expect(desc.img).toEqual("resources/customisation/character_color/character_color1.png");
|
|
||||||
});
|
|
||||||
|
|
||||||
it(", if given a descriptor without url as parameter, should search through hardcoded values", () => {
|
|
||||||
const desc = getRessourceDescriptor({ name: "male1", img: "" });
|
|
||||||
expect(desc.name).toEqual("male1");
|
|
||||||
expect(desc.img).toEqual("resources/characters/pipoya/Male 01-1.png");
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,5 +1,5 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import * as tg from "generic-type-guard";
|
||||||
import { isCharacterTexture } from "./CharacterTexture";
|
//import { isCharacterTexture } from "./CharacterTexture";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WARNING! The original file is in /messages/JsonMessages.
|
* WARNING! The original file is in /messages/JsonMessages.
|
||||||
@ -12,7 +12,7 @@ export const isAdminApiData = new tg.IsInterface()
|
|||||||
email: tg.isNullable(tg.isString),
|
email: tg.isNullable(tg.isString),
|
||||||
roomUrl: tg.isString,
|
roomUrl: tg.isString,
|
||||||
mapUrlStart: tg.isString,
|
mapUrlStart: tg.isString,
|
||||||
textures: tg.isArray(isCharacterTexture),
|
// textures: tg.isArray(isCharacterTexture),
|
||||||
})
|
})
|
||||||
.withOptionalProperties({
|
.withOptionalProperties({
|
||||||
messages: tg.isArray(tg.isUnknown),
|
messages: tg.isArray(tg.isUnknown),
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import * as tg from "generic-type-guard";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WARNING! The original file is in /messages/JsonMessages.
|
|
||||||
* All other files are automatically copied from this file on container startup / build
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const isCharacterTexture = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
id: tg.isNumber,
|
|
||||||
level: tg.isNumber,
|
|
||||||
url: tg.isString,
|
|
||||||
rights: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
export type CharacterTexture = tg.GuardedType<typeof isCharacterTexture>;
|
|
@ -1,5 +1,5 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import * as tg from "generic-type-guard";
|
||||||
import { isCharacterTexture } from "./CharacterTexture";
|
//import { isCharacterTexture } from "./CharacterTexture";
|
||||||
import { isNumber } from "generic-type-guard";
|
import { isNumber } from "generic-type-guard";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -12,7 +12,7 @@ export const isMapDetailsData = new tg.IsInterface()
|
|||||||
mapUrl: tg.isString,
|
mapUrl: tg.isString,
|
||||||
policy_type: isNumber, //isNumericEnum(GameRoomPolicyTypes),
|
policy_type: isNumber, //isNumericEnum(GameRoomPolicyTypes),
|
||||||
tags: tg.isArray(tg.isString),
|
tags: tg.isArray(tg.isString),
|
||||||
textures: tg.isArray(isCharacterTexture),
|
// textures: tg.isArray(isCharacterTexture),
|
||||||
authenticationMandatory: tg.isUnion(tg.isNullable(tg.isBoolean), tg.isUndefined),
|
authenticationMandatory: tg.isUnion(tg.isNullable(tg.isBoolean), tg.isUndefined),
|
||||||
roomSlug: tg.isNullable(tg.isString), // deprecated
|
roomSlug: tg.isNullable(tg.isString), // deprecated
|
||||||
contactPage: tg.isNullable(tg.isString),
|
contactPage: tg.isNullable(tg.isString),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import * as tg from "generic-type-guard";
|
||||||
import { isCharacterTexture } from "./CharacterTexture";
|
//import { isCharacterTexture } from "./CharacterTexture";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WARNING! The original file is in /messages/JsonMessages.
|
* WARNING! The original file is in /messages/JsonMessages.
|
||||||
@ -13,7 +13,7 @@ export const isRegisterData = new tg.IsInterface()
|
|||||||
organizationMemberToken: tg.isNullable(tg.isString),
|
organizationMemberToken: tg.isNullable(tg.isString),
|
||||||
mapUrlStart: tg.isString,
|
mapUrlStart: tg.isString,
|
||||||
userUuid: tg.isString,
|
userUuid: tg.isString,
|
||||||
textures: tg.isArray(isCharacterTexture),
|
// textures: tg.isArray(isCharacterTexture),
|
||||||
authToken: tg.isString,
|
authToken: tg.isString,
|
||||||
})
|
})
|
||||||
.withOptionalProperties({
|
.withOptionalProperties({
|
||||||
|
@ -34,6 +34,7 @@ message SilentMessage {
|
|||||||
message CharacterLayerMessage {
|
message CharacterLayerMessage {
|
||||||
string url = 1;
|
string url = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
|
string layer = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CompanionMessage {
|
message CompanionMessage {
|
||||||
@ -223,6 +224,8 @@ message RoomJoinedMessage {
|
|||||||
repeated string tag = 5;
|
repeated string tag = 5;
|
||||||
repeated VariableMessage variable = 6;
|
repeated VariableMessage variable = 6;
|
||||||
string userRoomToken = 7;
|
string userRoomToken = 7;
|
||||||
|
// We send the current skin of the current player.
|
||||||
|
repeated CharacterLayerMessage characterLayer = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message WebRtcStartMessage {
|
message WebRtcStartMessage {
|
||||||
@ -274,6 +277,8 @@ message WorldFullMessage{
|
|||||||
}
|
}
|
||||||
message TokenExpiredMessage{
|
message TokenExpiredMessage{
|
||||||
}
|
}
|
||||||
|
message InvalidTextureMessage{
|
||||||
|
}
|
||||||
|
|
||||||
message WorldConnexionMessage{
|
message WorldConnexionMessage{
|
||||||
string message = 2;
|
string message = 2;
|
||||||
@ -310,6 +315,7 @@ message ServerToClientMessage {
|
|||||||
FollowRequestMessage followRequestMessage = 21;
|
FollowRequestMessage followRequestMessage = 21;
|
||||||
FollowConfirmationMessage followConfirmationMessage = 22;
|
FollowConfirmationMessage followConfirmationMessage = 22;
|
||||||
FollowAbortMessage followAbortMessage = 23;
|
FollowAbortMessage followAbortMessage = 23;
|
||||||
|
InvalidTextureMessage invalidTextureMessage = 24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +273,6 @@ export class AuthenticateController extends BaseHttpController {
|
|||||||
const email = data.email;
|
const email = data.email;
|
||||||
const roomUrl = data.roomUrl;
|
const roomUrl = data.roomUrl;
|
||||||
const mapUrlStart = data.mapUrlStart;
|
const mapUrlStart = data.mapUrlStart;
|
||||||
const textures = data.textures;
|
|
||||||
|
|
||||||
const authToken = jwtTokenManager.createAuthToken(email || userUuid);
|
const authToken = jwtTokenManager.createAuthToken(email || userUuid);
|
||||||
res.json({
|
res.json({
|
||||||
@ -283,7 +282,6 @@ export class AuthenticateController extends BaseHttpController {
|
|||||||
roomUrl,
|
roomUrl,
|
||||||
mapUrlStart,
|
mapUrlStart,
|
||||||
organizationMemberToken,
|
organizationMemberToken,
|
||||||
textures,
|
|
||||||
} as RegisterData);
|
} as RegisterData);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("register => ERROR", e);
|
console.error("register => ERROR", e);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CharacterLayer, ExSocketInterface } from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
import { ExSocketInterface } from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
||||||
import { GameRoomPolicyTypes } from "../Model/PusherRoom";
|
import { GameRoomPolicyTypes } from "../Model/PusherRoom";
|
||||||
import { PointInterface } from "../Model/Websocket/PointInterface";
|
import { PointInterface } from "../Model/Websocket/PointInterface";
|
||||||
import {
|
import {
|
||||||
@ -31,11 +31,46 @@ import { emitInBatch } from "../Services/IoSocketHelpers";
|
|||||||
import { ADMIN_API_URL, ADMIN_SOCKETS_TOKEN, DISABLE_ANONYMOUS, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_URL, ADMIN_SOCKETS_TOKEN, DISABLE_ANONYMOUS, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable";
|
||||||
import { Zone } from "_Model/Zone";
|
import { Zone } from "_Model/Zone";
|
||||||
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
||||||
import { CharacterTexture } from "../Messages/JsonMessages/CharacterTexture";
|
|
||||||
import { isAdminMessageInterface } from "../Model/Websocket/Admin/AdminMessages";
|
import { isAdminMessageInterface } from "../Model/Websocket/Admin/AdminMessages";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import { InvalidTokenError } from "../Controller/InvalidTokenError";
|
import { InvalidTokenError } from "../Controller/InvalidTokenError";
|
||||||
import HyperExpress from "hyper-express";
|
import HyperExpress from "hyper-express";
|
||||||
|
import { localWokaService } from "../Services/LocalWokaService";
|
||||||
|
import { WebSocket } from "uWebSockets.js";
|
||||||
|
import { WokaDetail } from "../Enum/PlayerTextures";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object passed between the "open" and the "upgrade" methods when opening a websocket
|
||||||
|
*/
|
||||||
|
interface UpgradeData {
|
||||||
|
// Data passed here is accessible on the "websocket" socket object.
|
||||||
|
rejected: false;
|
||||||
|
token: string;
|
||||||
|
userUuid: string;
|
||||||
|
IPAddress: string;
|
||||||
|
roomId: string;
|
||||||
|
name: string;
|
||||||
|
companion: CompanionMessage | undefined;
|
||||||
|
characterLayers: WokaDetail[];
|
||||||
|
messages: unknown[];
|
||||||
|
tags: string[];
|
||||||
|
visitCardUrl: string | null;
|
||||||
|
userRoomToken: string | undefined;
|
||||||
|
position: PointInterface;
|
||||||
|
viewport: {
|
||||||
|
top: number;
|
||||||
|
right: number;
|
||||||
|
bottom: number;
|
||||||
|
left: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpgradeFailedData {
|
||||||
|
rejected: true;
|
||||||
|
reason: "tokenInvalid" | "textureInvalid" | null;
|
||||||
|
message: string;
|
||||||
|
roomId: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class IoSocketController {
|
export class IoSocketController {
|
||||||
private nextUserId: number = 1;
|
private nextUserId: number = 1;
|
||||||
@ -244,7 +279,7 @@ export class IoSocketController {
|
|||||||
let memberVisitCardUrl: string | null = null;
|
let memberVisitCardUrl: string | null = null;
|
||||||
let memberMessages: unknown;
|
let memberMessages: unknown;
|
||||||
let memberUserRoomToken: string | undefined;
|
let memberUserRoomToken: string | undefined;
|
||||||
let memberTextures: CharacterTexture[] = [];
|
let memberTextures: WokaDetail[] = [];
|
||||||
const room = await socketManager.getOrCreateRoom(roomId);
|
const room = await socketManager.getOrCreateRoom(roomId);
|
||||||
let userData: FetchMemberDataByUuidResponse = {
|
let userData: FetchMemberDataByUuidResponse = {
|
||||||
email: userIdentifier,
|
email: userIdentifier,
|
||||||
@ -256,6 +291,9 @@ export class IoSocketController {
|
|||||||
anonymous: true,
|
anonymous: true,
|
||||||
userRoomToken: undefined,
|
userRoomToken: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let characterLayerObjs: WokaDetail[];
|
||||||
|
|
||||||
if (ADMIN_API_URL) {
|
if (ADMIN_API_URL) {
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
@ -308,6 +346,8 @@ export class IoSocketController {
|
|||||||
) {
|
) {
|
||||||
throw new Error("Use the login URL to connect");
|
throw new Error("Use the login URL to connect");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
characterLayerObjs = memberTextures;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(
|
console.log(
|
||||||
"access not granted for user " +
|
"access not granted for user " +
|
||||||
@ -318,11 +358,31 @@ export class IoSocketController {
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
throw new Error("User cannot access this world");
|
throw new Error("User cannot access this world");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const fetchedTextures = await localWokaService.fetchWokaDetails(characterLayers);
|
||||||
|
if (fetchedTextures === undefined) {
|
||||||
|
// The textures we want to use do not exist!
|
||||||
|
// We need to go in error.
|
||||||
|
res.upgrade(
|
||||||
|
{
|
||||||
|
rejected: true,
|
||||||
|
reason: "textureInvalid",
|
||||||
|
message: "",
|
||||||
|
roomId,
|
||||||
|
} as UpgradeFailedData,
|
||||||
|
websocketKey,
|
||||||
|
websocketProtocol,
|
||||||
|
websocketExtensions,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
characterLayerObjs = fetchedTextures;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate characterLayers objects from characterLayers string[]
|
// Generate characterLayers objects from characterLayers string[]
|
||||||
const characterLayerObjs: CharacterLayer[] =
|
/*const characterLayerObjs: CharacterLayer[] =
|
||||||
SocketManager.mergeCharacterLayersAndCustomTextures(characterLayers, memberTextures);
|
SocketManager.mergeCharacterLayersAndCustomTextures(characterLayers, memberTextures);*/
|
||||||
|
|
||||||
if (upgradeAborted.aborted) {
|
if (upgradeAborted.aborted) {
|
||||||
console.log("Ouch! Client disconnected before we could upgrade it!");
|
console.log("Ouch! Client disconnected before we could upgrade it!");
|
||||||
@ -334,7 +394,7 @@ export class IoSocketController {
|
|||||||
res.upgrade(
|
res.upgrade(
|
||||||
{
|
{
|
||||||
// Data passed here is accessible on the "websocket" socket object.
|
// Data passed here is accessible on the "websocket" socket object.
|
||||||
url,
|
rejected: false,
|
||||||
token,
|
token,
|
||||||
userUuid: userData.userUuid,
|
userUuid: userData.userUuid,
|
||||||
IPAddress,
|
IPAddress,
|
||||||
@ -346,7 +406,6 @@ export class IoSocketController {
|
|||||||
tags: memberTags,
|
tags: memberTags,
|
||||||
visitCardUrl: memberVisitCardUrl,
|
visitCardUrl: memberVisitCardUrl,
|
||||||
userRoomToken: memberUserRoomToken,
|
userRoomToken: memberUserRoomToken,
|
||||||
textures: memberTextures,
|
|
||||||
position: {
|
position: {
|
||||||
x: x,
|
x: x,
|
||||||
y: y,
|
y: y,
|
||||||
@ -359,7 +418,7 @@ export class IoSocketController {
|
|||||||
bottom,
|
bottom,
|
||||||
left,
|
left,
|
||||||
},
|
},
|
||||||
},
|
} as UpgradeData,
|
||||||
/* Spell these correctly */
|
/* Spell these correctly */
|
||||||
websocketKey,
|
websocketKey,
|
||||||
websocketProtocol,
|
websocketProtocol,
|
||||||
@ -374,7 +433,7 @@ export class IoSocketController {
|
|||||||
reason: e instanceof InvalidTokenError ? tokenInvalidException : null,
|
reason: e instanceof InvalidTokenError ? tokenInvalidException : null,
|
||||||
message: e.message,
|
message: e.message,
|
||||||
roomId,
|
roomId,
|
||||||
},
|
} as UpgradeFailedData,
|
||||||
websocketKey,
|
websocketKey,
|
||||||
websocketProtocol,
|
websocketProtocol,
|
||||||
websocketExtensions,
|
websocketExtensions,
|
||||||
@ -387,7 +446,7 @@ export class IoSocketController {
|
|||||||
reason: null,
|
reason: null,
|
||||||
message: "500 Internal Server Error",
|
message: "500 Internal Server Error",
|
||||||
roomId,
|
roomId,
|
||||||
},
|
} as UpgradeFailedData,
|
||||||
websocketKey,
|
websocketKey,
|
||||||
websocketProtocol,
|
websocketProtocol,
|
||||||
websocketExtensions,
|
websocketExtensions,
|
||||||
@ -398,20 +457,23 @@ export class IoSocketController {
|
|||||||
})();
|
})();
|
||||||
},
|
},
|
||||||
/* Handlers */
|
/* Handlers */
|
||||||
open: (ws) => {
|
open: (_ws: WebSocket) => {
|
||||||
|
const ws = _ws as WebSocket & (UpgradeData | UpgradeFailedData);
|
||||||
if (ws.rejected === true) {
|
if (ws.rejected === true) {
|
||||||
// If there is a room in the error, let's check if we need to clean it.
|
// If there is a room in the error, let's check if we need to clean it.
|
||||||
if (ws.roomId) {
|
if (ws.roomId) {
|
||||||
socketManager.deleteRoomIfEmptyFromId(ws.roomId as string);
|
socketManager.deleteRoomIfEmptyFromId(ws.roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIX ME to use status code
|
//FIX ME to use status code
|
||||||
if (ws.reason === tokenInvalidException) {
|
if (ws.reason === tokenInvalidException) {
|
||||||
socketManager.emitTokenExpiredMessage(ws);
|
socketManager.emitTokenExpiredMessage(ws);
|
||||||
|
} else if (ws.reason === "textureInvalid") {
|
||||||
|
socketManager.emitInvalidTextureMessage(ws);
|
||||||
} else if (ws.message === "World is full") {
|
} else if (ws.message === "World is full") {
|
||||||
socketManager.emitWorldFullMessage(ws);
|
socketManager.emitWorldFullMessage(ws);
|
||||||
} else {
|
} else {
|
||||||
socketManager.emitConnexionErrorMessage(ws, ws.message as string);
|
socketManager.emitConnexionErrorMessage(ws, ws.message);
|
||||||
}
|
}
|
||||||
setTimeout(() => ws.close(), 0);
|
setTimeout(() => ws.close(), 0);
|
||||||
return;
|
return;
|
||||||
@ -535,7 +597,6 @@ export class IoSocketController {
|
|||||||
client.name = ws.name;
|
client.name = ws.name;
|
||||||
client.tags = ws.tags;
|
client.tags = ws.tags;
|
||||||
client.visitCardUrl = ws.visitCardUrl;
|
client.visitCardUrl = ws.visitCardUrl;
|
||||||
client.textures = ws.textures;
|
|
||||||
client.characterLayers = ws.characterLayers;
|
client.characterLayers = ws.characterLayers;
|
||||||
client.companion = ws.companion;
|
client.companion = ws.companion;
|
||||||
client.roomId = ws.roomId;
|
client.roomId = ws.roomId;
|
||||||
|
@ -1,24 +1,13 @@
|
|||||||
import { hasToken } from "../Middleware/HasToken";
|
import { hasToken } from "../Middleware/HasToken";
|
||||||
import { BaseHttpController } from "./BaseHttpController";
|
import { BaseHttpController } from "./BaseHttpController";
|
||||||
import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
import { wokaService } from "../Services/WokaService";
|
||||||
import { adminWokaService } from "..//Services/AdminWokaService";
|
|
||||||
import { localWokaService } from "..//Services/LocalWokaService";
|
|
||||||
import { WokaServiceInterface } from "src/Services/WokaServiceInterface";
|
|
||||||
import { Server } from "hyper-express";
|
|
||||||
|
|
||||||
export class WokaListController extends BaseHttpController {
|
export class WokaListController extends BaseHttpController {
|
||||||
private wokaService: WokaServiceInterface;
|
|
||||||
|
|
||||||
constructor(app: Server) {
|
|
||||||
super(app);
|
|
||||||
this.wokaService = ADMIN_API_URL ? adminWokaService : localWokaService;
|
|
||||||
}
|
|
||||||
|
|
||||||
routes() {
|
routes() {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
this.app.get("/woka-list", {}, async (req, res) => {
|
this.app.get("/woka-list", {}, async (req, res) => {
|
||||||
const token = req.header("Authorization");
|
const token = req.header("Authorization");
|
||||||
const wokaList = await this.wokaService.getWokaList(token);
|
const wokaList = await wokaService.getWokaList(token);
|
||||||
|
|
||||||
if (!wokaList) {
|
if (!wokaList) {
|
||||||
return res.status(500).send("Error on getting woka list");
|
return res.status(500).send("Error on getting woka list");
|
||||||
@ -28,20 +17,20 @@ export class WokaListController extends BaseHttpController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
this.app.post("/woka-details", async (req, res) => {
|
/*this.app.post("/woka-details", async (req, res) => {
|
||||||
const body = await req.json();
|
const body = await req.json();
|
||||||
if (!body || !body.textureIds) {
|
if (!body || !body.textureIds) {
|
||||||
return res.status(400);
|
return res.status(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
const textureIds = body.textureIds;
|
const textureIds = body.textureIds;
|
||||||
const wokaDetails = await this.wokaService.fetchWokaDetails(textureIds);
|
const wokaDetails = await wokaService.fetchWokaDetails(textureIds);
|
||||||
|
|
||||||
if (!wokaDetails) {
|
if (!wokaDetails) {
|
||||||
return res.json({ details: [] });
|
return res.json({ details: [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json(wokaDetails);
|
return res.json(wokaDetails);
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,16 +49,11 @@ export const isWokaDetail = new tg.IsInterface()
|
|||||||
id: tg.isString,
|
id: tg.isString,
|
||||||
})
|
})
|
||||||
.withOptionalProperties({
|
.withOptionalProperties({
|
||||||
texture: tg.isString,
|
url: tg.isString,
|
||||||
|
layer: tg.isString,
|
||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
export type WokaDetail = tg.GuardedType<typeof isWokaDetail>;
|
export type WokaDetail = tg.GuardedType<typeof isWokaDetail>;
|
||||||
|
|
||||||
export const isWokaDetailsResult = new tg.IsInterface()
|
export type WokaDetailsResult = WokaDetail[];
|
||||||
.withProperties({
|
|
||||||
details: tg.isArray(isWokaDetail),
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type WokaDetailsResult = tg.GuardedType<typeof isWokaDetailsResult>;
|
|
||||||
|
@ -13,14 +13,10 @@ import { ClientDuplexStream } from "grpc";
|
|||||||
import { Zone } from "_Model/Zone";
|
import { Zone } from "_Model/Zone";
|
||||||
import { CharacterTexture } from "../../Messages/JsonMessages/CharacterTexture";
|
import { CharacterTexture } from "../../Messages/JsonMessages/CharacterTexture";
|
||||||
import { compressors } from "hyper-express";
|
import { compressors } from "hyper-express";
|
||||||
|
import { WokaDetail } from "_Enum/PlayerTextures";
|
||||||
|
|
||||||
export type BackConnection = ClientDuplexStream<PusherToBackMessage, ServerToClientMessage>;
|
export type BackConnection = ClientDuplexStream<PusherToBackMessage, ServerToClientMessage>;
|
||||||
|
|
||||||
export interface CharacterLayer {
|
|
||||||
name: string;
|
|
||||||
url: string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExSocketInterface extends compressors.WebSocket, Identificable {
|
export interface ExSocketInterface extends compressors.WebSocket, Identificable {
|
||||||
token: string;
|
token: string;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
@ -28,7 +24,7 @@ export interface ExSocketInterface extends compressors.WebSocket, Identificable
|
|||||||
userUuid: string; // A unique identifier for this user
|
userUuid: string; // A unique identifier for this user
|
||||||
IPAddress: string; // IP address
|
IPAddress: string; // IP address
|
||||||
name: string;
|
name: string;
|
||||||
characterLayers: CharacterLayer[];
|
characterLayers: WokaDetail[];
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
viewport: ViewportInterface;
|
viewport: ViewportInterface;
|
||||||
companion?: CompanionMessage;
|
companion?: CompanionMessage;
|
||||||
@ -42,7 +38,6 @@ export interface ExSocketInterface extends compressors.WebSocket, Identificable
|
|||||||
messages: unknown;
|
messages: unknown;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
visitCardUrl: string | null;
|
visitCardUrl: string | null;
|
||||||
textures: CharacterTexture[];
|
|
||||||
backConnection: BackConnection;
|
backConnection: BackConnection;
|
||||||
listenedZones: Set<Zone>;
|
listenedZones: Set<Zone>;
|
||||||
userRoomToken: string | undefined;
|
userRoomToken: string | undefined;
|
||||||
|
@ -5,10 +5,11 @@ import {
|
|||||||
PointMessage,
|
PointMessage,
|
||||||
PositionMessage,
|
PositionMessage,
|
||||||
} from "../../Messages/generated/messages_pb";
|
} from "../../Messages/generated/messages_pb";
|
||||||
import { CharacterLayer, ExSocketInterface } from "_Model/Websocket/ExSocketInterface";
|
import { ExSocketInterface } from "_Model/Websocket/ExSocketInterface";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import { ItemEventMessageInterface } from "_Model/Websocket/ItemEventMessage";
|
import { ItemEventMessageInterface } from "_Model/Websocket/ItemEventMessage";
|
||||||
import { PositionInterface } from "_Model/PositionInterface";
|
import { PositionInterface } from "_Model/PositionInterface";
|
||||||
|
import { WokaDetail } from "_Enum/PlayerTextures";
|
||||||
|
|
||||||
export class ProtobufUtils {
|
export class ProtobufUtils {
|
||||||
public static toPositionMessage(point: PointInterface): PositionMessage {
|
public static toPositionMessage(point: PointInterface): PositionMessage {
|
||||||
@ -94,13 +95,16 @@ export class ProtobufUtils {
|
|||||||
return itemEventMessage;
|
return itemEventMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static toCharacterLayerMessages(characterLayers: CharacterLayer[]): CharacterLayerMessage[] {
|
public static toCharacterLayerMessages(characterLayers: WokaDetail[]): CharacterLayerMessage[] {
|
||||||
return characterLayers.map(function (characterLayer): CharacterLayerMessage {
|
return characterLayers.map(function (characterLayer): CharacterLayerMessage {
|
||||||
const message = new CharacterLayerMessage();
|
const message = new CharacterLayerMessage();
|
||||||
message.setName(characterLayer.name);
|
message.setName(characterLayer.id);
|
||||||
if (characterLayer.url) {
|
if (characterLayer.url) {
|
||||||
message.setUrl(characterLayer.url);
|
message.setUrl(characterLayer.url);
|
||||||
}
|
}
|
||||||
|
if (characterLayer.layer) {
|
||||||
|
message.setLayer(characterLayer.layer);
|
||||||
|
}
|
||||||
return message;
|
return message;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,33 @@
|
|||||||
import { ADMIN_API_TOKEN, ADMIN_API_URL, ADMIN_URL, OPID_PROFILE_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_TOKEN, ADMIN_API_URL, ADMIN_URL, OPID_PROFILE_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
|
||||||
import Axios from "axios";
|
import Axios, { AxiosResponse } from "axios";
|
||||||
import { CharacterTexture } from "../Messages/JsonMessages/CharacterTexture";
|
|
||||||
import { MapDetailsData } from "../Messages/JsonMessages/MapDetailsData";
|
import { MapDetailsData } from "../Messages/JsonMessages/MapDetailsData";
|
||||||
import { RoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
|
import { RoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
|
||||||
import { AdminApiData, isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
|
import { AdminApiData, isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
|
||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
import { isNumber } from "generic-type-guard";
|
||||||
|
import { isWokaDetail } from "../Enum/PlayerTextures";
|
||||||
|
|
||||||
export interface AdminBannedData {
|
export interface AdminBannedData {
|
||||||
is_banned: boolean;
|
is_banned: boolean;
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchMemberDataByUuidResponse {
|
const isFetchMemberDataByUuidResponse = new tg.IsInterface()
|
||||||
email: string;
|
.withProperties({
|
||||||
userUuid: string;
|
email: tg.isString,
|
||||||
tags: string[];
|
userUuid: tg.isString,
|
||||||
visitCardUrl: string | null;
|
tags: tg.isArray(tg.isString),
|
||||||
textures: CharacterTexture[];
|
visitCardUrl: tg.isNullable(tg.isString),
|
||||||
messages: unknown[];
|
textures: tg.isArray(isWokaDetail),
|
||||||
anonymous?: boolean;
|
messages: tg.isArray(tg.isUnknown),
|
||||||
userRoomToken: string | undefined;
|
})
|
||||||
}
|
.withOptionalProperties({
|
||||||
|
anonymous: tg.isBoolean,
|
||||||
|
userRoomToken: tg.isString,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
export type FetchMemberDataByUuidResponse = tg.GuardedType<typeof isFetchMemberDataByUuidResponse>;
|
||||||
|
|
||||||
class AdminApi {
|
class AdminApi {
|
||||||
/**
|
/**
|
||||||
@ -52,10 +60,16 @@ class AdminApi {
|
|||||||
if (!ADMIN_API_URL) {
|
if (!ADMIN_API_URL) {
|
||||||
return Promise.reject(new Error("No admin backoffice set!"));
|
return Promise.reject(new Error("No admin backoffice set!"));
|
||||||
}
|
}
|
||||||
const res = await Axios.get(ADMIN_API_URL + "/api/room/access", {
|
const res = await Axios.get<unknown, AxiosResponse<unknown>>(ADMIN_API_URL + "/api/room/access", {
|
||||||
params: { userIdentifier, roomId, ipAddress },
|
params: { userIdentifier, roomId, ipAddress },
|
||||||
headers: { Authorization: `${ADMIN_API_TOKEN}` },
|
headers: { Authorization: `${ADMIN_API_TOKEN}` },
|
||||||
});
|
});
|
||||||
|
if (!isFetchMemberDataByUuidResponse(res.data)) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid answer received from the admin for the /api/map endpoint. Received: " +
|
||||||
|
JSON.stringify(res.data)
|
||||||
|
);
|
||||||
|
}
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { ADMIN_API_TOKEN, ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_TOKEN, ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
||||||
import { isWokaDetailsResult, isWokaList, WokaDetailsResult, WokaList } from "../Enum/PlayerTextures";
|
import { isWokaList, WokaList } from "../Enum/PlayerTextures";
|
||||||
import { WokaServiceInterface } from "./WokaServiceInterface";
|
import { WokaServiceInterface } from "./WokaServiceInterface";
|
||||||
|
|
||||||
class AdminWokaService implements WokaServiceInterface {
|
class AdminWokaService implements WokaServiceInterface {
|
||||||
@ -32,7 +32,7 @@ class AdminWokaService implements WokaServiceInterface {
|
|||||||
*
|
*
|
||||||
* If one of the textures cannot be found, undefined is returned
|
* If one of the textures cannot be found, undefined is returned
|
||||||
*/
|
*/
|
||||||
fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined> {
|
/*fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined> {
|
||||||
return axios
|
return axios
|
||||||
.post(
|
.post(
|
||||||
`${ADMIN_API_URL}/api/woka-details`,
|
`${ADMIN_API_URL}/api/woka-details`,
|
||||||
@ -49,11 +49,11 @@ class AdminWokaService implements WokaServiceInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result: WokaDetailsResult = res.data;
|
const result: WokaDetailsResult = res.data;
|
||||||
if (result.details.length !== textureIds.length) {
|
if (result.length !== textureIds.length) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const detail of result.details) {
|
for (const detail of result) {
|
||||||
if (!detail.texture) {
|
if (!detail.texture) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ class AdminWokaService implements WokaServiceInterface {
|
|||||||
console.error(`Cannot get woka details from admin API with ids: ${textureIds}`, err);
|
console.error(`Cannot get woka details from admin API with ids: ${textureIds}`, err);
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
export const adminWokaService = new AdminWokaService();
|
export const adminWokaService = new AdminWokaService();
|
||||||
|
@ -23,7 +23,13 @@ class LocalWokaService implements WokaServiceInterface {
|
|||||||
*/
|
*/
|
||||||
async fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined> {
|
async fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined> {
|
||||||
const wokaData: WokaList = await require("../../data/woka.json");
|
const wokaData: WokaList = await require("../../data/woka.json");
|
||||||
const textures = new Map<string, string>();
|
const textures = new Map<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
url: string;
|
||||||
|
layer: string;
|
||||||
|
}
|
||||||
|
>();
|
||||||
const searchIds = new Set(textureIds);
|
const searchIds = new Set(textureIds);
|
||||||
|
|
||||||
for (const part of wokaPartNames) {
|
for (const part of wokaPartNames) {
|
||||||
@ -37,7 +43,10 @@ class LocalWokaService implements WokaServiceInterface {
|
|||||||
const texture = collection.textures.find((texture) => texture.id === id);
|
const texture = collection.textures.find((texture) => texture.id === id);
|
||||||
|
|
||||||
if (texture) {
|
if (texture) {
|
||||||
textures.set(id, texture.url);
|
textures.set(id, {
|
||||||
|
url: texture.url,
|
||||||
|
layer: part,
|
||||||
|
});
|
||||||
searchIds.delete(id);
|
searchIds.delete(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,11 +62,12 @@ class LocalWokaService implements WokaServiceInterface {
|
|||||||
textures.forEach((value, key) => {
|
textures.forEach((value, key) => {
|
||||||
details.push({
|
details.push({
|
||||||
id: key,
|
id: key,
|
||||||
texture: value,
|
url: value.url,
|
||||||
|
layer: value.layer,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return { details };
|
return details;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { PusherRoom } from "../Model/PusherRoom";
|
import { PusherRoom } from "../Model/PusherRoom";
|
||||||
import { CharacterLayer, ExSocketInterface } from "../Model/Websocket/ExSocketInterface";
|
import { ExSocketInterface } from "../Model/Websocket/ExSocketInterface";
|
||||||
import {
|
import {
|
||||||
AdminMessage,
|
AdminMessage,
|
||||||
AdminPusherToBackMessage,
|
AdminPusherToBackMessage,
|
||||||
@ -38,6 +38,7 @@ import {
|
|||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
WorldFullMessage,
|
WorldFullMessage,
|
||||||
PlayerDetailsUpdatedMessage,
|
PlayerDetailsUpdatedMessage,
|
||||||
|
InvalidTextureMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
||||||
import { ADMIN_API_URL, JITSI_ISS, JITSI_URL, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_URL, JITSI_ISS, JITSI_URL, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable";
|
||||||
@ -52,7 +53,7 @@ import Debug from "debug";
|
|||||||
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
||||||
import { WebSocket } from "uWebSockets.js";
|
import { WebSocket } from "uWebSockets.js";
|
||||||
import { isRoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
|
import { isRoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
|
||||||
import { CharacterTexture } from "../Messages/JsonMessages/CharacterTexture";
|
//import { CharacterTexture } from "../Messages/JsonMessages/CharacterTexture";
|
||||||
import { compressors } from "hyper-express";
|
import { compressors } from "hyper-express";
|
||||||
|
|
||||||
const debug = Debug("socket");
|
const debug = Debug("socket");
|
||||||
@ -175,10 +176,13 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
|
|
||||||
for (const characterLayer of client.characterLayers) {
|
for (const characterLayer of client.characterLayers) {
|
||||||
const characterLayerMessage = new CharacterLayerMessage();
|
const characterLayerMessage = new CharacterLayerMessage();
|
||||||
characterLayerMessage.setName(characterLayer.name);
|
characterLayerMessage.setName(characterLayer.id);
|
||||||
if (characterLayer.url !== undefined) {
|
if (characterLayer.url !== undefined) {
|
||||||
characterLayerMessage.setUrl(characterLayer.url);
|
characterLayerMessage.setUrl(characterLayer.url);
|
||||||
}
|
}
|
||||||
|
if (characterLayer.layer !== undefined) {
|
||||||
|
characterLayerMessage.setLayer(characterLayer.layer);
|
||||||
|
}
|
||||||
|
|
||||||
joinRoomMessage.addCharacterlayer(characterLayerMessage);
|
joinRoomMessage.addCharacterlayer(characterLayerMessage);
|
||||||
}
|
}
|
||||||
@ -545,36 +549,6 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges the characterLayers received from the front (as an array of string) with the custom textures from the back.
|
|
||||||
*/
|
|
||||||
static mergeCharacterLayersAndCustomTextures(
|
|
||||||
characterLayers: string[],
|
|
||||||
memberTextures: CharacterTexture[]
|
|
||||||
): CharacterLayer[] {
|
|
||||||
const characterLayerObjs: CharacterLayer[] = [];
|
|
||||||
for (const characterLayer of characterLayers) {
|
|
||||||
if (characterLayer.startsWith("customCharacterTexture")) {
|
|
||||||
const customCharacterLayerId: number = +characterLayer.substr(22);
|
|
||||||
for (const memberTexture of memberTextures) {
|
|
||||||
if (memberTexture.id == customCharacterLayerId) {
|
|
||||||
characterLayerObjs.push({
|
|
||||||
name: characterLayer,
|
|
||||||
url: memberTexture.url,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
characterLayerObjs.push({
|
|
||||||
name: characterLayer,
|
|
||||||
url: undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return characterLayerObjs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public onUserEnters(user: UserDescriptor, listener: ExSocketInterface): void {
|
public onUserEnters(user: UserDescriptor, listener: ExSocketInterface): void {
|
||||||
const subMessage = new SubMessage();
|
const subMessage = new SubMessage();
|
||||||
subMessage.setUserjoinedmessage(user.toUserJoinedMessage());
|
subMessage.setUserjoinedmessage(user.toUserJoinedMessage());
|
||||||
@ -642,6 +616,17 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public emitInvalidTextureMessage(client: compressors.WebSocket) {
|
||||||
|
const errorMessage = new InvalidTextureMessage();
|
||||||
|
|
||||||
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
|
serverToClientMessage.setInvalidtexturemessage(errorMessage);
|
||||||
|
|
||||||
|
if (!client.disconnecting) {
|
||||||
|
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public emitConnexionErrorMessage(client: compressors.WebSocket, message: string) {
|
public emitConnexionErrorMessage(client: compressors.WebSocket, message: string) {
|
||||||
const errorMessage = new WorldConnexionMessage();
|
const errorMessage = new WorldConnexionMessage();
|
||||||
errorMessage.setMessage(message);
|
errorMessage.setMessage(message);
|
||||||
|
5
pusher/src/Services/WokaService.ts
Normal file
5
pusher/src/Services/WokaService.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
||||||
|
import { adminWokaService } from "./AdminWokaService";
|
||||||
|
import { localWokaService } from "./LocalWokaService";
|
||||||
|
|
||||||
|
export const wokaService = ADMIN_API_URL ? adminWokaService : localWokaService;
|
@ -14,5 +14,5 @@ export interface WokaServiceInterface {
|
|||||||
*
|
*
|
||||||
* If one of the textures cannot be found, undefined is returned (and the user should be redirected to Woka choice page!)
|
* If one of the textures cannot be found, undefined is returned (and the user should be redirected to Woka choice page!)
|
||||||
*/
|
*/
|
||||||
fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined>;
|
//fetchWokaDetails(textureIds: string[]): Promise<WokaDetailsResult | undefined>;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user