Merge pull request #350 from thecodingmachine/develop
Release 2020-10-20 2
This commit is contained in:
commit
1dfc51ada6
@ -31,7 +31,6 @@ export class AuthenticateController extends BaseController {
|
|||||||
res.onAborted(() => {
|
res.onAborted(() => {
|
||||||
console.warn('Login request was aborted');
|
console.warn('Login request was aborted');
|
||||||
})
|
})
|
||||||
const host = req.getHeader('host');
|
|
||||||
const param = await res.json();
|
const param = await res.json();
|
||||||
|
|
||||||
//todo: what to do if the organizationMemberToken is already used?
|
//todo: what to do if the organizationMemberToken is already used?
|
||||||
@ -45,6 +44,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
const worldSlug = data.worldSlug;
|
const worldSlug = data.worldSlug;
|
||||||
const roomSlug = data.roomSlug;
|
const roomSlug = data.roomSlug;
|
||||||
const mapUrlStart = data.mapUrlStart;
|
const mapUrlStart = data.mapUrlStart;
|
||||||
|
const textures = data.textures;
|
||||||
|
|
||||||
const authToken = jwtTokenManager.createJWTToken(userUuid);
|
const authToken = jwtTokenManager.createJWTToken(userUuid);
|
||||||
res.writeStatus("200 OK");
|
res.writeStatus("200 OK");
|
||||||
@ -56,6 +56,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
worldSlug,
|
worldSlug,
|
||||||
roomSlug,
|
roomSlug,
|
||||||
mapUrlStart,
|
mapUrlStart,
|
||||||
|
textures
|
||||||
}));
|
}));
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
import {CharacterLayer, ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO fix import by "_Model/.."
|
||||||
import {GameRoomPolicyTypes} from "../Model/GameRoom";
|
import {GameRoomPolicyTypes} from "../Model/GameRoom";
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
import {PointInterface} from "../Model/Websocket/PointInterface";
|
||||||
import {
|
import {
|
||||||
@ -18,10 +18,9 @@ import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
|||||||
import {TemplatedApp} from "uWebSockets.js"
|
import {TemplatedApp} from "uWebSockets.js"
|
||||||
import {parse} from "query-string";
|
import {parse} from "query-string";
|
||||||
import {jwtTokenManager} from "../Services/JWTTokenManager";
|
import {jwtTokenManager} from "../Services/JWTTokenManager";
|
||||||
import {adminApi, fetchMemberDataByUuidResponse} from "../Services/AdminApi";
|
import {adminApi, CharacterTexture, FetchMemberDataByUuidResponse} from "../Services/AdminApi";
|
||||||
import {socketManager} from "../Services/SocketManager";
|
import {SocketManager, socketManager} from "../Services/SocketManager";
|
||||||
import {emitInBatch, resetPing} from "../Services/IoSocketHelpers";
|
import {emitInBatch, resetPing} from "../Services/IoSocketHelpers";
|
||||||
import Jwt from "jsonwebtoken";
|
|
||||||
import {clientEventsEmitter} from "../Services/ClientEventsEmitter";
|
import {clientEventsEmitter} from "../Services/ClientEventsEmitter";
|
||||||
import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable";
|
import {ADMIN_API_TOKEN} from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
@ -159,24 +158,27 @@ export class IoSocketController {
|
|||||||
characterLayers = [ characterLayers ];
|
characterLayers = [ characterLayers ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const userUuid = await jwtTokenManager.getUserUuidFromToken(token);
|
const userUuid = await jwtTokenManager.getUserUuidFromToken(token);
|
||||||
|
|
||||||
let memberTags: string[] = [];
|
let memberTags: string[] = [];
|
||||||
|
let memberTextures: CharacterTexture[] = [];
|
||||||
const room = await socketManager.getOrCreateRoom(roomId);
|
const room = await socketManager.getOrCreateRoom(roomId);
|
||||||
if (!room.anonymous && room.policyType !== GameRoomPolicyTypes.ANONYMUS_POLICY) {
|
|
||||||
try {
|
try {
|
||||||
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
||||||
|
//console.log('USERDATA', userData)
|
||||||
memberTags = userData.tags;
|
memberTags = userData.tags;
|
||||||
if (room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && !room.canAccess(memberTags)) {
|
memberTextures = userData.textures;
|
||||||
|
if (!room.anonymous && room.policyType === GameRoomPolicyTypes.USE_TAGS_POLICY && !room.canAccess(memberTags)) {
|
||||||
throw new Error('No correct tags')
|
throw new Error('No correct tags')
|
||||||
}
|
}
|
||||||
console.log('access granted for user '+userUuid+' and room '+roomId);
|
//console.log('access granted for user '+userUuid+' and room '+roomId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('access not granted for user '+userUuid+' and room '+roomId);
|
console.log('access not granted for user '+userUuid+' and room '+roomId);
|
||||||
throw new Error('Client cannot acces this ressource.')
|
throw new Error('Client cannot acces this ressource.')
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Generate characterLayers objects from characterLayers string[]
|
||||||
|
const characterLayerObjs: CharacterLayer[] = 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!");
|
||||||
@ -192,8 +194,9 @@ export class IoSocketController {
|
|||||||
userUuid,
|
userUuid,
|
||||||
roomId,
|
roomId,
|
||||||
name,
|
name,
|
||||||
characterLayers,
|
characterLayers: characterLayerObjs,
|
||||||
tags: memberTags,
|
tags: memberTags,
|
||||||
|
textures: memberTextures,
|
||||||
position: {
|
position: {
|
||||||
x: x,
|
x: x,
|
||||||
y: y,
|
y: y,
|
||||||
@ -233,7 +236,7 @@ export class IoSocketController {
|
|||||||
resetPing(client);
|
resetPing(client);
|
||||||
|
|
||||||
//get data information and shwo messages
|
//get data information and shwo messages
|
||||||
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: fetchMemberDataByUuidResponse) => {
|
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: FetchMemberDataByUuidResponse) => {
|
||||||
if (!res.messages) {
|
if (!res.messages) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -311,6 +314,7 @@ export class IoSocketController {
|
|||||||
|
|
||||||
client.name = ws.name;
|
client.name = ws.name;
|
||||||
client.tags = ws.tags;
|
client.tags = ws.tags;
|
||||||
|
client.textures = ws.textures;
|
||||||
client.characterLayers = ws.characterLayers;
|
client.characterLayers = ws.characterLayers;
|
||||||
client.roomId = ws.roomId;
|
client.roomId = ws.roomId;
|
||||||
return client;
|
return client;
|
||||||
|
@ -3,6 +3,12 @@ import {Identificable} from "./Identificable";
|
|||||||
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
||||||
import {BatchMessage, SubMessage} from "../../Messages/generated/messages_pb";
|
import {BatchMessage, SubMessage} from "../../Messages/generated/messages_pb";
|
||||||
import {WebSocket} from "uWebSockets.js"
|
import {WebSocket} from "uWebSockets.js"
|
||||||
|
import {CharacterTexture} from "../../Services/AdminApi";
|
||||||
|
|
||||||
|
export interface CharacterLayer {
|
||||||
|
name: string,
|
||||||
|
url: string|undefined
|
||||||
|
}
|
||||||
|
|
||||||
export interface ExSocketInterface extends WebSocket, Identificable {
|
export interface ExSocketInterface extends WebSocket, Identificable {
|
||||||
token: string;
|
token: string;
|
||||||
@ -10,7 +16,7 @@ export interface ExSocketInterface extends WebSocket, Identificable {
|
|||||||
//userId: number; // A temporary (autoincremented) identifier for this user
|
//userId: number; // A temporary (autoincremented) identifier for this user
|
||||||
userUuid: string; // A unique identifier for this user
|
userUuid: string; // A unique identifier for this user
|
||||||
name: string;
|
name: string;
|
||||||
characterLayers: string[];
|
characterLayers: CharacterLayer[];
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
viewport: ViewportInterface;
|
viewport: ViewportInterface;
|
||||||
/**
|
/**
|
||||||
@ -21,5 +27,6 @@ export interface ExSocketInterface extends WebSocket, Identificable {
|
|||||||
batchTimeout: NodeJS.Timeout|null;
|
batchTimeout: NodeJS.Timeout|null;
|
||||||
pingTimeout: NodeJS.Timeout|null;
|
pingTimeout: NodeJS.Timeout|null;
|
||||||
disconnecting: boolean,
|
disconnecting: boolean,
|
||||||
tags: string[]
|
tags: string[],
|
||||||
|
textures: CharacterTexture[],
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import {PointInterface} from "./PointInterface";
|
import {PointInterface} from "./PointInterface";
|
||||||
import {ItemEventMessage, PointMessage, PositionMessage} from "../../Messages/generated/messages_pb";
|
import {
|
||||||
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
CharacterLayerMessage,
|
||||||
|
ItemEventMessage,
|
||||||
|
PointMessage,
|
||||||
|
PositionMessage
|
||||||
|
} from "../../Messages/generated/messages_pb";
|
||||||
|
import {CharacterLayer, 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";
|
||||||
@ -89,4 +94,15 @@ export class ProtobufUtils {
|
|||||||
|
|
||||||
return itemEventMessage;
|
return itemEventMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static toCharacterLayerMessages(characterLayers: CharacterLayer[]): CharacterLayerMessage[] {
|
||||||
|
return characterLayers.map(function(characterLayer): CharacterLayerMessage {
|
||||||
|
const message = new CharacterLayerMessage();
|
||||||
|
message.setName(characterLayer.name);
|
||||||
|
if (characterLayer.url) {
|
||||||
|
message.setUrl(characterLayer.url);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
|
import {v4} from "uuid";
|
||||||
|
|
||||||
export interface AdminApiData {
|
export interface AdminApiData {
|
||||||
organizationSlug: string
|
organizationSlug: string
|
||||||
@ -9,12 +10,21 @@ export interface AdminApiData {
|
|||||||
tags: string[]
|
tags: string[]
|
||||||
policy_type: number
|
policy_type: number
|
||||||
userUuid: string
|
userUuid: string
|
||||||
messages?: unknown[]
|
messages?: unknown[],
|
||||||
|
textures: CharacterTexture[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface fetchMemberDataByUuidResponse {
|
export interface CharacterTexture {
|
||||||
|
id: number,
|
||||||
|
level: number,
|
||||||
|
url: string,
|
||||||
|
rights: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FetchMemberDataByUuidResponse {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
|
textures: CharacterTexture[];
|
||||||
messages: unknown[];
|
messages: unknown[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,14 +53,29 @@ class AdminApi {
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchMemberDataByUuid(uuid: string): Promise<fetchMemberDataByUuidResponse> {
|
async fetchMemberDataByUuid(uuid: string): Promise<FetchMemberDataByUuidResponse> {
|
||||||
if (!ADMIN_API_URL) {
|
if (!ADMIN_API_URL) {
|
||||||
return Promise.reject('No admin backoffice set!');
|
return Promise.reject('No admin backoffice set!');
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
const res = await Axios.get(ADMIN_API_URL+'/api/membership/'+uuid,
|
const res = await Axios.get(ADMIN_API_URL+'/api/membership/'+uuid,
|
||||||
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
|
||||||
)
|
)
|
||||||
return res.data;
|
return res.data;
|
||||||
|
} catch (e) {
|
||||||
|
if (e?.response?.status == 404) {
|
||||||
|
// If we get an HTTP 404, the token is invalid. Let's perform an anonymous login!
|
||||||
|
console.warn('Cannot find user with uuid "'+uuid+'". Performing an anonymous login instead.');
|
||||||
|
return {
|
||||||
|
uuid: v4(),
|
||||||
|
tags: [],
|
||||||
|
textures: [],
|
||||||
|
messages: [],
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchMemberDataByToken(organizationMemberToken: string): Promise<AdminApiData> {
|
async fetchMemberDataByToken(organizationMemberToken: string): Promise<AdminApiData> {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {GameRoom} from "../Model/GameRoom";
|
import {GameRoom} from "../Model/GameRoom";
|
||||||
import {ExSocketInterface} from "../Model/Websocket/ExSocketInterface";
|
import {CharacterLayer, ExSocketInterface} from "../Model/Websocket/ExSocketInterface";
|
||||||
import {
|
import {
|
||||||
GroupDeleteMessage,
|
GroupDeleteMessage,
|
||||||
GroupUpdateMessage,
|
GroupUpdateMessage,
|
||||||
@ -23,6 +23,7 @@ import {
|
|||||||
WebRtcStartMessage,
|
WebRtcStartMessage,
|
||||||
QueryJitsiJwtMessage,
|
QueryJitsiJwtMessage,
|
||||||
SendJitsiJwtMessage,
|
SendJitsiJwtMessage,
|
||||||
|
CharacterLayerMessage,
|
||||||
SendUserMessage
|
SendUserMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
import {PointInterface} from "../Model/Websocket/PointInterface";
|
||||||
@ -34,7 +35,7 @@ import {isSetPlayerDetailsMessage} from "../Model/Websocket/SetPlayerDetailsMess
|
|||||||
import {GROUP_RADIUS, JITSI_ISS, MINIMUM_DISTANCE, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
|
import {GROUP_RADIUS, JITSI_ISS, MINIMUM_DISTANCE, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
|
||||||
import {Movable} from "../Model/Movable";
|
import {Movable} from "../Model/Movable";
|
||||||
import {PositionInterface} from "../Model/PositionInterface";
|
import {PositionInterface} from "../Model/PositionInterface";
|
||||||
import {adminApi} from "./AdminApi";
|
import {adminApi, CharacterTexture} from "./AdminApi";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {Gauge} from "prom-client";
|
import {Gauge} from "prom-client";
|
||||||
import {emitError, emitInBatch} from "./IoSocketHelpers";
|
import {emitError, emitInBatch} from "./IoSocketHelpers";
|
||||||
@ -54,7 +55,7 @@ export interface AdminSocketData {
|
|||||||
users: AdminSocketUsersList,
|
users: AdminSocketUsersList,
|
||||||
}
|
}
|
||||||
|
|
||||||
class SocketManager {
|
export class SocketManager {
|
||||||
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
||||||
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
private sockets: Map<number, ExSocketInterface> = new Map<number, ExSocketInterface>();
|
||||||
private nbClientsGauge: Gauge<string>;
|
private nbClientsGauge: Gauge<string>;
|
||||||
@ -125,7 +126,7 @@ class SocketManager {
|
|||||||
const userJoinedMessage = new UserJoinedMessage();
|
const userJoinedMessage = new UserJoinedMessage();
|
||||||
userJoinedMessage.setUserid(thing.id);
|
userJoinedMessage.setUserid(thing.id);
|
||||||
userJoinedMessage.setName(player.name);
|
userJoinedMessage.setName(player.name);
|
||||||
userJoinedMessage.setCharacterlayersList(player.characterLayers);
|
userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(player.characterLayers));
|
||||||
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(player.position));
|
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(player.position));
|
||||||
|
|
||||||
roomJoinedMessage.addUser(userJoinedMessage);
|
roomJoinedMessage.addUser(userJoinedMessage);
|
||||||
@ -251,8 +252,7 @@ class SocketManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
client.name = playerDetails.name;
|
client.name = playerDetails.name;
|
||||||
client.characterLayers = playerDetails.characterLayers;
|
client.characterLayers = SocketManager.mergeCharacterLayersAndCustomTextures(playerDetails.characterLayers, client.textures);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSilentMessage(client: ExSocketInterface, silentMessage: SilentMessage) {
|
handleSilentMessage(client: ExSocketInterface, silentMessage: SilentMessage) {
|
||||||
@ -438,7 +438,7 @@ class SocketManager {
|
|||||||
}
|
}
|
||||||
userJoinedMessage.setUserid(clientUser.userId);
|
userJoinedMessage.setUserid(clientUser.userId);
|
||||||
userJoinedMessage.setName(clientUser.name);
|
userJoinedMessage.setName(clientUser.name);
|
||||||
userJoinedMessage.setCharacterlayersList(clientUser.characterLayers);
|
userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(clientUser.characterLayers));
|
||||||
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(clientUser.position));
|
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(clientUser.position));
|
||||||
|
|
||||||
const subMessage = new SubMessage();
|
const subMessage = new SubMessage();
|
||||||
@ -691,6 +691,33 @@ class SocketManager {
|
|||||||
}
|
}
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketManager = new SocketManager();
|
export const socketManager = new SocketManager();
|
||||||
|
@ -21,7 +21,7 @@ class ConnectionManager {
|
|||||||
if(connexionType === GameConnexionTypes.register) {
|
if(connexionType === GameConnexionTypes.register) {
|
||||||
const organizationMemberToken = urlManager.getOrganizationToken();
|
const organizationMemberToken = urlManager.getOrganizationToken();
|
||||||
const data = await Axios.post(`${API_URL}/register`, {organizationMemberToken}).then(res => res.data);
|
const data = await Axios.post(`${API_URL}/register`, {organizationMemberToken}).then(res => res.data);
|
||||||
this.localUser = new LocalUser(data.userUuid, data.authToken);
|
this.localUser = new LocalUser(data.userUuid, data.authToken, data.textures);
|
||||||
localUserStore.saveUser(this.localUser);
|
localUserStore.saveUser(this.localUser);
|
||||||
|
|
||||||
const organizationSlug = data.organizationSlug;
|
const organizationSlug = data.organizationSlug;
|
||||||
@ -34,7 +34,7 @@ class ConnectionManager {
|
|||||||
} else if (connexionType === GameConnexionTypes.anonymous || connexionType === GameConnexionTypes.empty) {
|
} else if (connexionType === GameConnexionTypes.anonymous || connexionType === GameConnexionTypes.empty) {
|
||||||
const localUser = localUserStore.getLocalUser();
|
const localUser = localUserStore.getLocalUser();
|
||||||
|
|
||||||
if (localUser && localUser.jwtToken && localUser.uuid) {
|
if (localUser && localUser.jwtToken && localUser.uuid && localUser.textures) {
|
||||||
this.localUser = localUser;
|
this.localUser = localUser;
|
||||||
try {
|
try {
|
||||||
await this.verifyToken(localUser.jwtToken);
|
await this.verifyToken(localUser.jwtToken);
|
||||||
@ -78,12 +78,12 @@ class ConnectionManager {
|
|||||||
|
|
||||||
private async anonymousLogin(): Promise<void> {
|
private async anonymousLogin(): Promise<void> {
|
||||||
const data = await Axios.post(`${API_URL}/anonymLogin`).then(res => res.data);
|
const data = await Axios.post(`${API_URL}/anonymLogin`).then(res => res.data);
|
||||||
this.localUser = new LocalUser(data.userUuid, data.authToken);
|
this.localUser = new LocalUser(data.userUuid, data.authToken, []);
|
||||||
localUserStore.saveUser(this.localUser);
|
localUserStore.saveUser(this.localUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public initBenchmark(): void {
|
public initBenchmark(): void {
|
||||||
this.localUser = new LocalUser('', 'test');
|
this.localUser = new LocalUser('', 'test', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public connectToRoomSocket(roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface): Promise<RoomConnection> {
|
public connectToRoomSocket(roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface): Promise<RoomConnection> {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {PlayerAnimationNames} from "../Phaser/Player/Animation";
|
import {PlayerAnimationNames} from "../Phaser/Player/Animation";
|
||||||
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
||||||
import {SignalData} from "simple-peer";
|
import {SignalData} from "simple-peer";
|
||||||
|
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/body_character";
|
||||||
|
|
||||||
export enum EventMessage{
|
export enum EventMessage{
|
||||||
WEBRTC_SIGNAL = "webrtc-signal",
|
WEBRTC_SIGNAL = "webrtc-signal",
|
||||||
@ -49,7 +50,7 @@ export class Point implements PointInterface{
|
|||||||
export interface MessageUserPositionInterface {
|
export interface MessageUserPositionInterface {
|
||||||
userId: number;
|
userId: number;
|
||||||
name: string;
|
name: string;
|
||||||
characterLayers: string[];
|
characterLayers: BodyResourceDescriptionInterface[];
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ export interface MessageUserMovedInterface {
|
|||||||
export interface MessageUserJoined {
|
export interface MessageUserJoined {
|
||||||
userId: number;
|
userId: number;
|
||||||
name: string;
|
name: string;
|
||||||
characterLayers: string[];
|
characterLayers: BodyResourceDescriptionInterface[];
|
||||||
position: PointInterface
|
position: PointInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
export class LocalUser {
|
export interface CharacterTexture {
|
||||||
public uuid: string;
|
id: number,
|
||||||
public jwtToken: string;
|
level: number,
|
||||||
|
url: string,
|
||||||
|
rights: string
|
||||||
|
}
|
||||||
|
|
||||||
constructor(uuid:string, jwtToken: string) {
|
export class LocalUser {
|
||||||
this.uuid = uuid;
|
constructor(public readonly uuid:string, public readonly jwtToken: string, public readonly textures: CharacterTexture[]) {
|
||||||
this.jwtToken = jwtToken;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,6 @@ class LocalUserStore {
|
|||||||
saveUser(localUser: LocalUser) {
|
saveUser(localUser: LocalUser) {
|
||||||
localStorage.setItem('localUser', JSON.stringify(localUser));
|
localStorage.setItem('localUser', JSON.stringify(localUser));
|
||||||
}
|
}
|
||||||
|
|
||||||
getLocalUser(): LocalUser|null {
|
getLocalUser(): LocalUser|null {
|
||||||
const data = localStorage.getItem('localUser');
|
const data = localStorage.getItem('localUser');
|
||||||
return data ? JSON.parse(data) : null;
|
return data ? JSON.parse(data) : null;
|
||||||
@ -15,11 +14,23 @@ class LocalUserStore {
|
|||||||
setName(name:string): void {
|
setName(name:string): void {
|
||||||
window.localStorage.setItem('playerName', name);
|
window.localStorage.setItem('playerName', name);
|
||||||
}
|
}
|
||||||
|
|
||||||
getName(): string {
|
getName(): string {
|
||||||
return window.localStorage.getItem('playerName') ?? '';
|
return window.localStorage.getItem('playerName') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPlayerCharacterIndex(playerCharacterIndex: number): void {
|
||||||
|
window.localStorage.setItem('selectedPlayer', ''+playerCharacterIndex);
|
||||||
|
}
|
||||||
|
getPlayerCharacterIndex(): number {
|
||||||
|
return parseInt(window.localStorage.getItem('selectedPlayer') || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
setCustomCursorPosition(activeRow:number, selectedLayers: number[]): void {
|
||||||
|
window.localStorage.setItem('customCursorPosition', JSON.stringify({activeRow, selectedLayers}));
|
||||||
|
}
|
||||||
|
getCustomCursorPosition(): {activeRow:number, selectedLayers:number[]}|null {
|
||||||
|
return JSON.parse(window.localStorage.getItem('customCursorPosition') || "null");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const localUserStore = new LocalUserStore();
|
export const localUserStore = new LocalUserStore();
|
@ -22,7 +22,11 @@ import {
|
|||||||
WebRtcSignalToServerMessage,
|
WebRtcSignalToServerMessage,
|
||||||
WebRtcStartMessage,
|
WebRtcStartMessage,
|
||||||
ReportPlayerMessage,
|
ReportPlayerMessage,
|
||||||
TeleportMessageMessage, QueryJitsiJwtMessage, SendJitsiJwtMessage, SendUserMessage
|
TeleportMessageMessage,
|
||||||
|
QueryJitsiJwtMessage,
|
||||||
|
SendJitsiJwtMessage,
|
||||||
|
CharacterLayerMessage,
|
||||||
|
SendUserMessage
|
||||||
} from "../Messages/generated/messages_pb"
|
} from "../Messages/generated/messages_pb"
|
||||||
|
|
||||||
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
||||||
@ -36,6 +40,7 @@ import {
|
|||||||
ViewportInterface, WebRtcDisconnectMessageInterface,
|
ViewportInterface, WebRtcDisconnectMessageInterface,
|
||||||
WebRtcSignalReceivedMessageInterface,
|
WebRtcSignalReceivedMessageInterface,
|
||||||
} from "./ConnexionModels";
|
} from "./ConnexionModels";
|
||||||
|
import {BodyResourceDescriptionInterface} from "../Phaser/Entity/body_character";
|
||||||
|
|
||||||
export class RoomConnection implements RoomConnection {
|
export class RoomConnection implements RoomConnection {
|
||||||
private readonly socket: WebSocket;
|
private readonly socket: WebSocket;
|
||||||
@ -169,10 +174,10 @@ export class RoomConnection implements RoomConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public emitPlayerDetailsMessage(userName: string, characterLayersSelected: string[]) {
|
public emitPlayerDetailsMessage(userName: string, characterLayersSelected: BodyResourceDescriptionInterface[]) {
|
||||||
const message = new SetPlayerDetailsMessage();
|
const message = new SetPlayerDetailsMessage();
|
||||||
message.setName(userName);
|
message.setName(userName);
|
||||||
message.setCharacterlayersList(characterLayersSelected);
|
message.setCharacterlayersList(characterLayersSelected.map((characterLayer) => characterLayer.name));
|
||||||
|
|
||||||
const clientToServerMessage = new ClientToServerMessage();
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
clientToServerMessage.setSetplayerdetailsmessage(message);
|
clientToServerMessage.setSetplayerdetailsmessage(message);
|
||||||
@ -277,10 +282,18 @@ export class RoomConnection implements RoomConnection {
|
|||||||
if (position === undefined) {
|
if (position === undefined) {
|
||||||
throw new Error('Invalid JOIN_ROOM message');
|
throw new Error('Invalid JOIN_ROOM message');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const characterLayers = message.getCharacterlayersList().map((characterLayer: CharacterLayerMessage): BodyResourceDescriptionInterface => {
|
||||||
|
return {
|
||||||
|
name: characterLayer.getName(),
|
||||||
|
img: characterLayer.getUrl()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userId: message.getUserid(),
|
userId: message.getUserid(),
|
||||||
name: message.getName(),
|
name: message.getName(),
|
||||||
characterLayers: message.getCharacterlayersList(),
|
characterLayers,
|
||||||
position: ProtobufClientUtils.toPointInterface(position)
|
position: ProtobufClientUtils.toPointInterface(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,22 +61,7 @@ export abstract class Character extends Container {
|
|||||||
|
|
||||||
this.sprites = new Map<string, Sprite>();
|
this.sprites = new Map<string, Sprite>();
|
||||||
|
|
||||||
for (const texture of textures) {
|
this.addTextures(textures, frame);
|
||||||
const sprite = new Sprite(scene, 0, 0, texture, frame);
|
|
||||||
sprite.setInteractive({useHandCursor: true});
|
|
||||||
this.add(sprite);
|
|
||||||
this.getPlayerAnimations(texture).forEach(d => {
|
|
||||||
this.scene.anims.create({
|
|
||||||
key: d.key,
|
|
||||||
frames: this.scene.anims.generateFrameNumbers(d.frameModel, {start: d.frameStart, end: d.frameEnd}),
|
|
||||||
frameRate: d.frameRate,
|
|
||||||
repeat: d.repeat
|
|
||||||
});
|
|
||||||
})
|
|
||||||
// Needed, otherwise, animations are not handled correctly.
|
|
||||||
this.scene.sys.updateList.add(sprite);
|
|
||||||
this.sprites.set(texture, sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*this.teleportation = new Sprite(scene, -20, -10, 'teleportation', 3);
|
/*this.teleportation = new Sprite(scene, -20, -10, 'teleportation', 3);
|
||||||
this.teleportation.setInteractive();
|
this.teleportation.setInteractive();
|
||||||
@ -107,6 +92,25 @@ export abstract class Character extends Container {
|
|||||||
this.playAnimation(direction, moving);
|
this.playAnimation(direction, moving);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addTextures(textures: string[], frame?: string | number): void {
|
||||||
|
for (const texture of textures) {
|
||||||
|
const sprite = new Sprite(this.scene, 0, 0, texture, frame);
|
||||||
|
sprite.setInteractive({useHandCursor: true});
|
||||||
|
this.add(sprite);
|
||||||
|
this.getPlayerAnimations(texture).forEach(d => {
|
||||||
|
this.scene.anims.create({
|
||||||
|
key: d.key,
|
||||||
|
frames: this.scene.anims.generateFrameNumbers(d.frameModel, {start: d.frameStart, end: d.frameEnd}),
|
||||||
|
frameRate: d.frameRate,
|
||||||
|
repeat: d.repeat
|
||||||
|
});
|
||||||
|
})
|
||||||
|
// Needed, otherwise, animations are not handled correctly.
|
||||||
|
this.scene.sys.updateList.add(sprite);
|
||||||
|
this.sprites.set(texture, sprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private getPlayerAnimations(name: string): AnimationData[] {
|
private getPlayerAnimations(name: string): AnimationData[] {
|
||||||
return [{
|
return [{
|
||||||
key: `${name}-${PlayerAnimationNames.WalkDown}`,
|
key: `${name}-${PlayerAnimationNames.WalkDown}`,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
||||||
import {PLAYER_RESOURCES, PlayerResourceDescriptionInterface} from "./Character";
|
import {PLAYER_RESOURCES, PlayerResourceDescriptionInterface} from "./Character";
|
||||||
|
import {CharacterTexture} from "../../Connexion/LocalUser";
|
||||||
|
|
||||||
export interface BodyResourceDescriptionInterface {
|
export interface BodyResourceDescriptionInterface {
|
||||||
name: string,
|
name: string,
|
||||||
@ -312,6 +313,15 @@ export const loadAllLayers = (load: LoaderPlugin) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const loadCustomTexture = (load: LoaderPlugin, texture: CharacterTexture) => {
|
||||||
|
const name = 'customCharacterTexture'+texture.id;
|
||||||
|
load.spritesheet(
|
||||||
|
name,
|
||||||
|
texture.url,
|
||||||
|
{frameWidth: 32, frameHeight: 32}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export const OBJECTS: Array<PlayerResourceDescriptionInterface> = [
|
export const OBJECTS: Array<PlayerResourceDescriptionInterface> = [
|
||||||
{name:'layout_modes', img:'resources/objects/layout_modes.png'},
|
{name:'layout_modes', img:'resources/objects/layout_modes.png'},
|
||||||
{name:'teleportation', img:'resources/objects/teleportation.png'},
|
{name:'teleportation', img:'resources/objects/teleportation.png'},
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import {PointInterface} from "../../Connexion/ConnexionModels";
|
import {PointInterface} from "../../Connexion/ConnexionModels";
|
||||||
|
import {BodyResourceDescriptionInterface} from "../Entity/body_character";
|
||||||
|
|
||||||
export interface AddPlayerInterface {
|
export interface AddPlayerInterface {
|
||||||
userId: number;
|
userId: number;
|
||||||
name: string;
|
name: string;
|
||||||
characterLayers: string[];
|
characterLayers: BodyResourceDescriptionInterface[];
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import {GameScene} from "./GameScene";
|
import {GameScene} from "./GameScene";
|
||||||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||||
import {Room} from "../../Connexion/Room";
|
import {Room} from "../../Connexion/Room";
|
||||||
import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
|
|
||||||
|
|
||||||
export interface HasMovedEvent {
|
export interface HasMovedEvent {
|
||||||
direction: string;
|
direction: string;
|
||||||
@ -24,11 +23,7 @@ export class GameManager {
|
|||||||
this.playerName = name;
|
this.playerName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setCharacterUserSelected(characterUserSelected : string): void {
|
public setCharacterLayers(layers: string[]): void {
|
||||||
this.characterLayers = [characterUserSelected];
|
|
||||||
}
|
|
||||||
|
|
||||||
public setCharacterLayers(layers: string[]) {
|
|
||||||
this.characterLayers = layers;
|
this.characterLayers = layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,13 +49,6 @@ export class GameManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMapKeyByUrl(mapUrlStart: string) : string {
|
|
||||||
// FIXME: the key should be computed from the full URL of the map.
|
|
||||||
const startPos = mapUrlStart.indexOf('://')+3;
|
|
||||||
const endPos = mapUrlStart.indexOf(".json");
|
|
||||||
return mapUrlStart.substring(startPos, endPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async goToStartingMap(scenePlugin: Phaser.Scenes.ScenePlugin) {
|
public async goToStartingMap(scenePlugin: Phaser.Scenes.ScenePlugin) {
|
||||||
const url = await this.startRoom.getMapUrl();
|
const url = await this.startRoom.getMapUrl();
|
||||||
console.log('Starting scene '+url);
|
console.log('Starting scene '+url);
|
||||||
|
@ -32,7 +32,7 @@ import {RemotePlayer} from "../Entity/RemotePlayer";
|
|||||||
import {Queue} from 'queue-typescript';
|
import {Queue} from 'queue-typescript';
|
||||||
import {SimplePeer, UserSimplePeerInterface} from "../../WebRtc/SimplePeer";
|
import {SimplePeer, UserSimplePeerInterface} from "../../WebRtc/SimplePeer";
|
||||||
import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene";
|
import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene";
|
||||||
import {loadAllLayers, loadObject, loadPlayerCharacters} from "../Entity/body_character";
|
import {loadAllLayers, loadCustomTexture, loadObject, loadPlayerCharacters} from "../Entity/body_character";
|
||||||
import {CenterListener, layoutManager, LayoutMode} from "../../WebRtc/LayoutManager";
|
import {CenterListener, layoutManager, LayoutMode} from "../../WebRtc/LayoutManager";
|
||||||
import Texture = Phaser.Textures.Texture;
|
import Texture = Phaser.Textures.Texture;
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
@ -475,7 +475,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
this.stopJitsi();
|
this.stopJitsi();
|
||||||
} else {
|
} else {
|
||||||
console.log("JITSI_PRIVATE_MODE", JITSI_PRIVATE_MODE);
|
|
||||||
if (JITSI_PRIVATE_MODE) {
|
if (JITSI_PRIVATE_MODE) {
|
||||||
const adminTag = allProps.get("jitsiRoomAdminTag") as string|undefined;
|
const adminTag = allProps.get("jitsiRoomAdminTag") as string|undefined;
|
||||||
|
|
||||||
@ -1022,7 +1021,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
/**
|
/**
|
||||||
* Create new player
|
* Create new player
|
||||||
*/
|
*/
|
||||||
private doAddPlayer(addPlayerData : AddPlayerInterface) : void {
|
private async doAddPlayer(addPlayerData : AddPlayerInterface) : Promise<void> {
|
||||||
//check if exist player, if exist, move position
|
//check if exist player, if exist, move position
|
||||||
if(this.MapPlayersByKey.has(addPlayerData.userId)){
|
if(this.MapPlayersByKey.has(addPlayerData.userId)){
|
||||||
this.updatePlayerPosition({
|
this.updatePlayerPosition({
|
||||||
@ -1031,6 +1030,20 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Load textures (in case it is a custom texture)
|
||||||
|
const characterLayerList: string[] = [];
|
||||||
|
const loadPromises: Promise<void>[] = [];
|
||||||
|
for (const characterLayer of addPlayerData.characterLayers) {
|
||||||
|
characterLayerList.push(characterLayer.name);
|
||||||
|
if (characterLayer.img) {
|
||||||
|
console.log('LOADING ', characterLayer.name, characterLayer.img)
|
||||||
|
loadPromises.push(this.loadSpritesheet(characterLayer.name, characterLayer.img));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (loadPromises.length > 0) {
|
||||||
|
this.load.start();
|
||||||
|
}
|
||||||
|
|
||||||
//initialise player
|
//initialise player
|
||||||
const player = new RemotePlayer(
|
const player = new RemotePlayer(
|
||||||
addPlayerData.userId,
|
addPlayerData.userId,
|
||||||
@ -1038,7 +1051,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
addPlayerData.position.x,
|
addPlayerData.position.x,
|
||||||
addPlayerData.position.y,
|
addPlayerData.position.y,
|
||||||
addPlayerData.name,
|
addPlayerData.name,
|
||||||
addPlayerData.characterLayers,
|
[], // Let's go with no textures and let's load textures when promises have returned.
|
||||||
addPlayerData.position.direction,
|
addPlayerData.position.direction,
|
||||||
addPlayerData.position.moving
|
addPlayerData.position.moving
|
||||||
);
|
);
|
||||||
@ -1046,10 +1059,15 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
this.MapPlayersByKey.set(player.userId, player);
|
this.MapPlayersByKey.set(player.userId, player);
|
||||||
player.updatePosition(addPlayerData.position);
|
player.updatePosition(addPlayerData.position);
|
||||||
|
|
||||||
|
|
||||||
|
await Promise.all(loadPromises);
|
||||||
|
|
||||||
|
player.addTextures(characterLayerList, 1);
|
||||||
//init collision
|
//init collision
|
||||||
/*this.physics.add.collider(this.CurrentPlayer, player, (CurrentPlayer: CurrentGamerInterface, MapPlayer: GamerInterface) => {
|
/*this.physics.add.collider(this.CurrentPlayer, player, (CurrentPlayer: CurrentGamerInterface, MapPlayer: GamerInterface) => {
|
||||||
CurrentPlayer.say("Hello, how are you ? ");
|
CurrentPlayer.say("Hello, how are you ? ");
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1245,4 +1263,18 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
CoWebsiteManager.closeCoWebsite();
|
CoWebsiteManager.closeCoWebsite();
|
||||||
mediaManager.showGameOverlay();
|
mediaManager.showGameOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private loadSpritesheet(name: string, url: string): Promise<void> {
|
||||||
|
return new Promise<void>(((resolve, reject) => {
|
||||||
|
this.load.spritesheet(
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
{frameWidth: 32, frameHeight: 32}
|
||||||
|
);
|
||||||
|
this.load.on('filecomplete-spritesheet-'+name, () => {
|
||||||
|
console.log('RESOURCE LOADED!');
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,13 @@ import {EnableCameraSceneName} from "./EnableCameraScene";
|
|||||||
import {TextField} from "../Components/TextField";
|
import {TextField} from "../Components/TextField";
|
||||||
import Image = Phaser.GameObjects.Image;
|
import Image = Phaser.GameObjects.Image;
|
||||||
import Rectangle = Phaser.GameObjects.Rectangle;
|
import Rectangle = Phaser.GameObjects.Rectangle;
|
||||||
import {LAYERS, loadAllLayers} from "../Entity/body_character";
|
import {BodyResourceDescriptionInterface, LAYERS, loadAllLayers, loadCustomTexture} from "../Entity/body_character";
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
import Container = Phaser.GameObjects.Container;
|
import Container = Phaser.GameObjects.Container;
|
||||||
import {gameManager} from "../Game/GameManager";
|
import {gameManager} from "../Game/GameManager";
|
||||||
import {ResizableScene} from "./ResizableScene";
|
import {ResizableScene} from "./ResizableScene";
|
||||||
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
|
import {PlayerResourceDescriptionInterface} from "../Entity/Character";
|
||||||
|
|
||||||
export const CustomizeSceneName = "CustomizeScene";
|
export const CustomizeSceneName = "CustomizeScene";
|
||||||
|
|
||||||
@ -32,9 +34,10 @@ export class CustomizeScene extends ResizableScene {
|
|||||||
|
|
||||||
private logo!: Image;
|
private logo!: Image;
|
||||||
|
|
||||||
private selectedLayers: Array<number> = [0];
|
private selectedLayers: number[] = [0];
|
||||||
private containersRow: Array<Array<Container>> = new Array<Array<Container>>();
|
private containersRow: Container[][] = [];
|
||||||
private activeRow = 0;
|
private activeRow:number = 0;
|
||||||
|
private layers: BodyResourceDescriptionInterface[][] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
@ -50,6 +53,23 @@ export class CustomizeScene extends ResizableScene {
|
|||||||
|
|
||||||
//load all the png files
|
//load all the png files
|
||||||
loadAllLayers(this.load);
|
loadAllLayers(this.load);
|
||||||
|
|
||||||
|
// load custom layers
|
||||||
|
this.layers = LAYERS;
|
||||||
|
|
||||||
|
const localUser = localUserStore.getLocalUser();
|
||||||
|
|
||||||
|
const textures = localUser?.textures;
|
||||||
|
if (textures) {
|
||||||
|
for (const texture of textures) {
|
||||||
|
loadCustomTexture(this.load, texture);
|
||||||
|
const name = 'customCharacterTexture'+texture.id;
|
||||||
|
this.layers[texture.level].unshift({
|
||||||
|
name,
|
||||||
|
img: texture.url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
@ -93,7 +113,7 @@ export class CustomizeScene extends ResizableScene {
|
|||||||
let i = 0;
|
let i = 0;
|
||||||
for (const layerItem of this.selectedLayers) {
|
for (const layerItem of this.selectedLayers) {
|
||||||
if (layerItem !== undefined) {
|
if (layerItem !== undefined) {
|
||||||
layers.push(LAYERS[i][layerItem].name);
|
layers.push(this.layers[i][layerItem].name);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -103,43 +123,47 @@ export class CustomizeScene extends ResizableScene {
|
|||||||
return this.scene.start(EnableCameraSceneName);
|
return this.scene.start(EnableCameraSceneName);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.input.keyboard.on('keydown-RIGHT', () => {
|
this.input.keyboard.on('keydown-RIGHT', () => this.moveCursorHorizontally(1));
|
||||||
if (this.selectedLayers[this.activeRow] === undefined) {
|
this.input.keyboard.on('keydown-LEFT', () => this.moveCursorHorizontally(-1));
|
||||||
this.selectedLayers[this.activeRow] = 0;
|
this.input.keyboard.on('keydown-DOWN', () => this.moveCursorVertically(1));
|
||||||
}
|
this.input.keyboard.on('keydown-UP', () => this.moveCursorVertically(-1));
|
||||||
if (this.selectedLayers[this.activeRow] < LAYERS[this.activeRow].length - 1) {
|
|
||||||
this.selectedLayers[this.activeRow]++;
|
const customCursorPosition = localUserStore.getCustomCursorPosition();
|
||||||
|
if (customCursorPosition) {
|
||||||
|
this.activeRow = customCursorPosition.activeRow;
|
||||||
|
this.selectedLayers = customCursorPosition.selectedLayers;
|
||||||
this.moveLayers();
|
this.moveLayers();
|
||||||
this.updateSelectedLayer();
|
this.updateSelectedLayer();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
this.input.keyboard.on('keydown-LEFT', () => {
|
private moveCursorHorizontally(index: number): void {
|
||||||
if (this.selectedLayers[this.activeRow] > 0) {
|
this.selectedLayers[this.activeRow] += index;
|
||||||
if (this.selectedLayers[this.activeRow] === 0) {
|
if (this.selectedLayers[this.activeRow] < 0) {
|
||||||
delete this.selectedLayers[this.activeRow];
|
this.selectedLayers[this.activeRow] = 0
|
||||||
} else {
|
} else if(this.selectedLayers[this.activeRow] > this.layers[this.activeRow].length - 1) {
|
||||||
this.selectedLayers[this.activeRow]--;
|
this.selectedLayers[this.activeRow] = this.layers[this.activeRow].length - 1
|
||||||
}
|
}
|
||||||
this.moveLayers();
|
this.moveLayers();
|
||||||
this.updateSelectedLayer();
|
this.updateSelectedLayer();
|
||||||
|
this.saveInLocalStorage();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.input.keyboard.on('keydown-DOWN', () => {
|
private moveCursorVertically(index:number): void {
|
||||||
if (this.activeRow < LAYERS.length - 1) {
|
this.activeRow += index;
|
||||||
this.activeRow++;
|
if (this.activeRow < 0) {
|
||||||
this.moveLayers();
|
this.activeRow = 0
|
||||||
|
} else if (this.activeRow > this.layers.length - 1) {
|
||||||
|
this.activeRow = this.layers.length - 1
|
||||||
|
}
|
||||||
|
this.moveLayers();
|
||||||
|
this.saveInLocalStorage();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.input.keyboard.on('keydown-UP', () => {
|
private saveInLocalStorage() {
|
||||||
if (this.activeRow > 0) {
|
localUserStore.setCustomCursorPosition(this.activeRow, this.selectedLayers);
|
||||||
this.activeRow--;
|
|
||||||
this.moveLayers();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update(time: number, delta: number): void {
|
update(time: number, delta: number): void {
|
||||||
super.update(time, delta);
|
super.update(time, delta);
|
||||||
this.enterField.setVisible(!!(Math.floor(time / 500) % 2));
|
this.enterField.setVisible(!!(Math.floor(time / 500) % 2));
|
||||||
@ -148,14 +172,15 @@ export class CustomizeScene extends ResizableScene {
|
|||||||
/**
|
/**
|
||||||
* @param x, the layer's vertical position
|
* @param x, the layer's vertical position
|
||||||
* @param y, the layer's horizontal position
|
* @param y, the layer's horizontal position
|
||||||
* @param layerNumber, index of the LAYERS array
|
* @param layerNumber, index of the this.layers array
|
||||||
* create the layer and display it on the scene
|
* create the layer and display it on the scene
|
||||||
*/
|
*/
|
||||||
private createCustomizeLayer(x: number, y: number, layerNumber: number): void {
|
private createCustomizeLayer(x: number, y: number, layerNumber: number): void {
|
||||||
this.containersRow[layerNumber] = new Array<Container>();
|
this.containersRow[layerNumber] = [];
|
||||||
|
this.selectedLayers[layerNumber] = 0;
|
||||||
let alpha = 0;
|
let alpha = 0;
|
||||||
let layerPosX = 0;
|
let layerPosX = 0;
|
||||||
for (let i = 0; i < LAYERS[layerNumber].length; i++) {
|
for (let i = 0; i < this.layers[layerNumber].length; i++) {
|
||||||
const container = this.generateCharacter(300 + x + layerPosX, y, layerNumber, i);
|
const container = this.generateCharacter(300 + x + layerPosX, y, layerNumber, i);
|
||||||
|
|
||||||
this.containersRow[layerNumber][i] = container;
|
this.containersRow[layerNumber][i] = container;
|
||||||
@ -184,13 +209,13 @@ export class CustomizeScene extends ResizableScene {
|
|||||||
const children: Array<Sprite> = new Array<Sprite>();
|
const children: Array<Sprite> = new Array<Sprite>();
|
||||||
for (let j = 0; j <= layerNumber; j++) {
|
for (let j = 0; j <= layerNumber; j++) {
|
||||||
if (j === layerNumber) {
|
if (j === layerNumber) {
|
||||||
children.push(this.generateLayers(0, 0, LAYERS[j][selectedItem].name));
|
children.push(this.generateLayers(0, 0, this.layers[j][selectedItem].name));
|
||||||
} else {
|
} else {
|
||||||
const layer = this.selectedLayers[j];
|
const layer = this.selectedLayers[j];
|
||||||
if (layer === undefined) {
|
if (layer === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
children.push(this.generateLayers(0, 0, LAYERS[j][layer].name));
|
children.push(this.generateLayers(0, 0, this.layers[j][layer].name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return children;
|
return children;
|
||||||
|
@ -6,6 +6,7 @@ import {PLAYER_RESOURCES, PlayerResourceDescriptionInterface} from "../Entity/Ch
|
|||||||
import {EnableCameraSceneName} from "./EnableCameraScene";
|
import {EnableCameraSceneName} from "./EnableCameraScene";
|
||||||
import {CustomizeSceneName} from "./CustomizeScene";
|
import {CustomizeSceneName} from "./CustomizeScene";
|
||||||
import {ResizableScene} from "./ResizableScene";
|
import {ResizableScene} from "./ResizableScene";
|
||||||
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
|
|
||||||
|
|
||||||
//todo: put this constants in a dedicated file
|
//todo: put this constants in a dedicated file
|
||||||
@ -99,12 +100,14 @@ export class SelectCharacterScene extends ResizableScene {
|
|||||||
/*create user*/
|
/*create user*/
|
||||||
this.createCurrentPlayer();
|
this.createCurrentPlayer();
|
||||||
|
|
||||||
if (window.localStorage) {
|
const playerNumber = localUserStore.getPlayerCharacterIndex();
|
||||||
const playerNumberStr: string = window.localStorage.getItem('selectedPlayer') ?? '0';
|
if (playerNumber && playerNumber !== -1) {
|
||||||
const playerNumber: number = Number(playerNumberStr);
|
|
||||||
this.selectedRectangleXPos = playerNumber % this.nbCharactersPerRow;
|
this.selectedRectangleXPos = playerNumber % this.nbCharactersPerRow;
|
||||||
this.selectedRectangleYPos = Math.floor(playerNumber / this.nbCharactersPerRow);
|
this.selectedRectangleYPos = Math.floor(playerNumber / this.nbCharactersPerRow);
|
||||||
this.updateSelectedPlayer();
|
this.updateSelectedPlayer();
|
||||||
|
} else if (playerNumber === -1) {
|
||||||
|
this.selectedRectangleYPos = Math.ceil(PLAYER_RESOURCES.length / this.nbCharactersPerRow);
|
||||||
|
this.updateSelectedPlayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,33 +116,14 @@ export class SelectCharacterScene extends ResizableScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private nextScene(): void {
|
private nextScene(): void {
|
||||||
|
|
||||||
if (this.selectedPlayer !== null) {
|
if (this.selectedPlayer !== null) {
|
||||||
gameManager.setCharacterUserSelected(this.selectedPlayer.texture.key);
|
gameManager.setCharacterLayers([this.selectedPlayer.texture.key]);
|
||||||
|
|
||||||
this.scene.start(EnableCameraSceneName);
|
this.scene.start(EnableCameraSceneName);
|
||||||
} else {
|
} else {
|
||||||
this.scene.start(CustomizeSceneName);
|
this.scene.start(CustomizeSceneName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the map URL and the instance from the current URL
|
|
||||||
*/
|
|
||||||
private findMapUrl(): [string, string]|null {
|
|
||||||
const path = window.location.pathname;
|
|
||||||
if (!path.startsWith('/_/')) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const instanceAndMap = path.substr(3);
|
|
||||||
const firstSlash = instanceAndMap.indexOf('/');
|
|
||||||
if (firstSlash === -1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const instance = instanceAndMap.substr(0, firstSlash);
|
|
||||||
return [window.location.protocol+'//'+instanceAndMap.substr(firstSlash+1), instance];
|
|
||||||
}
|
|
||||||
|
|
||||||
createCurrentPlayer(): void {
|
createCurrentPlayer(): void {
|
||||||
for (let i = 0; i <PLAYER_RESOURCES.length; i++) {
|
for (let i = 0; i <PLAYER_RESOURCES.length; i++) {
|
||||||
const playerResource = PLAYER_RESOURCES[i];
|
const playerResource = PLAYER_RESOURCES[i];
|
||||||
@ -200,6 +184,7 @@ export class SelectCharacterScene extends ResizableScene {
|
|||||||
this.selectedRectangle.setVisible(false);
|
this.selectedRectangle.setVisible(false);
|
||||||
this.customizeButtonSelected.setVisible(true);
|
this.customizeButtonSelected.setVisible(true);
|
||||||
this.customizeButton.setVisible(false);
|
this.customizeButton.setVisible(false);
|
||||||
|
localUserStore.setPlayerCharacterIndex(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.customizeButtonSelected.setVisible(false);
|
this.customizeButtonSelected.setVisible(false);
|
||||||
@ -213,9 +198,7 @@ export class SelectCharacterScene extends ResizableScene {
|
|||||||
const player = this.players[playerNumber];
|
const player = this.players[playerNumber];
|
||||||
player.play(PLAYER_RESOURCES[playerNumber].name);
|
player.play(PLAYER_RESOURCES[playerNumber].name);
|
||||||
this.selectedPlayer = player;
|
this.selectedPlayer = player;
|
||||||
if (window.localStorage) {
|
localUserStore.setPlayerCharacterIndex(playerNumber);
|
||||||
window.localStorage.setItem('selectedPlayer', String(playerNumber));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onResize(ev: UIEvent): void {
|
public onResize(ev: UIEvent): void {
|
||||||
|
@ -455,8 +455,7 @@ export class MediaManager {
|
|||||||
addStreamRemoteVideo(userId: string, stream : MediaStream){
|
addStreamRemoteVideo(userId: string, stream : MediaStream){
|
||||||
const remoteVideo = this.remoteVideo.get(userId);
|
const remoteVideo = this.remoteVideo.get(userId);
|
||||||
if (remoteVideo === undefined) {
|
if (remoteVideo === undefined) {
|
||||||
console.error('Unable to find video for ', userId);
|
throw `Unable to find video for ${userId}`;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
remoteVideo.srcObject = stream;
|
remoteVideo.srcObject = stream;
|
||||||
}
|
}
|
||||||
|
@ -126,10 +126,19 @@ export class SimplePeer {
|
|||||||
* create peer connection to bind users
|
* create peer connection to bind users
|
||||||
*/
|
*/
|
||||||
private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null{
|
private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null{
|
||||||
if(
|
const peerConnection = this.PeerConnectionArray.get(user.userId)
|
||||||
this.PeerConnectionArray.has(user.userId)
|
if(peerConnection){
|
||||||
){
|
if(peerConnection.destroyed){
|
||||||
console.log('Peer connection already exists to user '+user.userId)
|
peerConnection.toClose = true;
|
||||||
|
peerConnection.destroy();
|
||||||
|
const peerConnexionDeleted = this.PeerConnectionArray.delete(user.userId);
|
||||||
|
if(!peerConnexionDeleted){
|
||||||
|
throw 'Error to delete peer connection';
|
||||||
|
}
|
||||||
|
this.createPeerConnection(user);
|
||||||
|
}else {
|
||||||
|
peerConnection.toClose = false;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +159,7 @@ export class SimplePeer {
|
|||||||
mediaManager.addActiveVideo("" + user.userId, reportCallback, name);
|
mediaManager.addActiveVideo("" + user.userId, reportCallback, name);
|
||||||
|
|
||||||
const peer = new VideoPeer(user.userId, user.initiator ? user.initiator : false, this.Connection);
|
const peer = new VideoPeer(user.userId, user.initiator ? user.initiator : false, this.Connection);
|
||||||
|
peer.toClose = false;
|
||||||
// When a connection is established to a video stream, and if a screen sharing is taking place,
|
// When a connection is established to a video stream, and if a screen sharing is taking place,
|
||||||
// the user sharing screen should also initiate a connection to the remote user!
|
// the user sharing screen should also initiate a connection to the remote user!
|
||||||
peer.on('connect', () => {
|
peer.on('connect', () => {
|
||||||
@ -200,16 +210,17 @@ export class SimplePeer {
|
|||||||
//mediaManager.removeActiveVideo(userId);
|
//mediaManager.removeActiveVideo(userId);
|
||||||
const peer = this.PeerConnectionArray.get(userId);
|
const peer = this.PeerConnectionArray.get(userId);
|
||||||
if (peer === undefined) {
|
if (peer === undefined) {
|
||||||
console.warn("Tried to close connection for user "+userId+" but could not find user")
|
console.warn("closeConnection => Tried to close connection for user "+userId+" but could not find user");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//create temp perr to close
|
||||||
|
peer.toClose = true;
|
||||||
peer.destroy();
|
peer.destroy();
|
||||||
// FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray"
|
// FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray"
|
||||||
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
|
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
|
||||||
//console.log('Closing connection with '+userId);
|
|
||||||
this.PeerConnectionArray.delete(userId);
|
|
||||||
this.closeScreenSharingConnection(userId);
|
this.closeScreenSharingConnection(userId);
|
||||||
//console.log('Nb users in peerConnectionArray '+this.PeerConnectionArray.size);
|
|
||||||
for (const peerConnectionListener of this.peerConnectionListeners) {
|
for (const peerConnectionListener of this.peerConnectionListeners) {
|
||||||
peerConnectionListener.onDisconnect(userId);
|
peerConnectionListener.onDisconnect(userId);
|
||||||
}
|
}
|
||||||
@ -228,14 +239,16 @@ export class SimplePeer {
|
|||||||
mediaManager.removeActiveScreenSharingVideo("" + userId);
|
mediaManager.removeActiveScreenSharingVideo("" + userId);
|
||||||
const peer = this.PeerScreenSharingConnectionArray.get(userId);
|
const peer = this.PeerScreenSharingConnectionArray.get(userId);
|
||||||
if (peer === undefined) {
|
if (peer === undefined) {
|
||||||
console.warn("Tried to close connection for user "+userId+" but could not find user")
|
console.warn("closeScreenSharingConnection => Tried to close connection for user "+userId+" but could not find user")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray"
|
// FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray"
|
||||||
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
|
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
|
||||||
//console.log('Closing connection with '+userId);
|
//console.log('Closing connection with '+userId);
|
||||||
peer.destroy();
|
peer.destroy();
|
||||||
this.PeerScreenSharingConnectionArray.delete(userId)
|
if(!this.PeerScreenSharingConnectionArray.delete(userId)){
|
||||||
|
throw 'Couln\'t delete peer screen sharing connexion';
|
||||||
|
}
|
||||||
//console.log('Nb users in peerConnectionArray '+this.PeerConnectionArray.size);
|
//console.log('Nb users in peerConnectionArray '+this.PeerConnectionArray.size);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("closeConnection", err)
|
console.error("closeConnection", err)
|
||||||
@ -292,6 +305,9 @@ export class SimplePeer {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`receiveWebrtcSignal => ${data.userId}`, e);
|
console.error(`receiveWebrtcSignal => ${data.userId}`, e);
|
||||||
|
//force delete and recreate peer connexion
|
||||||
|
this.PeerScreenSharingConnectionArray.delete(data.userId);
|
||||||
|
this.receiveWebrtcScreenSharingSignal(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,10 @@ const Peer: SimplePeerNamespace.SimplePeer = require('simple-peer');
|
|||||||
* A peer connection used to transmit video / audio signals between 2 peers.
|
* A peer connection used to transmit video / audio signals between 2 peers.
|
||||||
*/
|
*/
|
||||||
export class VideoPeer extends Peer {
|
export class VideoPeer extends Peer {
|
||||||
constructor(private userId: number, initiator: boolean, private connection: RoomConnection) {
|
public toClose: boolean = false;
|
||||||
|
public _connected: boolean = false;
|
||||||
|
|
||||||
|
constructor(public userId: number, initiator: boolean, private connection: RoomConnection) {
|
||||||
super({
|
super({
|
||||||
initiator: initiator ? initiator : false,
|
initiator: initiator ? initiator : false,
|
||||||
reconnectTimer: 10000,
|
reconnectTimer: 10000,
|
||||||
@ -57,6 +60,8 @@ export class VideoPeer extends Peer {
|
|||||||
});*/
|
});*/
|
||||||
|
|
||||||
this.on('close', () => {
|
this.on('close', () => {
|
||||||
|
this._connected = false;
|
||||||
|
this.toClose = true;
|
||||||
this.destroy();
|
this.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -67,6 +72,7 @@ export class VideoPeer extends Peer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.on('connect', () => {
|
this.on('connect', () => {
|
||||||
|
this._connected = true;
|
||||||
mediaManager.isConnected("" + this.userId);
|
mediaManager.isConnected("" + this.userId);
|
||||||
console.info(`connect => ${this.userId}`);
|
console.info(`connect => ${this.userId}`);
|
||||||
});
|
});
|
||||||
@ -88,6 +94,10 @@ export class VideoPeer extends Peer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.once('finish', () => {
|
||||||
|
this._onFinish();
|
||||||
|
});
|
||||||
|
|
||||||
this.pushVideoToRemoteUser();
|
this.pushVideoToRemoteUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +118,15 @@ export class VideoPeer extends Peer {
|
|||||||
mediaManager.disabledVideoByUserId(this.userId);
|
mediaManager.disabledVideoByUserId(this.userId);
|
||||||
mediaManager.disabledMicrophoneByUserId(this.userId);
|
mediaManager.disabledMicrophoneByUserId(this.userId);
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
mediaManager.addStreamRemoteVideo("" + this.userId, stream);
|
mediaManager.addStreamRemoteVideo("" + this.userId, stream);
|
||||||
|
}catch (err){
|
||||||
|
console.error(err);
|
||||||
|
//Force add streem video
|
||||||
|
setTimeout(() => {
|
||||||
|
this.stream(stream);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,16 +135,31 @@ export class VideoPeer extends Peer {
|
|||||||
*/
|
*/
|
||||||
public destroy(error?: Error): void {
|
public destroy(error?: Error): void {
|
||||||
try {
|
try {
|
||||||
|
this._connected = false
|
||||||
|
if(!this.toClose){
|
||||||
|
return;
|
||||||
|
}
|
||||||
mediaManager.removeActiveVideo("" + this.userId);
|
mediaManager.removeActiveVideo("" + this.userId);
|
||||||
// FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray"
|
// FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray"
|
||||||
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
|
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
|
||||||
//console.log('Closing connection with '+userId);
|
|
||||||
super.destroy(error);
|
super.destroy(error);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("VideoPeer::destroy", err)
|
console.error("VideoPeer::destroy", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onFinish () {
|
||||||
|
if (this.destroyed) return
|
||||||
|
const destroySoon = () => {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
if (this._connected) {
|
||||||
|
destroySoon();
|
||||||
|
} else {
|
||||||
|
this.once('connect', destroySoon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private pushVideoToRemoteUser() {
|
private pushVideoToRemoteUser() {
|
||||||
try {
|
try {
|
||||||
const localStream: MediaStream | null = mediaManager.localStream;
|
const localStream: MediaStream | null = mediaManager.localStream;
|
||||||
|
BIN
maps/characters/tenue-f-jolicode.png
Normal file
BIN
maps/characters/tenue-f-jolicode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
maps/characters/tenue-f-vanoix.png
Normal file
BIN
maps/characters/tenue-f-vanoix.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
maps/characters/tenue-f.png
Normal file
BIN
maps/characters/tenue-f.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
maps/characters/tenue-m-jolicode.png
Normal file
BIN
maps/characters/tenue-m-jolicode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
maps/characters/tenue-m-vanoix.png
Normal file
BIN
maps/characters/tenue-m-vanoix.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
maps/characters/tenue-m.png
Normal file
BIN
maps/characters/tenue-m.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -31,6 +31,11 @@ message SilentMessage {
|
|||||||
bool silent = 1;
|
bool silent = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message CharacterLayerMessage {
|
||||||
|
string url = 1;
|
||||||
|
string name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
/*********** CLIENT TO SERVER MESSAGES *************/
|
/*********** CLIENT TO SERVER MESSAGES *************/
|
||||||
|
|
||||||
message SetPlayerDetailsMessage {
|
message SetPlayerDetailsMessage {
|
||||||
@ -129,7 +134,7 @@ message GroupDeleteMessage {
|
|||||||
message UserJoinedMessage {
|
message UserJoinedMessage {
|
||||||
int32 userId = 1;
|
int32 userId = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
repeated string characterLayers = 3;
|
repeated CharacterLayerMessage characterLayers = 3;
|
||||||
PositionMessage position = 4;
|
PositionMessage position = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user