Merge pull request #355 from thecodingmachine/user-limit-grp
Create and send close message
This commit is contained in:
commit
f002170ed5
|
@ -162,11 +162,13 @@ export class IoSocketController {
|
||||||
|
|
||||||
let memberTags: string[] = [];
|
let memberTags: string[] = [];
|
||||||
let memberTextures: CharacterTexture[] = [];
|
let memberTextures: CharacterTexture[] = [];
|
||||||
|
|
||||||
const room = await socketManager.getOrCreateRoom(roomId);
|
const room = await socketManager.getOrCreateRoom(roomId);
|
||||||
if (room.isFull()) {
|
//TODO http return status
|
||||||
res.writeStatus("503").end('Too many users');
|
/*if (room.isFull) {
|
||||||
return;
|
throw new Error('Room is full');
|
||||||
}
|
}*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
const userData = await adminApi.fetchMemberDataByUuid(userUuid);
|
||||||
//console.log('USERDATA', userData)
|
//console.log('USERDATA', userData)
|
||||||
|
@ -234,30 +236,46 @@ export class IoSocketController {
|
||||||
},
|
},
|
||||||
/* Handlers */
|
/* Handlers */
|
||||||
open: (ws) => {
|
open: (ws) => {
|
||||||
// Let's join the room
|
(async () => {
|
||||||
const client = this.initClient(ws); //todo: into the upgrade instead?
|
// Let's join the room
|
||||||
socketManager.handleJoinRoom(client);
|
const client = this.initClient(ws); //todo: into the upgrade instead?
|
||||||
resetPing(client);
|
|
||||||
|
|
||||||
//get data information and shwo messages
|
const room = socketManager.getRoomById(client.roomId);
|
||||||
adminApi.fetchMemberDataByUuid(client.userUuid).then((res: FetchMemberDataByUuidResponse) => {
|
if (room && room.isFull) {
|
||||||
if (!res.messages) {
|
socketManager.emitCloseMessage(client, 302);
|
||||||
return;
|
}else {
|
||||||
|
socketManager.handleJoinRoom(client);
|
||||||
|
resetPing(client);
|
||||||
}
|
}
|
||||||
res.messages.forEach((c: unknown) => {
|
|
||||||
const messageToSend = c as { type: string, message: string };
|
//get data information and shwo messages
|
||||||
socketManager.emitSendUserMessage({
|
try {
|
||||||
userUuid: client.userUuid,
|
const res: FetchMemberDataByUuidResponse = await adminApi.fetchMemberDataByUuid(client.userUuid);
|
||||||
type: messageToSend.type,
|
if (!res.messages) {
|
||||||
message: messageToSend.message
|
return;
|
||||||
})
|
}
|
||||||
});
|
res.messages.forEach((c: unknown) => {
|
||||||
}).catch((err) => {
|
const messageToSend = c as { type: string, message: string };
|
||||||
console.error('fetchMemberDataByUuid => err', err);
|
socketManager.emitSendUserMessage({
|
||||||
});
|
userUuid: client.userUuid,
|
||||||
|
type: messageToSend.type,
|
||||||
|
message: messageToSend.message
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error('fetchMemberDataByUuid => err', err);
|
||||||
|
}
|
||||||
|
})();
|
||||||
},
|
},
|
||||||
message: (ws, arrayBuffer, isBinary): void => {
|
message: (ws, arrayBuffer, isBinary): void => {
|
||||||
|
|
||||||
const client = ws as ExSocketInterface;
|
const client = ws as ExSocketInterface;
|
||||||
|
|
||||||
|
const room = socketManager.getRoomById(client.roomId);
|
||||||
|
if (room && room.isFull) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const message = ClientToServerMessage.deserializeBinary(new Uint8Array(arrayBuffer));
|
const message = ClientToServerMessage.deserializeBinary(new Uint8Array(arrayBuffer));
|
||||||
|
|
||||||
if (message.hasViewportmessage()) {
|
if (message.hasViewportmessage()) {
|
||||||
|
@ -281,7 +299,6 @@ export class IoSocketController {
|
||||||
} else if (message.hasQueryjitsijwtmessage()){
|
} else if (message.hasQueryjitsijwtmessage()){
|
||||||
socketManager.handleQueryJitsiJwtMessage(client, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
socketManager.handleQueryJitsiJwtMessage(client, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ok is false if backpressure was built up, wait for drain */
|
/* Ok is false if backpressure was built up, wait for drain */
|
||||||
//let ok = ws.send(message, isBinary);
|
//let ok = ws.send(message, isBinary);
|
||||||
},
|
},
|
||||||
|
|
|
@ -85,7 +85,7 @@ export class MapController extends BaseController{
|
||||||
res.writeStatus('404').end('No room found');
|
res.writeStatus('404').end('No room found');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res.writeStatus("200").end(world.isFull() ? '1':'0');
|
res.writeStatus("200").end(world.isFull ? '1':'0');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
||||||
import {Movable} from "_Model/Movable";
|
import {Movable} from "_Model/Movable";
|
||||||
import {extractDataFromPrivateRoomId, extractRoomSlugPublicRoomId, isRoomAnonymous} from "./RoomIdentifier";
|
import {extractDataFromPrivateRoomId, extractRoomSlugPublicRoomId, isRoomAnonymous} from "./RoomIdentifier";
|
||||||
import {arrayIntersect} from "../Services/ArrayHelper";
|
import {arrayIntersect} from "../Services/ArrayHelper";
|
||||||
import {MAX_USERS_PER_ROOM} from "_Enum/EnvironmentVariable";
|
import {MAX_USERS_PER_ROOM} from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
export type ConnectCallback = (user: User, group: Group) => void;
|
export type ConnectCallback = (user: User, group: Group) => void;
|
||||||
export type DisconnectCallback = (user: User, group: Group) => void;
|
export type DisconnectCallback = (user: User, group: Group) => void;
|
||||||
|
@ -180,7 +180,7 @@ export class GameRoom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isFull() : boolean {
|
get isFull() : boolean {
|
||||||
return this.getUsers().size > MAX_USERS_PER_ROOM;
|
return this.getUsers().size > MAX_USERS_PER_ROOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,4 +117,8 @@ export class Group implements Movable {
|
||||||
this.leave(user);
|
this.leave(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get getSize(){
|
||||||
|
return this.users.size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,8 @@ import {
|
||||||
QueryJitsiJwtMessage,
|
QueryJitsiJwtMessage,
|
||||||
SendJitsiJwtMessage,
|
SendJitsiJwtMessage,
|
||||||
CharacterLayerMessage,
|
CharacterLayerMessage,
|
||||||
SendUserMessage
|
SendUserMessage,
|
||||||
|
CloseMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
import {PointInterface} from "../Model/Websocket/PointInterface";
|
||||||
import {User} from "../Model/User";
|
import {User} from "../Model/User";
|
||||||
|
@ -130,6 +131,7 @@ export class SocketManager {
|
||||||
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(player.position));
|
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(player.position));
|
||||||
|
|
||||||
roomJoinedMessage.addUser(userJoinedMessage);
|
roomJoinedMessage.addUser(userJoinedMessage);
|
||||||
|
roomJoinedMessage.setTagList(client.tags);
|
||||||
} else if (thing instanceof Group) {
|
} else if (thing instanceof Group) {
|
||||||
const groupUpdateMessage = new GroupUpdateMessage();
|
const groupUpdateMessage = new GroupUpdateMessage();
|
||||||
groupUpdateMessage.setGroupid(thing.getId());
|
groupUpdateMessage.setGroupid(thing.getId());
|
||||||
|
@ -406,6 +408,10 @@ export class SocketManager {
|
||||||
return Promise.resolve(world)
|
return Promise.resolve(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRoomById(roomId: string) {
|
||||||
|
return this.Worlds.get(roomId);
|
||||||
|
}
|
||||||
|
|
||||||
private joinRoom(client : ExSocketInterface, position: PointInterface): GameRoom {
|
private joinRoom(client : ExSocketInterface, position: PointInterface): GameRoom {
|
||||||
|
|
||||||
const roomId = client.roomId;
|
const roomId = client.roomId;
|
||||||
|
@ -493,6 +499,7 @@ export class SocketManager {
|
||||||
const groupUpdateMessage = new GroupUpdateMessage();
|
const groupUpdateMessage = new GroupUpdateMessage();
|
||||||
groupUpdateMessage.setGroupid(group.getId());
|
groupUpdateMessage.setGroupid(group.getId());
|
||||||
groupUpdateMessage.setPosition(pointMessage);
|
groupUpdateMessage.setPosition(pointMessage);
|
||||||
|
groupUpdateMessage.setGroupsize(group.getSize);
|
||||||
|
|
||||||
const subMessage = new SubMessage();
|
const subMessage = new SubMessage();
|
||||||
subMessage.setGroupupdatemessage(groupUpdateMessage);
|
subMessage.setGroupupdatemessage(groupUpdateMessage);
|
||||||
|
@ -692,6 +699,19 @@ export class SocketManager {
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public emitCloseMessage(socket: ExSocketInterface, status: number): ExSocketInterface {
|
||||||
|
const closeMessage = new CloseMessage();
|
||||||
|
closeMessage.setStatus(status);
|
||||||
|
|
||||||
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
|
serverToClientMessage.setClosemessage(closeMessage);
|
||||||
|
|
||||||
|
if (!socket.disconnecting) {
|
||||||
|
socket.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
|
}
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the characterLayers received from the front (as an array of string) with the custom textures from the back.
|
* Merges the characterLayers received from the front (as an array of string) with the custom textures from the back.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -81,10 +81,12 @@ class ConnectionManager {
|
||||||
await Axios.get(`${API_URL}/verify`, {params: {token}});
|
await Axios.get(`${API_URL}/verify`, {params: {token}});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async anonymousLogin(): Promise<void> {
|
public async anonymousLogin(isBenchmark: boolean = false): 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);
|
if (!isBenchmark) { // In benchmark, we don't have a local storage.
|
||||||
|
localUserStore.saveUser(this.localUser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public initBenchmark(): void {
|
public initBenchmark(): void {
|
||||||
|
@ -95,8 +97,7 @@ class ConnectionManager {
|
||||||
return new Promise<RoomConnection>((resolve, reject) => {
|
return new Promise<RoomConnection>((resolve, reject) => {
|
||||||
const connection = new RoomConnection(this.localUser.jwtToken, roomId, name, characterLayers, position, viewport);
|
const connection = new RoomConnection(this.localUser.jwtToken, roomId, name, characterLayers, position, viewport);
|
||||||
connection.onConnectError((error: object) => {
|
connection.onConnectError((error: object) => {
|
||||||
console.log(error);
|
if (error) { //todo: how to check error type?
|
||||||
if (false) { //todo: how to check error type?
|
|
||||||
reject(connexionErrorTypes.tooManyUsers);
|
reject(connexionErrorTypes.tooManyUsers);
|
||||||
} else {
|
} else {
|
||||||
reject(connexionErrorTypes.serverError);
|
reject(connexionErrorTypes.serverError);
|
||||||
|
|
|
@ -30,6 +30,8 @@ export enum EventMessage{
|
||||||
TELEPORT = "teleport",
|
TELEPORT = "teleport",
|
||||||
USER_MESSAGE = "user-message",
|
USER_MESSAGE = "user-message",
|
||||||
START_JITSI_ROOM = "start-jitsi-room",
|
START_JITSI_ROOM = "start-jitsi-room",
|
||||||
|
|
||||||
|
CLOSE_MESSAGE = "close-message",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PointInterface {
|
export interface PointInterface {
|
||||||
|
@ -73,7 +75,8 @@ export interface PositionInterface {
|
||||||
|
|
||||||
export interface GroupCreatedUpdatedMessageInterface {
|
export interface GroupCreatedUpdatedMessageInterface {
|
||||||
position: PositionInterface,
|
position: PositionInterface,
|
||||||
groupId: number
|
groupId: number,
|
||||||
|
groupSize: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebRtcStartMessageInterface {
|
export interface WebRtcStartMessageInterface {
|
||||||
|
|
|
@ -26,7 +26,8 @@ import {
|
||||||
QueryJitsiJwtMessage,
|
QueryJitsiJwtMessage,
|
||||||
SendJitsiJwtMessage,
|
SendJitsiJwtMessage,
|
||||||
CharacterLayerMessage,
|
CharacterLayerMessage,
|
||||||
SendUserMessage
|
SendUserMessage,
|
||||||
|
CloseMessage
|
||||||
} from "../Messages/generated/messages_pb"
|
} from "../Messages/generated/messages_pb"
|
||||||
|
|
||||||
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
||||||
|
@ -157,10 +158,11 @@ export class RoomConnection implements RoomConnection {
|
||||||
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
|
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
|
||||||
} else if (message.hasSendusermessage()) {
|
} else if (message.hasSendusermessage()) {
|
||||||
this.dispatch(EventMessage.USER_MESSAGE, message.getSendusermessage());
|
this.dispatch(EventMessage.USER_MESSAGE, message.getSendusermessage());
|
||||||
|
} else if (message.hasClosemessage()) {
|
||||||
|
this.dispatch(EventMessage.CLOSE_MESSAGE, message.getClosemessage());
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown message received');
|
throw new Error('Unknown message received');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +337,8 @@ export class RoomConnection implements RoomConnection {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
groupId: message.getGroupid(),
|
groupId: message.getGroupid(),
|
||||||
position: position.toObject()
|
position: position.toObject(),
|
||||||
|
groupSize: message.getGroupsize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,6 +543,12 @@ export class RoomConnection implements RoomConnection {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onCloseMessage(callback: (status: number) => void): void {
|
||||||
|
return this.onMessage(EventMessage.CLOSE_MESSAGE, (message: CloseMessage) => {
|
||||||
|
callback(message.getStatus());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public hasTag(tag: string): boolean {
|
public hasTag(tag: string): boolean {
|
||||||
return this.tags.includes(tag);
|
return this.tags.includes(tag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const DEBUG_MODE: boolean = process.env.DEBUG_MODE == "true";
|
const DEBUG_MODE: boolean = process.env.DEBUG_MODE == "true";
|
||||||
const API_URL = (typeof(window) !== 'undefined' ? window.location.protocol : 'http:') + '//' + (process.env.API_URL || "api.workadventure.localhost");
|
const API_URL = (process.env.API_PROTOCOL || (typeof(window) !== 'undefined' ? window.location.protocol : 'http:')) + '//' + (process.env.API_URL || "api.workadventure.localhost");
|
||||||
const TURN_SERVER: string = process.env.TURN_SERVER || "turn:numb.viagenie.ca";
|
const TURN_SERVER: string = process.env.TURN_SERVER || "turn:numb.viagenie.ca";
|
||||||
const TURN_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com';
|
const TURN_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com';
|
||||||
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$';
|
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$';
|
||||||
|
|
|
@ -56,6 +56,7 @@ import {ConsoleGlobalMessageManager} from "../../Administration/ConsoleGlobalMes
|
||||||
import {ResizableScene} from "../Login/ResizableScene";
|
import {ResizableScene} from "../Login/ResizableScene";
|
||||||
import {Room} from "../../Connexion/Room";
|
import {Room} from "../../Connexion/Room";
|
||||||
import {MessageUI} from "../../Logger/MessageUI";
|
import {MessageUI} from "../../Logger/MessageUI";
|
||||||
|
import {WaitScene} from "../Reconnecting/WaitScene";
|
||||||
|
|
||||||
|
|
||||||
export enum Textures {
|
export enum Textures {
|
||||||
|
@ -110,6 +111,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
startX!: number;
|
startX!: number;
|
||||||
startY!: number;
|
startY!: number;
|
||||||
circleTexture!: CanvasTexture;
|
circleTexture!: CanvasTexture;
|
||||||
|
circleRedTexture!: CanvasTexture;
|
||||||
pendingEvents: Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface> = new Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface>();
|
pendingEvents: Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface> = new Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface>();
|
||||||
private initPosition: PositionInterface|null = null;
|
private initPosition: PositionInterface|null = null;
|
||||||
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
||||||
|
@ -411,11 +413,18 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
this.initCamera();
|
this.initCamera();
|
||||||
|
|
||||||
// Let's generate the circle for the group delimiter
|
// Let's generate the circle for the group delimiter
|
||||||
const circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite');
|
let circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-white');
|
||||||
if (circleElement) {
|
if (circleElement) {
|
||||||
this.textures.remove('circleSprite');
|
this.textures.remove('circleSprite-white');
|
||||||
}
|
}
|
||||||
this.circleTexture = this.textures.createCanvas('circleSprite', 96, 96);
|
|
||||||
|
circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-red');
|
||||||
|
if (circleElement) {
|
||||||
|
this.textures.remove('circleSprite-red');
|
||||||
|
}
|
||||||
|
|
||||||
|
//create white circle canvas use to create sprite
|
||||||
|
this.circleTexture = this.textures.createCanvas('circleSprite-white', 96, 96);
|
||||||
const context = this.circleTexture.context;
|
const context = this.circleTexture.context;
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.arc(48, 48, 48, 0, 2 * Math.PI, false);
|
context.arc(48, 48, 48, 0, 2 * Math.PI, false);
|
||||||
|
@ -424,6 +433,16 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
context.stroke();
|
context.stroke();
|
||||||
this.circleTexture.refresh();
|
this.circleTexture.refresh();
|
||||||
|
|
||||||
|
//create red circle canvas use to create sprite
|
||||||
|
this.circleRedTexture = this.textures.createCanvas('circleSprite-red', 96, 96);
|
||||||
|
const contextRed = this.circleRedTexture.context;
|
||||||
|
contextRed.beginPath();
|
||||||
|
contextRed.arc(48, 48, 48, 0, 2 * Math.PI, false);
|
||||||
|
// context.lineWidth = 5;
|
||||||
|
contextRed.strokeStyle = '#ff0000';
|
||||||
|
contextRed.stroke();
|
||||||
|
this.circleRedTexture.refresh();
|
||||||
|
|
||||||
// Let's pause the scene if the connection is not established yet
|
// Let's pause the scene if the connection is not established yet
|
||||||
if (this.connection === undefined) {
|
if (this.connection === undefined) {
|
||||||
// Let's wait 0.5 seconds before printing the "connecting" screen to avoid blinking
|
// Let's wait 0.5 seconds before printing the "connecting" screen to avoid blinking
|
||||||
|
@ -600,6 +619,36 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
this.startJitsi(room, jwt);
|
this.startJitsi(room, jwt);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connection.onCloseMessage((status: number) => {
|
||||||
|
console.log(`close message status : ${status}`);
|
||||||
|
|
||||||
|
//TODO show wait room
|
||||||
|
this.connection.closeConnection();
|
||||||
|
this.simplePeer.unregister();
|
||||||
|
connection.closeConnection();
|
||||||
|
|
||||||
|
const waitGameSceneKey = 'somekey' + Math.round(Math.random() * 10000);
|
||||||
|
//show wait scene
|
||||||
|
setTimeout(() => {
|
||||||
|
const game: Phaser.Scene = new WaitScene(waitGameSceneKey, status);
|
||||||
|
this.scene.add(waitGameSceneKey, game, true, {
|
||||||
|
initPosition: {
|
||||||
|
x: this.CurrentPlayer.x,
|
||||||
|
y: this.CurrentPlayer.y
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.scene.stop(this.scene.key);
|
||||||
|
this.scene.start(waitGameSceneKey);
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
//trying to reload map
|
||||||
|
setTimeout(() => {
|
||||||
|
this.scene.stop(waitGameSceneKey);
|
||||||
|
this.scene.remove(waitGameSceneKey);
|
||||||
|
this.scene.start(this.scene.key);
|
||||||
|
}, 30000);
|
||||||
|
});
|
||||||
|
|
||||||
// When connection is performed, let's connect SimplePeer
|
// When connection is performed, let's connect SimplePeer
|
||||||
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic);
|
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic);
|
||||||
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
||||||
|
@ -1135,18 +1184,28 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
|
|
||||||
private doShareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) {
|
private doShareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) {
|
||||||
const groupId = groupPositionMessage.groupId;
|
const groupId = groupPositionMessage.groupId;
|
||||||
|
const groupSize = groupPositionMessage.groupSize;
|
||||||
|
|
||||||
const group = this.groups.get(groupId);
|
const group = this.groups.get(groupId);
|
||||||
if (group !== undefined) {
|
if (group !== undefined) {
|
||||||
group.setPosition(Math.round(groupPositionMessage.position.x), Math.round(groupPositionMessage.position.y));
|
group.setPosition(Math.round(groupPositionMessage.position.x), Math.round(groupPositionMessage.position.y));
|
||||||
} else {
|
} else {
|
||||||
// TODO: circle radius should not be hard stored
|
// TODO: circle radius should not be hard stored
|
||||||
|
const positionX = 48;
|
||||||
|
const positionY = 48;
|
||||||
|
|
||||||
|
console.log('doShareGroupPosition', groupSize);
|
||||||
|
let texture = 'circleSprite-red';
|
||||||
|
if(groupSize < 4){
|
||||||
|
texture = 'circleSprite-white';
|
||||||
|
}
|
||||||
const sprite = new Sprite(
|
const sprite = new Sprite(
|
||||||
this,
|
this,
|
||||||
Math.round(groupPositionMessage.position.x),
|
Math.round(groupPositionMessage.position.x),
|
||||||
Math.round(groupPositionMessage.position.y),
|
Math.round(groupPositionMessage.position.y),
|
||||||
'circleSprite');
|
texture
|
||||||
sprite.setDisplayOrigin(48, 48);
|
);
|
||||||
|
sprite.setDisplayOrigin(positionX, positionY);
|
||||||
this.add.existing(sprite);
|
this.add.existing(sprite);
|
||||||
this.groups.set(groupId, sprite);
|
this.groups.set(groupId, sprite);
|
||||||
}
|
}
|
||||||
|
@ -1278,6 +1337,10 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
|
|
||||||
private loadSpritesheet(name: string, url: string): Promise<void> {
|
private loadSpritesheet(name: string, url: string): Promise<void> {
|
||||||
return new Promise<void>(((resolve, reject) => {
|
return new Promise<void>(((resolve, reject) => {
|
||||||
|
if (this.textures.exists(name)) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.load.spritesheet(
|
this.load.spritesheet(
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
|
|
70
front/src/Phaser/Reconnecting/WaitScene.ts
Normal file
70
front/src/Phaser/Reconnecting/WaitScene.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import {TextField} from "../Components/TextField";
|
||||||
|
import Image = Phaser.GameObjects.Image;
|
||||||
|
|
||||||
|
enum ReconnectingTextures {
|
||||||
|
icon = "icon",
|
||||||
|
mainFont = "main_font"
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WaitScene extends Phaser.Scene {
|
||||||
|
private reconnectingField!: TextField;
|
||||||
|
private logo!: Image;
|
||||||
|
private text: string = '';
|
||||||
|
|
||||||
|
constructor(key: string, private readonly status: number) {
|
||||||
|
super({
|
||||||
|
key: key
|
||||||
|
});
|
||||||
|
this.initialiseText();
|
||||||
|
}
|
||||||
|
|
||||||
|
initialiseText() {
|
||||||
|
this.text = `${this.status}` + '\n' + '\n';
|
||||||
|
switch (this.status) {
|
||||||
|
case 302:
|
||||||
|
this.text += 'Aie ! Work Adventure est victime de son succes, ' +
|
||||||
|
'\n' +
|
||||||
|
'\n' +
|
||||||
|
'le nombre maximum de joueurs a ete atteint !' +
|
||||||
|
'\n' +
|
||||||
|
'\n' +
|
||||||
|
`Reconnexion dans 30 secondes ...`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
this.load.image(ReconnectingTextures.icon, "resources/logos/tcm_full.png");
|
||||||
|
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
|
||||||
|
this.load.bitmapFont(ReconnectingTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
|
||||||
|
this.load.spritesheet(
|
||||||
|
'cat',
|
||||||
|
'resources/characters/pipoya/Cat 01-1.png',
|
||||||
|
{frameWidth: 32, frameHeight: 32}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, ReconnectingTextures.icon);
|
||||||
|
this.add.existing(this.logo);
|
||||||
|
|
||||||
|
this.reconnectingField = new TextField(
|
||||||
|
this,
|
||||||
|
this.game.renderer.width / 2,
|
||||||
|
this.game.renderer.height / 2,
|
||||||
|
this.text);
|
||||||
|
|
||||||
|
const cat = this.physics.add.sprite(
|
||||||
|
this.game.renderer.width / 2,
|
||||||
|
this.game.renderer.height / 2 - 70,
|
||||||
|
'cat');
|
||||||
|
|
||||||
|
this.anims.create({
|
||||||
|
key: 'right',
|
||||||
|
frames: this.anims.generateFrameNumbers('cat', {start: 6, end: 8}),
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
cat.play('right');
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,8 @@ export class ScreenSharingPeer extends Peer {
|
||||||
* Whether this connection is currently receiving a video stream from a remote user.
|
* Whether this connection is currently receiving a video stream from a remote user.
|
||||||
*/
|
*/
|
||||||
private isReceivingStream:boolean = false;
|
private isReceivingStream:boolean = false;
|
||||||
|
public toClose: boolean = false;
|
||||||
|
public _connected: boolean = false;
|
||||||
|
|
||||||
constructor(private userId: number, initiator: boolean, private connection: RoomConnection) {
|
constructor(private userId: number, initiator: boolean, private connection: RoomConnection) {
|
||||||
super({
|
super({
|
||||||
|
@ -42,6 +44,8 @@ export class ScreenSharingPeer extends Peer {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('close', () => {
|
this.on('close', () => {
|
||||||
|
this._connected = false;
|
||||||
|
this.toClose = true;
|
||||||
this.destroy();
|
this.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -62,11 +66,16 @@ export class ScreenSharingPeer extends Peer {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('connect', () => {
|
this.on('connect', () => {
|
||||||
|
this._connected = true;
|
||||||
// FIXME: we need to put the loader on the screen sharing connection
|
// FIXME: we need to put the loader on the screen sharing connection
|
||||||
mediaManager.isConnected("" + this.userId);
|
mediaManager.isConnected("" + this.userId);
|
||||||
console.info(`connect => ${this.userId}`);
|
console.info(`connect => ${this.userId}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.once('finish', () => {
|
||||||
|
this._onFinish();
|
||||||
|
});
|
||||||
|
|
||||||
this.pushScreenSharingToRemoteUser();
|
this.pushScreenSharingToRemoteUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +109,10 @@ export class ScreenSharingPeer extends Peer {
|
||||||
|
|
||||||
public destroy(error?: Error): void {
|
public destroy(error?: Error): void {
|
||||||
try {
|
try {
|
||||||
|
this._connected = false
|
||||||
|
if(!this.toClose){
|
||||||
|
return;
|
||||||
|
}
|
||||||
mediaManager.removeActiveScreenSharingVideo("" + this.userId);
|
mediaManager.removeActiveScreenSharingVideo("" + 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.
|
||||||
|
@ -111,6 +124,18 @@ export class ScreenSharingPeer extends Peer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onFinish () {
|
||||||
|
if (this.destroyed) return
|
||||||
|
const destroySoon = () => {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
if (this._connected) {
|
||||||
|
destroySoon();
|
||||||
|
} else {
|
||||||
|
this.once('connect', destroySoon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private pushScreenSharingToRemoteUser() {
|
private pushScreenSharingToRemoteUser() {
|
||||||
const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture;
|
const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture;
|
||||||
if(!localScreenCapture){
|
if(!localScreenCapture){
|
||||||
|
|
|
@ -108,44 +108,30 @@ export class SimplePeer {
|
||||||
this.createPeerConnection(user);
|
this.createPeerConnection(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* server has two people connected, start the meet
|
|
||||||
*/
|
|
||||||
private startWebRtc() {
|
|
||||||
console.warn('startWebRtc startWebRtc');
|
|
||||||
this.Users.forEach((user: UserSimplePeerInterface) => {
|
|
||||||
//if it's not an initiator, peer connection will be created when gamer will receive offer signal
|
|
||||||
if(!user.initiator){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.createPeerConnection(user);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create peer connection to bind users
|
* create peer connection to bind users
|
||||||
*/
|
*/
|
||||||
private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null{
|
private createPeerConnection(user : UserSimplePeerInterface) : VideoPeer | null {
|
||||||
const peerConnection = this.PeerConnectionArray.get(user.userId)
|
const peerConnection = this.PeerConnectionArray.get(user.userId)
|
||||||
if(peerConnection){
|
if (peerConnection) {
|
||||||
if(peerConnection.destroyed){
|
if (peerConnection.destroyed) {
|
||||||
peerConnection.toClose = true;
|
peerConnection.toClose = true;
|
||||||
peerConnection.destroy();
|
peerConnection.destroy();
|
||||||
const peerConnexionDeleted = this.PeerConnectionArray.delete(user.userId);
|
const peerConnexionDeleted = this.PeerConnectionArray.delete(user.userId);
|
||||||
if(!peerConnexionDeleted){
|
if (!peerConnexionDeleted) {
|
||||||
throw 'Error to delete peer connection';
|
throw 'Error to delete peer connection';
|
||||||
}
|
}
|
||||||
this.createPeerConnection(user);
|
this.createPeerConnection(user);
|
||||||
}else {
|
} else {
|
||||||
peerConnection.toClose = false;
|
peerConnection.toClose = false;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = user.name;
|
let name = user.name;
|
||||||
if(!name){
|
if (!name) {
|
||||||
const userSearch = this.Users.find((userSearch: UserSimplePeerInterface) => userSearch.userId === user.userId);
|
const userSearch = this.Users.find((userSearch: UserSimplePeerInterface) => userSearch.userId === user.userId);
|
||||||
if(userSearch) {
|
if (userSearch) {
|
||||||
name = userSearch.name;
|
name = userSearch.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,8 +139,8 @@ export class SimplePeer {
|
||||||
mediaManager.removeActiveVideo("" + user.userId);
|
mediaManager.removeActiveVideo("" + user.userId);
|
||||||
|
|
||||||
const reportCallback = this.enableReporting ? (comment: string) => {
|
const reportCallback = this.enableReporting ? (comment: string) => {
|
||||||
this.reportUser(user.userId, comment);
|
this.reportUser(user.userId, comment);
|
||||||
}: undefined;
|
} : undefined;
|
||||||
|
|
||||||
mediaManager.addActiveVideo("" + user.userId, reportCallback, name);
|
mediaManager.addActiveVideo("" + user.userId, reportCallback, name);
|
||||||
|
|
||||||
|
@ -179,9 +165,19 @@ export class SimplePeer {
|
||||||
* create peer connection to bind users
|
* create peer connection to bind users
|
||||||
*/
|
*/
|
||||||
private createPeerScreenSharingConnection(user : UserSimplePeerInterface) : ScreenSharingPeer | null{
|
private createPeerScreenSharingConnection(user : UserSimplePeerInterface) : ScreenSharingPeer | null{
|
||||||
if(
|
const peerConnection = this.PeerScreenSharingConnectionArray.get(user.userId);
|
||||||
this.PeerScreenSharingConnectionArray.has(user.userId)
|
if(peerConnection){
|
||||||
){
|
if(peerConnection.destroyed){
|
||||||
|
peerConnection.toClose = true;
|
||||||
|
peerConnection.destroy();
|
||||||
|
const peerConnexionDeleted = this.PeerScreenSharingConnectionArray.delete(user.userId);
|
||||||
|
if(!peerConnexionDeleted){
|
||||||
|
throw 'Error to delete peer connection';
|
||||||
|
}
|
||||||
|
this.createPeerConnection(user);
|
||||||
|
}else {
|
||||||
|
peerConnection.toClose = false;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,13 +39,13 @@ export class VideoPeer extends Peer {
|
||||||
urls: 'stun:stun.l.google.com:19302'
|
urls: 'stun:stun.l.google.com:19302'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
urls: TURN_SERVER,
|
urls: TURN_SERVER.split(','),
|
||||||
username: TURN_USER,
|
username: TURN_USER,
|
||||||
credential: TURN_PASSWORD
|
credential: TURN_PASSWORD
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
//start listen signal for the peer connection
|
//start listen signal for the peer connection
|
||||||
this.on('signal', (data: unknown) => {
|
this.on('signal', (data: unknown) => {
|
||||||
|
|
|
@ -125,6 +125,7 @@ message BatchMessage {
|
||||||
message GroupUpdateMessage {
|
message GroupUpdateMessage {
|
||||||
int32 groupId = 1;
|
int32 groupId = 1;
|
||||||
PointMessage position = 2;
|
PointMessage position = 2;
|
||||||
|
int32 groupSize = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GroupDeleteMessage {
|
message GroupDeleteMessage {
|
||||||
|
@ -188,6 +189,10 @@ message SendUserMessage{
|
||||||
string message = 2;
|
string message = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message CloseMessage{
|
||||||
|
int32 status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message ServerToClientMessage {
|
message ServerToClientMessage {
|
||||||
oneof message {
|
oneof message {
|
||||||
BatchMessage batchMessage = 1;
|
BatchMessage batchMessage = 1;
|
||||||
|
@ -202,5 +207,6 @@ message ServerToClientMessage {
|
||||||
TeleportMessageMessage teleportMessageMessage = 10;
|
TeleportMessageMessage teleportMessageMessage = 10;
|
||||||
SendJitsiJwtMessage sendJitsiJwtMessage = 11;
|
SendJitsiJwtMessage sendJitsiJwtMessage = 11;
|
||||||
SendUserMessage sendUserMessage = 12;
|
SendUserMessage sendUserMessage = 12;
|
||||||
|
CloseMessage closeMessage = 13;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue