Merge branch 'develop' of github.com:thecodingmachine/workadventure into layoutManagerSvelte
This commit is contained in:
commit
2d8098b06d
42 changed files with 987 additions and 8874 deletions
|
@ -1,12 +1,13 @@
|
||||||
## Version develop
|
## Version develop
|
||||||
|
|
||||||
### Updates
|
### Updates
|
||||||
|
- New scripting API features :
|
||||||
|
- Use `WA.room.loadTileset(url: string) : Promise<number>` to load a tileset from a JSON file.
|
||||||
- Rewrote the way authentification works: the auth jwt token can now contains an email instead of an uuid
|
- Rewrote the way authentification works: the auth jwt token can now contains an email instead of an uuid
|
||||||
- Added an OpenId login flow than can be plugged to any OIDC provider.
|
- Added an OpenId login flow than can be plugged to any OIDC provider.
|
||||||
-
|
- You can send a message to all rooms of your world from the console global message (user with tag admin only).
|
||||||
|
|
||||||
## Version 1.4.10
|
## Version 1.4.11
|
||||||
|
|
||||||
### Updates
|
### Updates
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,7 @@ const roomManager: IRoomManagerServer = {
|
||||||
sendAdminMessageToRoom(call: ServerUnaryCall<AdminRoomMessage>, callback: sendUnaryData<EmptyMessage>): void {
|
sendAdminMessageToRoom(call: ServerUnaryCall<AdminRoomMessage>, callback: sendUnaryData<EmptyMessage>): void {
|
||||||
// FIXME: we could improve return message by returning a Success|ErrorMessage message
|
// FIXME: we could improve return message by returning a Success|ErrorMessage message
|
||||||
socketManager
|
socketManager
|
||||||
.sendAdminRoomMessage(call.request.getRoomid(), call.request.getMessage())
|
.sendAdminRoomMessage(call.request.getRoomid(), call.request.getMessage(), call.request.getType())
|
||||||
.catch((e) => console.error(e));
|
.catch((e) => console.error(e));
|
||||||
callback(null, new EmptyMessage());
|
callback(null, new EmptyMessage());
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,7 +27,9 @@ class MapFetcher {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isTiledMap(res.data)) {
|
if (!isTiledMap(res.data)) {
|
||||||
throw new Error("Invalid map format for map " + mapUrl);
|
//TODO fixme
|
||||||
|
//throw new Error("Invalid map format for map " + mapUrl);
|
||||||
|
console.error("Invalid map format for map " + mapUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
|
|
|
@ -761,7 +761,7 @@ export class SocketManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendAdminRoomMessage(roomId: string, message: string) {
|
async sendAdminRoomMessage(roomId: string, message: string, type: string) {
|
||||||
const room = await this.roomsPromises.get(roomId);
|
const room = await this.roomsPromises.get(roomId);
|
||||||
if (!room) {
|
if (!room) {
|
||||||
//todo: this should cause the http call to return a 500
|
//todo: this should cause the http call to return a 500
|
||||||
|
@ -776,7 +776,7 @@ export class SocketManager {
|
||||||
room.getUsers().forEach((recipient) => {
|
room.getUsers().forEach((recipient) => {
|
||||||
const sendUserMessage = new SendUserMessage();
|
const sendUserMessage = new SendUserMessage();
|
||||||
sendUserMessage.setMessage(message);
|
sendUserMessage.setMessage(message);
|
||||||
sendUserMessage.setType("message");
|
sendUserMessage.setType(type);
|
||||||
|
|
||||||
const clientMessage = new ServerToClientMessage();
|
const clientMessage = new ServerToClientMessage();
|
||||||
clientMessage.setSendusermessage(sendUserMessage);
|
clientMessage.setSendusermessage(sendUserMessage);
|
||||||
|
|
|
@ -1,58 +1,62 @@
|
||||||
import "jasmine";
|
import "jasmine";
|
||||||
import {ConnectCallback, DisconnectCallback, GameRoom} from "../src/Model/GameRoom";
|
import { ConnectCallback, DisconnectCallback, GameRoom } from "../src/Model/GameRoom";
|
||||||
import {Point} from "../src/Model/Websocket/MessageUserPosition";
|
import { Point } from "../src/Model/Websocket/MessageUserPosition";
|
||||||
import {Group} from "../src/Model/Group";
|
import { Group } from "../src/Model/Group";
|
||||||
import {User, UserSocket} from "_Model/User";
|
import { User, UserSocket } from "_Model/User";
|
||||||
import {JoinRoomMessage, PositionMessage} from "../src/Messages/generated/messages_pb";
|
import { JoinRoomMessage, PositionMessage } from "../src/Messages/generated/messages_pb";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {EmoteCallback} from "_Model/Zone";
|
import { EmoteCallback } from "_Model/Zone";
|
||||||
|
|
||||||
function createMockUser(userId: number): User {
|
function createMockUser(userId: number): User {
|
||||||
return {
|
return {
|
||||||
userId
|
userId,
|
||||||
} as unknown as User;
|
} as unknown as User;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMockUserSocket(): UserSocket {
|
function createMockUserSocket(): UserSocket {
|
||||||
return {
|
return {} as unknown as UserSocket;
|
||||||
} as unknown as UserSocket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createJoinRoomMessage(uuid: string, x: number, y: number): JoinRoomMessage
|
function createJoinRoomMessage(uuid: string, x: number, y: number): JoinRoomMessage {
|
||||||
{
|
|
||||||
const positionMessage = new PositionMessage();
|
const positionMessage = new PositionMessage();
|
||||||
positionMessage.setX(x);
|
positionMessage.setX(x);
|
||||||
positionMessage.setY(y);
|
positionMessage.setY(y);
|
||||||
positionMessage.setDirection(Direction.DOWN);
|
positionMessage.setDirection(Direction.DOWN);
|
||||||
positionMessage.setMoving(false);
|
positionMessage.setMoving(false);
|
||||||
const joinRoomMessage = new JoinRoomMessage();
|
const joinRoomMessage = new JoinRoomMessage();
|
||||||
joinRoomMessage.setUseruuid('1');
|
joinRoomMessage.setUseruuid("1");
|
||||||
joinRoomMessage.setIpaddress('10.0.0.2');
|
joinRoomMessage.setIpaddress("10.0.0.2");
|
||||||
joinRoomMessage.setName('foo');
|
joinRoomMessage.setName("foo");
|
||||||
joinRoomMessage.setRoomid('_/global/test.json');
|
joinRoomMessage.setRoomid("_/global/test.json");
|
||||||
joinRoomMessage.setPositionmessage(positionMessage);
|
joinRoomMessage.setPositionmessage(positionMessage);
|
||||||
return joinRoomMessage;
|
return joinRoomMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emote: EmoteCallback = (emoteEventMessage, listener): void => {}
|
const emote: EmoteCallback = (emoteEventMessage, listener): void => {};
|
||||||
|
|
||||||
describe("GameRoom", () => {
|
describe("GameRoom", () => {
|
||||||
it("should connect user1 and user2", async () => {
|
it("should connect user1 and user2", async () => {
|
||||||
let connectCalledNumber: number = 0;
|
let connectCalledNumber: number = 0;
|
||||||
const connect: ConnectCallback = (user: User, group: Group): void => {
|
const connect: ConnectCallback = (user: User, group: Group): void => {
|
||||||
connectCalledNumber++;
|
connectCalledNumber++;
|
||||||
}
|
};
|
||||||
const disconnect: DisconnectCallback = (user: User, group: Group): void => {
|
const disconnect: DisconnectCallback = (user: User, group: Group): void => {};
|
||||||
|
|
||||||
}
|
const world = await GameRoom.create(
|
||||||
|
"https://play.workadventu.re/_/global/localhost/test.json",
|
||||||
|
connect,
|
||||||
|
disconnect,
|
||||||
|
160,
|
||||||
|
160,
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
|
emote
|
||||||
|
);
|
||||||
|
|
||||||
|
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
||||||
|
|
||||||
const world = await GameRoom.create('https://play.workadventu.re/_/global/localhost/test.json', connect, disconnect, 160, 160, () => {}, () => {}, () => {}, emote);
|
const user2 = world.join(createMockUserSocket(), createJoinRoomMessage("2", 500, 100));
|
||||||
|
|
||||||
|
|
||||||
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage('1', 100, 100));
|
|
||||||
|
|
||||||
const user2 = world.join(createMockUserSocket(), createJoinRoomMessage('2', 500, 100));
|
|
||||||
|
|
||||||
world.updatePosition(user2, new Point(261, 100));
|
world.updatePosition(user2, new Point(261, 100));
|
||||||
|
|
||||||
|
@ -70,22 +74,30 @@ describe("GameRoom", () => {
|
||||||
let connectCalled: boolean = false;
|
let connectCalled: boolean = false;
|
||||||
const connect: ConnectCallback = (user: User, group: Group): void => {
|
const connect: ConnectCallback = (user: User, group: Group): void => {
|
||||||
connectCalled = true;
|
connectCalled = true;
|
||||||
}
|
};
|
||||||
const disconnect: DisconnectCallback = (user: User, group: Group): void => {
|
const disconnect: DisconnectCallback = (user: User, group: Group): void => {};
|
||||||
|
|
||||||
}
|
const world = await GameRoom.create(
|
||||||
|
"https://play.workadventu.re/_/global/localhost/test.json",
|
||||||
|
connect,
|
||||||
|
disconnect,
|
||||||
|
160,
|
||||||
|
160,
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
|
emote
|
||||||
|
);
|
||||||
|
|
||||||
const world = await GameRoom.create('https://play.workadventu.re/_/global/localhost/test.json', connect, disconnect, 160, 160, () => {}, () => {}, () => {}, emote);
|
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
||||||
|
|
||||||
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage('1', 100, 100));
|
const user2 = world.join(createMockUserSocket(), createJoinRoomMessage("2", 200, 100));
|
||||||
|
|
||||||
const user2 = world.join(createMockUserSocket(), createJoinRoomMessage('2', 200, 100));
|
|
||||||
|
|
||||||
expect(connectCalled).toBe(true);
|
expect(connectCalled).toBe(true);
|
||||||
connectCalled = false;
|
connectCalled = false;
|
||||||
|
|
||||||
// baz joins at the outer limit of the group
|
// baz joins at the outer limit of the group
|
||||||
const user3 = world.join(createMockUserSocket(), createJoinRoomMessage('2', 311, 100));
|
const user3 = world.join(createMockUserSocket(), createJoinRoomMessage("2", 311, 100));
|
||||||
|
|
||||||
expect(connectCalled).toBe(false);
|
expect(connectCalled).toBe(false);
|
||||||
|
|
||||||
|
@ -99,26 +111,35 @@ describe("GameRoom", () => {
|
||||||
let disconnectCallNumber: number = 0;
|
let disconnectCallNumber: number = 0;
|
||||||
const connect: ConnectCallback = (user: User, group: Group): void => {
|
const connect: ConnectCallback = (user: User, group: Group): void => {
|
||||||
connectCalled = true;
|
connectCalled = true;
|
||||||
}
|
};
|
||||||
const disconnect: DisconnectCallback = (user: User, group: Group): void => {
|
const disconnect: DisconnectCallback = (user: User, group: Group): void => {
|
||||||
disconnectCallNumber++;
|
disconnectCallNumber++;
|
||||||
}
|
};
|
||||||
|
|
||||||
const world = await GameRoom.create('https://play.workadventu.re/_/global/localhost/test.json', connect, disconnect, 160, 160, () => {}, () => {}, () => {}, emote);
|
const world = await GameRoom.create(
|
||||||
|
"https://play.workadventu.re/_/global/localhost/test.json",
|
||||||
|
connect,
|
||||||
|
disconnect,
|
||||||
|
160,
|
||||||
|
160,
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
|
() => {},
|
||||||
|
emote
|
||||||
|
);
|
||||||
|
|
||||||
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage('1', 100, 100));
|
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
||||||
|
|
||||||
const user2 = world.join(createMockUserSocket(), createJoinRoomMessage('2', 259, 100));
|
const user2 = world.join(createMockUserSocket(), createJoinRoomMessage("2", 259, 100));
|
||||||
|
|
||||||
expect(connectCalled).toBe(true);
|
expect(connectCalled).toBe(true);
|
||||||
expect(disconnectCallNumber).toBe(0);
|
expect(disconnectCallNumber).toBe(0);
|
||||||
|
|
||||||
world.updatePosition(user2, new Point(100+160+160+1, 100));
|
world.updatePosition(user2, new Point(100 + 160 + 160 + 1, 100));
|
||||||
|
|
||||||
expect(disconnectCallNumber).toBe(2);
|
expect(disconnectCallNumber).toBe(2);
|
||||||
|
|
||||||
world.updatePosition(user2, new Point(262, 100));
|
world.updatePosition(user2, new Point(262, 100));
|
||||||
expect(disconnectCallNumber).toBe(2);
|
expect(disconnectCallNumber).toBe(2);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
})
|
|
||||||
|
|
|
@ -163,3 +163,17 @@ WA.room.setTiles([
|
||||||
{x: 9, y: 4, tile: 'blue', layer: 'setTiles'}
|
{x: 9, y: 4, tile: 'blue', layer: 'setTiles'}
|
||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Loading a tileset
|
||||||
|
```
|
||||||
|
WA.room.loadTileset(url: string): Promise<number>
|
||||||
|
```
|
||||||
|
Load a tileset in JSON format from an url and return the id of the first tile of the loaded tileset.
|
||||||
|
|
||||||
|
You can create a tileset file in Tile Editor.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.room.loadTileset("Assets/Tileset.json").then((firstId) => {
|
||||||
|
WA.room.setTiles([{x: 4, y: 4, tile: firstId, layer: 'bottom'}]);
|
||||||
|
})
|
||||||
|
```
|
1
front/dist/resources/html/gameMenu.html
vendored
1
front/dist/resources/html/gameMenu.html
vendored
|
@ -60,6 +60,7 @@
|
||||||
<section>
|
<section>
|
||||||
<button id="enableNotification">Enable notifications</button>
|
<button id="enableNotification">Enable notifications</button>
|
||||||
</section>
|
</section>
|
||||||
|
<!-- TODO activate authentication -->
|
||||||
<section hidden>
|
<section hidden>
|
||||||
<button id="oidcLogin">Oauth Login</button>
|
<button id="oidcLogin">Oauth Login</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
8393
front/package-lock.json
generated
8393
front/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -51,6 +51,7 @@
|
||||||
"phaser3-rex-plugins": "^1.1.42",
|
"phaser3-rex-plugins": "^1.1.42",
|
||||||
"queue-typescript": "^1.0.1",
|
"queue-typescript": "^1.0.1",
|
||||||
"quill": "1.3.6",
|
"quill": "1.3.6",
|
||||||
|
"quill-delta-to-html": "^0.12.0",
|
||||||
"rxjs": "^6.6.3",
|
"rxjs": "^6.6.3",
|
||||||
"simple-peer": "^9.11.0",
|
"simple-peer": "^9.11.0",
|
||||||
"socket.io-client": "^2.3.0",
|
"socket.io-client": "^2.3.0",
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
import {HtmlUtils} from "./../WebRtc/HtmlUtils";
|
|
||||||
import {PUSHER_URL, UPLOADER_URL} from "../Enum/EnvironmentVariable";
|
|
||||||
import type {RoomConnection} from "../Connexion/RoomConnection";
|
|
||||||
import type {PlayGlobalMessageInterface} from "../Connexion/ConnexionModels";
|
|
||||||
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
|
||||||
import {soundManager} from "../Phaser/Game/SoundManager";
|
|
||||||
import {AdminMessageEventTypes} from "../Connexion/AdminMessagesService";
|
|
||||||
|
|
||||||
export class GlobalMessageManager {
|
|
||||||
|
|
||||||
constructor(private Connection: RoomConnection) {
|
|
||||||
this.initialise();
|
|
||||||
}
|
|
||||||
|
|
||||||
initialise(){
|
|
||||||
//receive signal to show message
|
|
||||||
this.Connection.receivePlayGlobalMessage((message: PlayGlobalMessageInterface) => {
|
|
||||||
this.playMessage(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
//receive signal to close message
|
|
||||||
this.Connection.receiveStopGlobalMessage((messageId: string) => {
|
|
||||||
this.stopMessage(messageId);
|
|
||||||
});
|
|
||||||
|
|
||||||
//receive signal to close message
|
|
||||||
this.Connection.receiveTeleportMessage((map: string) => {
|
|
||||||
console.log('map to teleport user', map);
|
|
||||||
//TODO teleport user on map
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private playMessage(message : PlayGlobalMessageInterface){
|
|
||||||
const previousMessage = document.getElementById(this.getHtmlMessageId(message.id));
|
|
||||||
if(previousMessage){
|
|
||||||
previousMessage.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(AdminMessageEventTypes.audio === message.type){
|
|
||||||
this.playAudioMessage(message.id, message.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(AdminMessageEventTypes.admin === message.type){
|
|
||||||
this.playTextMessage(message.id, message.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private playAudioMessage(messageId : string, urlMessage: string) {
|
|
||||||
soundPlayingStore.playSound(UPLOADER_URL + urlMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private playTextMessage(messageId : string, htmlMessage: string){
|
|
||||||
//add button to clear message
|
|
||||||
const buttonText = document.createElement('p');
|
|
||||||
buttonText.id = 'button-clear-message';
|
|
||||||
buttonText.innerText = 'Clear';
|
|
||||||
|
|
||||||
const buttonMainConsole = document.createElement('div');
|
|
||||||
buttonMainConsole.classList.add('clear');
|
|
||||||
buttonMainConsole.appendChild(buttonText);
|
|
||||||
buttonMainConsole.addEventListener('click', () => {
|
|
||||||
messageContainer.style.top = '-80%';
|
|
||||||
setTimeout(() => {
|
|
||||||
messageContainer.remove();
|
|
||||||
buttonMainConsole.remove();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
//create content message
|
|
||||||
const messageCotent = document.createElement('div');
|
|
||||||
messageCotent.innerHTML = htmlMessage;
|
|
||||||
messageCotent.className = "content-message";
|
|
||||||
|
|
||||||
//add message container
|
|
||||||
const messageContainer = document.createElement('div');
|
|
||||||
messageContainer.id = this.getHtmlMessageId(messageId);
|
|
||||||
messageContainer.className = "message-container";
|
|
||||||
messageContainer.appendChild(messageCotent);
|
|
||||||
messageContainer.appendChild(buttonMainConsole);
|
|
||||||
|
|
||||||
const mainSectionDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('main-container');
|
|
||||||
mainSectionDiv.appendChild(messageContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private stopMessage(messageId: string){
|
|
||||||
HtmlUtils.removeElementByIdOrFail<HTMLDivElement>(this.getHtmlMessageId(messageId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private getHtmlMessageId(messageId: string) : string{
|
|
||||||
return `message-${messageId}`;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
import type {TypeMessageInterface} from "./UserMessageManager";
|
|
||||||
import {HtmlUtils} from "../WebRtc/HtmlUtils";
|
|
||||||
|
|
||||||
let modalTimeOut : NodeJS.Timeout;
|
|
||||||
|
|
||||||
export class TypeMessageExt implements TypeMessageInterface{
|
|
||||||
private nbSecond = 0;
|
|
||||||
private maxNbSecond = 10;
|
|
||||||
private titleMessage = 'IMPORTANT !';
|
|
||||||
|
|
||||||
showMessage(message: string, canDeleteMessage: boolean = true): void {
|
|
||||||
//delete previous modal
|
|
||||||
try{
|
|
||||||
if(modalTimeOut){
|
|
||||||
clearTimeout(modalTimeOut);
|
|
||||||
}
|
|
||||||
const modal = HtmlUtils.getElementByIdOrFail('report-message-user');
|
|
||||||
modal.remove();
|
|
||||||
}catch (err){
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
//create new modal
|
|
||||||
const div : HTMLDivElement = document.createElement('div');
|
|
||||||
div.classList.add('modal-report-user');
|
|
||||||
div.id = 'report-message-user';
|
|
||||||
div.style.backgroundColor = '#000000e0';
|
|
||||||
|
|
||||||
const img : HTMLImageElement = document.createElement('img');
|
|
||||||
img.src = 'resources/logos/report.svg';
|
|
||||||
div.appendChild(img);
|
|
||||||
|
|
||||||
const title : HTMLParagraphElement = document.createElement('p');
|
|
||||||
title.id = 'title-report-user';
|
|
||||||
title.innerText = `${this.titleMessage} (${this.maxNbSecond})`;
|
|
||||||
div.appendChild(title);
|
|
||||||
|
|
||||||
const p : HTMLParagraphElement = document.createElement('p');
|
|
||||||
p.id = 'body-report-user'
|
|
||||||
p.innerText = message;
|
|
||||||
div.appendChild(p);
|
|
||||||
|
|
||||||
const mainSectionDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('main-container');
|
|
||||||
mainSectionDiv.appendChild(div);
|
|
||||||
|
|
||||||
const reportMessageAudio = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('report-message');
|
|
||||||
// FIXME: this will fail on iOS
|
|
||||||
// We should move the sound playing into the GameScene and listen to the event of a report using a store
|
|
||||||
try {
|
|
||||||
reportMessageAudio.play();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.nbSecond = this.maxNbSecond;
|
|
||||||
setTimeout((c) => {
|
|
||||||
this.forMessage(title, canDeleteMessage);
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
forMessage(title: HTMLParagraphElement, canDeleteMessage: boolean = true){
|
|
||||||
this.nbSecond -= 1;
|
|
||||||
title.innerText = `${this.titleMessage} (${this.nbSecond})`;
|
|
||||||
if(this.nbSecond > 0){
|
|
||||||
modalTimeOut = setTimeout(() => {
|
|
||||||
this.forMessage(title, canDeleteMessage);
|
|
||||||
}, 1000);
|
|
||||||
}else {
|
|
||||||
title.innerText = this.titleMessage;
|
|
||||||
|
|
||||||
if (!canDeleteMessage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const imgCancel: HTMLImageElement = document.createElement('img');
|
|
||||||
imgCancel.id = 'cancel-report-user';
|
|
||||||
imgCancel.src = 'resources/logos/close.svg';
|
|
||||||
|
|
||||||
const div = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('report-message-user');
|
|
||||||
div.appendChild(imgCancel);
|
|
||||||
imgCancel.addEventListener('click', () => {
|
|
||||||
div.remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Message extends TypeMessageExt {}
|
|
||||||
|
|
||||||
export class Ban extends TypeMessageExt {}
|
|
||||||
|
|
||||||
export class Banned extends TypeMessageExt {
|
|
||||||
showMessage(message: string){
|
|
||||||
super.showMessage(message, false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +1,34 @@
|
||||||
import * as TypeMessages from "./TypeMessage";
|
import { AdminMessageEventTypes, adminMessagesService } from "../Connexion/AdminMessagesService";
|
||||||
import {Banned} from "./TypeMessage";
|
import { textMessageContentStore, textMessageVisibleStore } from "../Stores/TypeMessageStore/TextMessageStore";
|
||||||
import {adminMessagesService} from "../Connexion/AdminMessagesService";
|
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
|
||||||
|
import { UPLOADER_URL } from "../Enum/EnvironmentVariable";
|
||||||
export interface TypeMessageInterface {
|
import { banMessageContentStore, banMessageVisibleStore } from "../Stores/TypeMessageStore/BanMessageStore";
|
||||||
showMessage(message: string): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserMessageManager {
|
class UserMessageManager {
|
||||||
|
|
||||||
typeMessages: Map<string, TypeMessageInterface> = new Map<string, TypeMessageInterface>();
|
|
||||||
receiveBannedMessageListener!: Function;
|
receiveBannedMessageListener!: Function;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const valueTypeMessageTab = Object.values(TypeMessages);
|
|
||||||
Object.keys(TypeMessages).forEach((value: string, index: number) => {
|
|
||||||
const typeMessageInstance: TypeMessageInterface = (new valueTypeMessageTab[index]() as TypeMessageInterface);
|
|
||||||
this.typeMessages.set(value.toLowerCase(), typeMessageInstance);
|
|
||||||
});
|
|
||||||
|
|
||||||
adminMessagesService.messageStream.subscribe((event) => {
|
adminMessagesService.messageStream.subscribe((event) => {
|
||||||
const typeMessage = this.showMessage(event.type, event.text);
|
textMessageVisibleStore.set(false);
|
||||||
if(typeMessage instanceof Banned) {
|
banMessageVisibleStore.set(false);
|
||||||
|
if (event.type === AdminMessageEventTypes.admin) {
|
||||||
|
textMessageContentStore.set(event.text);
|
||||||
|
textMessageVisibleStore.set(true);
|
||||||
|
} else if (event.type === AdminMessageEventTypes.audio) {
|
||||||
|
soundPlayingStore.playSound(UPLOADER_URL + event.text);
|
||||||
|
} else if (event.type === AdminMessageEventTypes.ban) {
|
||||||
|
banMessageContentStore.set(event.text);
|
||||||
|
banMessageVisibleStore.set(true);
|
||||||
|
} else if (event.type === AdminMessageEventTypes.banned) {
|
||||||
|
banMessageContentStore.set(event.text);
|
||||||
|
banMessageVisibleStore.set(true);
|
||||||
this.receiveBannedMessageListener();
|
this.receiveBannedMessageListener();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage(type: string, message: string) {
|
setReceiveBanListener(callback: Function) {
|
||||||
const classTypeMessage = this.typeMessages.get(type.toLowerCase());
|
|
||||||
if (!classTypeMessage) {
|
|
||||||
console.error('Message unknown');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
classTypeMessage.showMessage(message);
|
|
||||||
return classTypeMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
setReceiveBanListener(callback: Function){
|
|
||||||
this.receiveBannedMessageListener = callback;
|
this.receiveBannedMessageListener = callback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const userMessageManager = new UserMessageManager()
|
export const userMessageManager = new UserMessageManager();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as tg from "generic-type-guard";
|
import * as tg from "generic-type-guard";
|
||||||
import type { GameStateEvent } from "./GameStateEvent";
|
|
||||||
import type { ButtonClickedEvent } from "./ButtonClickedEvent";
|
import type { ButtonClickedEvent } from "./ButtonClickedEvent";
|
||||||
import type { ChatEvent } from "./ChatEvent";
|
import type { ChatEvent } from "./ChatEvent";
|
||||||
import type { ClosePopupEvent } from "./ClosePopupEvent";
|
import type { ClosePopupEvent } from "./ClosePopupEvent";
|
||||||
|
@ -10,7 +9,6 @@ import type { OpenCoWebSiteEvent } from "./OpenCoWebSiteEvent";
|
||||||
import type { OpenPopupEvent } from "./OpenPopupEvent";
|
import type { OpenPopupEvent } from "./OpenPopupEvent";
|
||||||
import type { OpenTabEvent } from "./OpenTabEvent";
|
import type { OpenTabEvent } from "./OpenTabEvent";
|
||||||
import type { UserInputChatEvent } from "./UserInputChatEvent";
|
import type { UserInputChatEvent } from "./UserInputChatEvent";
|
||||||
import type { MapDataEvent } from "./MapDataEvent";
|
|
||||||
import type { LayerEvent } from "./LayerEvent";
|
import type { LayerEvent } from "./LayerEvent";
|
||||||
import type { SetPropertyEvent } from "./setPropertyEvent";
|
import type { SetPropertyEvent } from "./setPropertyEvent";
|
||||||
import type { LoadSoundEvent } from "./LoadSoundEvent";
|
import type { LoadSoundEvent } from "./LoadSoundEvent";
|
||||||
|
@ -20,9 +18,11 @@ import type { MenuItemRegisterEvent } from "./ui/MenuItemRegisterEvent";
|
||||||
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
|
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
|
||||||
import type { SetTilesEvent } from "./SetTilesEvent";
|
import type { SetTilesEvent } from "./SetTilesEvent";
|
||||||
import type { SetVariableEvent } from "./SetVariableEvent";
|
import type { SetVariableEvent } from "./SetVariableEvent";
|
||||||
import {isGameStateEvent} from "./GameStateEvent";
|
import { isGameStateEvent } from "./GameStateEvent";
|
||||||
import {isMapDataEvent} from "./MapDataEvent";
|
import { isMapDataEvent } from "./MapDataEvent";
|
||||||
import {isSetVariableEvent} from "./SetVariableEvent";
|
import { isSetVariableEvent } from "./SetVariableEvent";
|
||||||
|
import type { LoadTilesetEvent } from "./LoadTilesetEvent";
|
||||||
|
import { isLoadTilesetEvent } from "./LoadTilesetEvent";
|
||||||
|
|
||||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||||
data: T;
|
data: T;
|
||||||
|
@ -52,6 +52,7 @@ export type IframeEventMap = {
|
||||||
playSound: PlaySoundEvent;
|
playSound: PlaySoundEvent;
|
||||||
stopSound: null;
|
stopSound: null;
|
||||||
getState: undefined;
|
getState: undefined;
|
||||||
|
loadTileset: LoadTilesetEvent;
|
||||||
registerMenuCommand: MenuItemRegisterEvent;
|
registerMenuCommand: MenuItemRegisterEvent;
|
||||||
setTiles: SetTilesEvent;
|
setTiles: SetTilesEvent;
|
||||||
};
|
};
|
||||||
|
@ -83,7 +84,6 @@ export const isIframeResponseEventWrapper = (event: {
|
||||||
type?: string;
|
type?: string;
|
||||||
}): event is IframeResponseEvent<keyof IframeResponseEventMap> => typeof event.type === "string";
|
}): event is IframeResponseEvent<keyof IframeResponseEventMap> => typeof event.type === "string";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame.
|
* List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame.
|
||||||
* Types are defined using Type guards that will actually bused to enforce and check types.
|
* Types are defined using Type guards that will actually bused to enforce and check types.
|
||||||
|
@ -101,22 +101,26 @@ export const iframeQueryMapTypeGuards = {
|
||||||
query: isSetVariableEvent,
|
query: isSetVariableEvent,
|
||||||
answer: tg.isUndefined,
|
answer: tg.isUndefined,
|
||||||
},
|
},
|
||||||
}
|
loadTileset: {
|
||||||
|
query: isLoadTilesetEvent,
|
||||||
|
answer: tg.isNumber,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
type GuardedType<T> = T extends (x: unknown) => x is (infer T) ? T : never;
|
type GuardedType<T> = T extends (x: unknown) => x is infer T ? T : never;
|
||||||
type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards;
|
type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards;
|
||||||
type UnknownToVoid<T> = undefined extends T ? void : T;
|
type UnknownToVoid<T> = undefined extends T ? void : T;
|
||||||
|
|
||||||
export type IframeQueryMap = {
|
export type IframeQueryMap = {
|
||||||
[key in keyof IframeQueryMapTypeGuardsType]: {
|
[key in keyof IframeQueryMapTypeGuardsType]: {
|
||||||
query: GuardedType<IframeQueryMapTypeGuardsType[key]['query']>
|
query: GuardedType<IframeQueryMapTypeGuardsType[key]["query"]>;
|
||||||
answer: UnknownToVoid<GuardedType<IframeQueryMapTypeGuardsType[key]['answer']>>
|
answer: UnknownToVoid<GuardedType<IframeQueryMapTypeGuardsType[key]["answer"]>>;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface IframeQuery<T extends keyof IframeQueryMap> {
|
export interface IframeQuery<T extends keyof IframeQueryMap> {
|
||||||
type: T;
|
type: T;
|
||||||
data: IframeQueryMap[T]['query'];
|
data: IframeQueryMap[T]["query"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IframeQueryWrapper<T extends keyof IframeQueryMap> {
|
export interface IframeQueryWrapper<T extends keyof IframeQueryMap> {
|
||||||
|
@ -126,30 +130,34 @@ export interface IframeQueryWrapper<T extends keyof IframeQueryMap> {
|
||||||
|
|
||||||
export const isIframeQueryKey = (type: string): type is keyof IframeQueryMap => {
|
export const isIframeQueryKey = (type: string): type is keyof IframeQueryMap => {
|
||||||
return type in iframeQueryMapTypeGuards;
|
return type in iframeQueryMapTypeGuards;
|
||||||
}
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const isIframeQuery = (event: any): event is IframeQuery<keyof IframeQueryMap> => {
|
export const isIframeQuery = (event: any): event is IframeQuery<keyof IframeQueryMap> => {
|
||||||
const type = event.type;
|
const type = event.type;
|
||||||
if (typeof type !== 'string') {
|
if (typeof type !== "string") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!isIframeQueryKey(type)) {
|
if (!isIframeQueryKey(type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return iframeQueryMapTypeGuards[type].query(event.data);
|
return iframeQueryMapTypeGuards[type].query(event.data);
|
||||||
}
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const isIframeQueryWrapper = (event: any): event is IframeQueryWrapper<keyof IframeQueryMap> => typeof event.id === 'number' && isIframeQuery(event.query);
|
export const isIframeQueryWrapper = (event: any): event is IframeQueryWrapper<keyof IframeQueryMap> =>
|
||||||
|
typeof event.id === "number" && isIframeQuery(event.query);
|
||||||
|
|
||||||
export interface IframeAnswerEvent<T extends keyof IframeQueryMap> {
|
export interface IframeAnswerEvent<T extends keyof IframeQueryMap> {
|
||||||
id: number;
|
id: number;
|
||||||
type: T;
|
type: T;
|
||||||
data: IframeQueryMap[T]['answer'];
|
data: IframeQueryMap[T]["answer"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isIframeAnswerEvent = (event: { type?: string, id?: number }): event is IframeAnswerEvent<keyof IframeQueryMap> => typeof event.type === 'string' && typeof event.id === 'number';
|
export const isIframeAnswerEvent = (event: {
|
||||||
|
type?: string;
|
||||||
|
id?: number;
|
||||||
|
}): event is IframeAnswerEvent<keyof IframeQueryMap> => typeof event.type === "string" && typeof event.id === "number";
|
||||||
|
|
||||||
export interface IframeErrorAnswerEvent {
|
export interface IframeErrorAnswerEvent {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -157,4 +165,9 @@ export interface IframeErrorAnswerEvent {
|
||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isIframeErrorAnswerEvent = (event: { type?: string, id?: number, error?: string }): event is IframeErrorAnswerEvent => typeof event.type === 'string' && typeof event.id === 'number' && typeof event.error === 'string';
|
export const isIframeErrorAnswerEvent = (event: {
|
||||||
|
type?: string;
|
||||||
|
id?: number;
|
||||||
|
error?: string;
|
||||||
|
}): event is IframeErrorAnswerEvent =>
|
||||||
|
typeof event.type === "string" && typeof event.id === "number" && typeof event.error === "string";
|
||||||
|
|
12
front/src/Api/Events/LoadTilesetEvent.ts
Normal file
12
front/src/Api/Events/LoadTilesetEvent.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
export const isLoadTilesetEvent = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
url: tg.isString,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
|
*/
|
||||||
|
export type LoadTilesetEvent = tg.GuardedType<typeof isLoadTilesetEvent>;
|
|
@ -1,18 +1,20 @@
|
||||||
import * as tg from "generic-type-guard";
|
import * as tg from "generic-type-guard";
|
||||||
import {isMenuItemRegisterEvent} from "./ui/MenuItemRegisterEvent";
|
import { isMenuItemRegisterEvent } from "./ui/MenuItemRegisterEvent";
|
||||||
|
|
||||||
export const isSetVariableEvent =
|
export const isSetVariableEvent = new tg.IsInterface()
|
||||||
new tg.IsInterface().withProperties({
|
.withProperties({
|
||||||
key: tg.isString,
|
key: tg.isString,
|
||||||
value: tg.isUnknown,
|
value: tg.isUnknown,
|
||||||
}).get();
|
})
|
||||||
|
.get();
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to change the value of the property of the layer
|
* A message sent from the iFrame to the game to change the value of the property of the layer
|
||||||
*/
|
*/
|
||||||
export type SetVariableEvent = tg.GuardedType<typeof isSetVariableEvent>;
|
export type SetVariableEvent = tg.GuardedType<typeof isSetVariableEvent>;
|
||||||
|
|
||||||
export const isSetVariableIframeEvent =
|
export const isSetVariableIframeEvent = new tg.IsInterface()
|
||||||
new tg.IsInterface().withProperties({
|
.withProperties({
|
||||||
type: tg.isSingletonString("setVariable"),
|
type: tg.isSingletonString("setVariable"),
|
||||||
data: isSetVariableEvent
|
data: isSetVariableEvent,
|
||||||
}).get();
|
})
|
||||||
|
.get();
|
||||||
|
|
|
@ -12,7 +12,8 @@ import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent
|
||||||
import {
|
import {
|
||||||
IframeErrorAnswerEvent,
|
IframeErrorAnswerEvent,
|
||||||
IframeEvent,
|
IframeEvent,
|
||||||
IframeEventMap, IframeQueryMap,
|
IframeEventMap,
|
||||||
|
IframeQueryMap,
|
||||||
IframeResponseEvent,
|
IframeResponseEvent,
|
||||||
IframeResponseEventMap,
|
IframeResponseEventMap,
|
||||||
isIframeEventWrapper,
|
isIframeEventWrapper,
|
||||||
|
@ -25,16 +26,16 @@ import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent";
|
||||||
import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent";
|
import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent";
|
||||||
import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent";
|
import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent";
|
||||||
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
|
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
|
||||||
import { isMenuItemRegisterEvent } from "./Events/ui/MenuItemRegisterEvent";
|
|
||||||
import type { MapDataEvent } from "./Events/MapDataEvent";
|
|
||||||
import type { GameStateEvent } from "./Events/GameStateEvent";
|
|
||||||
import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent";
|
import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent";
|
||||||
import { isLoadPageEvent } from "./Events/LoadPageEvent";
|
import { isLoadPageEvent } from "./Events/LoadPageEvent";
|
||||||
import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from "./Events/ui/MenuItemRegisterEvent";
|
import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from "./Events/ui/MenuItemRegisterEvent";
|
||||||
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
||||||
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
||||||
|
|
||||||
type AnswererCallback<T extends keyof IframeQueryMap> = (query: IframeQueryMap[T]["query"], source: MessageEventSource | null) => IframeQueryMap[T]["answer"] | PromiseLike<IframeQueryMap[T]["answer"]>;
|
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
||||||
|
query: IframeQueryMap[T]["query"],
|
||||||
|
source: MessageEventSource | null
|
||||||
|
) => IframeQueryMap[T]["answer"] | PromiseLike<IframeQueryMap[T]["answer"]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens to messages from iframes and turn those messages into easy to use observables.
|
* Listens to messages from iframes and turn those messages into easy to use observables.
|
||||||
|
@ -112,13 +113,11 @@ class IframeListener {
|
||||||
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
||||||
private sendPlayerMove: boolean = false;
|
private sendPlayerMove: boolean = false;
|
||||||
|
|
||||||
|
|
||||||
// Note: we are forced to type this in unknown and later cast with "as" because of https://github.com/microsoft/TypeScript/issues/31904
|
// Note: we are forced to type this in unknown and later cast with "as" because of https://github.com/microsoft/TypeScript/issues/31904
|
||||||
private answerers: {
|
private answerers: {
|
||||||
[str in keyof IframeQueryMap]?: unknown
|
[str in keyof IframeQueryMap]?: unknown;
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
"message",
|
"message",
|
||||||
|
@ -158,42 +157,56 @@ class IframeListener {
|
||||||
|
|
||||||
const answerer = this.answerers[query.type] as AnswererCallback<keyof IframeQueryMap> | undefined;
|
const answerer = this.answerers[query.type] as AnswererCallback<keyof IframeQueryMap> | undefined;
|
||||||
if (answerer === undefined) {
|
if (answerer === undefined) {
|
||||||
const errorMsg = 'The iFrame sent a message of type "'+query.type+'" but there is no service configured to answer these messages.';
|
const errorMsg =
|
||||||
|
'The iFrame sent a message of type "' +
|
||||||
|
query.type +
|
||||||
|
'" but there is no service configured to answer these messages.';
|
||||||
console.error(errorMsg);
|
console.error(errorMsg);
|
||||||
iframe.contentWindow?.postMessage({
|
iframe.contentWindow?.postMessage(
|
||||||
|
{
|
||||||
id: queryId,
|
id: queryId,
|
||||||
type: query.type,
|
type: query.type,
|
||||||
error: errorMsg
|
error: errorMsg,
|
||||||
} as IframeErrorAnswerEvent, '*');
|
} as IframeErrorAnswerEvent,
|
||||||
|
"*"
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorHandler = (reason: unknown) => {
|
const errorHandler = (reason: unknown) => {
|
||||||
console.error('An error occurred while responding to an iFrame query.', reason);
|
console.error("An error occurred while responding to an iFrame query.", reason);
|
||||||
let reasonMsg: string = '';
|
let reasonMsg: string = "";
|
||||||
if (reason instanceof Error) {
|
if (reason instanceof Error) {
|
||||||
reasonMsg = reason.message;
|
reasonMsg = reason.message;
|
||||||
} else if (typeof reason === 'object') {
|
} else if (typeof reason === "object") {
|
||||||
reasonMsg = reason ? reason.toString() : '';
|
reasonMsg = reason ? reason.toString() : "";
|
||||||
} else if (typeof reason === 'string') {
|
} else if (typeof reason === "string") {
|
||||||
reasonMsg = reason;
|
reasonMsg = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
iframe?.contentWindow?.postMessage({
|
iframe?.contentWindow?.postMessage(
|
||||||
|
{
|
||||||
id: queryId,
|
id: queryId,
|
||||||
type: query.type,
|
type: query.type,
|
||||||
error: reasonMsg
|
error: reasonMsg,
|
||||||
} as IframeErrorAnswerEvent, '*');
|
} as IframeErrorAnswerEvent,
|
||||||
|
"*"
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Promise.resolve(answerer(query.data, message.source)).then((value) => {
|
Promise.resolve(answerer(query.data, message.source))
|
||||||
iframe?.contentWindow?.postMessage({
|
.then((value) => {
|
||||||
|
iframe?.contentWindow?.postMessage(
|
||||||
|
{
|
||||||
id: queryId,
|
id: queryId,
|
||||||
type: query.type,
|
type: query.type,
|
||||||
data: value
|
data: value,
|
||||||
}, '*');
|
},
|
||||||
}).catch(errorHandler);
|
"*"
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(errorHandler);
|
||||||
} catch (reason) {
|
} catch (reason) {
|
||||||
errorHandler(reason);
|
errorHandler(reason);
|
||||||
}
|
}
|
||||||
|
@ -398,8 +411,8 @@ class IframeListener {
|
||||||
|
|
||||||
setVariable(setVariableEvent: SetVariableEvent) {
|
setVariable(setVariableEvent: SetVariableEvent) {
|
||||||
this.postMessage({
|
this.postMessage({
|
||||||
'type': 'setVariable',
|
type: "setVariable",
|
||||||
'data': setVariableEvent
|
data: setVariableEvent,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +433,7 @@ class IframeListener {
|
||||||
* @param key The "type" of the query we are answering
|
* @param key The "type" of the query we are answering
|
||||||
* @param callback
|
* @param callback
|
||||||
*/
|
*/
|
||||||
public registerAnswerer<T extends keyof IframeQueryMap>(key: T, callback: AnswererCallback<T> ): void {
|
public registerAnswerer<T extends keyof IframeQueryMap>(key: T, callback: AnswererCallback<T>): void {
|
||||||
this.answerers[key] = callback;
|
this.answerers[key] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,13 +445,16 @@ class IframeListener {
|
||||||
// Let's dispatch the message to the other iframes
|
// Let's dispatch the message to the other iframes
|
||||||
for (const iframe of this.iframes) {
|
for (const iframe of this.iframes) {
|
||||||
if (iframe.contentWindow !== source) {
|
if (iframe.contentWindow !== source) {
|
||||||
iframe.contentWindow?.postMessage({
|
iframe.contentWindow?.postMessage(
|
||||||
'type': 'setVariable',
|
{
|
||||||
'data': {
|
type: "setVariable",
|
||||||
|
data: {
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
}
|
},
|
||||||
}, '*');
|
},
|
||||||
|
"*"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Observable, Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
|
|
||||||
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
||||||
|
|
||||||
|
@ -105,6 +105,14 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
||||||
}
|
}
|
||||||
return mapURL;
|
return mapURL;
|
||||||
}
|
}
|
||||||
|
async loadTileset(url: string): Promise<number> {
|
||||||
|
return await queryWorkadventure({
|
||||||
|
type: "loadTileset",
|
||||||
|
data: {
|
||||||
|
url: url,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new WorkadventureRoomCommands();
|
export default new WorkadventureRoomCommands();
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
import {gameOverlayVisibilityStore} from "../Stores/GameOverlayStoreVisibility";
|
import {gameOverlayVisibilityStore} from "../Stores/GameOverlayStoreVisibility";
|
||||||
import {consoleGlobalMessageManagerVisibleStore} from "../Stores/ConsoleGlobalMessageManagerStore";
|
import {consoleGlobalMessageManagerVisibleStore} from "../Stores/ConsoleGlobalMessageManagerStore";
|
||||||
import ConsoleGlobalMessageManager from "./ConsoleGlobalMessageManager/ConsoleGlobalMessageManager.svelte";
|
import ConsoleGlobalMessageManager from "./ConsoleGlobalMessageManager/ConsoleGlobalMessageManager.svelte";
|
||||||
|
import AdminMessage from "./TypeMessage/BanMessage.svelte";
|
||||||
|
import TextMessage from "./TypeMessage/TextMessage.svelte";
|
||||||
|
import {banMessageVisibleStore} from "../Stores/TypeMessageStore/BanMessageStore";
|
||||||
|
import {textMessageVisibleStore} from "../Stores/TypeMessageStore/TextMessageStore";
|
||||||
import {warningContainerStore} from "../Stores/MenuStore";
|
import {warningContainerStore} from "../Stores/MenuStore";
|
||||||
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
||||||
import {layoutManagerVisibilityStore} from "../Stores/LayoutManagerStore";
|
import {layoutManagerVisibilityStore} from "../Stores/LayoutManagerStore";
|
||||||
|
@ -62,6 +66,16 @@
|
||||||
<EnableCameraScene game={game}></EnableCameraScene>
|
<EnableCameraScene game={game}></EnableCameraScene>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $banMessageVisibleStore}
|
||||||
|
<div>
|
||||||
|
<AdminMessage></AdminMessage>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if $textMessageVisibleStore}
|
||||||
|
<div>
|
||||||
|
<TextMessage></TextMessage>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if $soundPlayingStore}
|
{#if $soundPlayingStore}
|
||||||
<div>
|
<div>
|
||||||
<AudioPlaying url={$soundPlayingStore} />
|
<AudioPlaying url={$soundPlayingStore} />
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
let inputSendTextActive = true;
|
let inputSendTextActive = true;
|
||||||
let uploadMusicActive = false;
|
let uploadMusicActive = false;
|
||||||
let handleSendText: { sendTextMessage(): void };
|
let handleSendText: { sendTextMessage(broadcast: boolean): void };
|
||||||
let handleSendAudio: { sendAudioMessage(): Promise<void> };
|
let handleSendAudio: { sendAudioMessage(broadcast: boolean): Promise<void> };
|
||||||
let broadcastToWorld = false;
|
let broadcastToWorld = false;
|
||||||
|
|
||||||
function closeConsoleGlobalMessage() {
|
function closeConsoleGlobalMessage() {
|
||||||
|
@ -35,10 +35,10 @@
|
||||||
|
|
||||||
function send() {
|
function send() {
|
||||||
if (inputSendTextActive) {
|
if (inputSendTextActive) {
|
||||||
handleSendText.sendTextMessage();
|
handleSendText.sendTextMessage(broadcastToWorld);
|
||||||
}
|
}
|
||||||
if (uploadMusicActive) {
|
if (uploadMusicActive) {
|
||||||
handleSendAudio.sendAudioMessage();
|
handleSendAudio.sendAudioMessage(broadcastToWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
import { consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
||||||
import { onMount } from "svelte";
|
import {onDestroy, onMount} from "svelte";
|
||||||
import type { Game } from "../../Phaser/Game/Game";
|
import type { Game } from "../../Phaser/Game/Game";
|
||||||
import type { GameManager } from "../../Phaser/Game/GameManager";
|
import type { GameManager } from "../../Phaser/Game/GameManager";
|
||||||
import type { PlayGlobalMessageInterface } from "../../Connexion/ConnexionModels";
|
|
||||||
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
|
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
|
||||||
import type { Quill } from "quill";
|
import type { Quill } from "quill";
|
||||||
|
import type { PlayGlobalMessageInterface } from "../../Connexion/ConnexionModels";
|
||||||
|
|
||||||
//toolbar
|
//toolbar
|
||||||
const toolbarOptions = [
|
const toolbarOptions = [
|
||||||
|
@ -34,27 +34,27 @@
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
export let gameManager: GameManager;
|
export let gameManager: GameManager;
|
||||||
|
|
||||||
let gameScene = gameManager.getCurrentGameScene(game.findAnyScene());
|
const gameScene = gameManager.getCurrentGameScene(game.findAnyScene());
|
||||||
let quill: Quill;
|
let quill: Quill;
|
||||||
let INPUT_CONSOLE_MESSAGE: HTMLDivElement;
|
let INPUT_CONSOLE_MESSAGE: HTMLDivElement;
|
||||||
|
|
||||||
const MESSAGE_TYPE = AdminMessageEventTypes.admin;
|
const MESSAGE_TYPE = AdminMessageEventTypes.admin;
|
||||||
|
|
||||||
export const handleSending = {
|
export const handleSending = {
|
||||||
sendTextMessage() {
|
sendTextMessage(broadcastToWorld: boolean) {
|
||||||
if (gameScene == undefined) {
|
if (gameScene == undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const text = quill.getText(0, quill.getLength());
|
const text = JSON.stringify(quill.getContents(0, quill.getLength()));
|
||||||
|
|
||||||
const GlobalMessage: PlayGlobalMessageInterface = {
|
const textGlobalMessage: PlayGlobalMessageInterface = {
|
||||||
id: "1", // FIXME: use another ID?
|
type: MESSAGE_TYPE,
|
||||||
message: text,
|
content: text,
|
||||||
type: MESSAGE_TYPE
|
broadcastToWorld: broadcastToWorld
|
||||||
};
|
};
|
||||||
|
|
||||||
quill.deleteText(0, quill.getLength());
|
quill.deleteText(0, quill.getLength());
|
||||||
gameScene.connection?.emitGlobalMessage(GlobalMessage);
|
gameScene.connection?.emitGlobalMessage(textGlobalMessage);
|
||||||
disableConsole();
|
disableConsole();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,13 +73,12 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
quill.on('selection-change', function (range, oldRange) {
|
|
||||||
if (range === null && oldRange !== null) {
|
|
||||||
consoleGlobalMessageManagerFocusStore.set(false);
|
|
||||||
} else if (range !== null && oldRange === null)
|
|
||||||
consoleGlobalMessageManagerFocusStore.set(true);
|
consoleGlobalMessageManagerFocusStore.set(true);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
onDestroy(() => {
|
||||||
|
consoleGlobalMessageManagerFocusStore.set(false);
|
||||||
|
})
|
||||||
|
|
||||||
function disableConsole() {
|
function disableConsole() {
|
||||||
consoleGlobalMessageManagerVisibleStore.set(false);
|
consoleGlobalMessageManagerVisibleStore.set(false);
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
import type { GameManager } from "../../Phaser/Game/GameManager";
|
import type { GameManager } from "../../Phaser/Game/GameManager";
|
||||||
import { consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
import { consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
||||||
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
|
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
|
||||||
import type { PlayGlobalMessageInterface } from "../../Connexion/ConnexionModels";
|
|
||||||
import uploadFile from "../images/music-file.svg";
|
import uploadFile from "../images/music-file.svg";
|
||||||
|
import type {PlayGlobalMessageInterface} from "../../Connexion/ConnexionModels";
|
||||||
|
|
||||||
interface EventTargetFiles extends EventTarget {
|
interface EventTargetFiles extends EventTarget {
|
||||||
files: Array<File>;
|
files: Array<File>;
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
const AUDIO_TYPE = AdminMessageEventTypes.audio;
|
const AUDIO_TYPE = AdminMessageEventTypes.audio;
|
||||||
|
|
||||||
export const handleSending = {
|
export const handleSending = {
|
||||||
async sendAudioMessage() {
|
async sendAudioMessage(broadcast: boolean) {
|
||||||
if (gameScene == undefined) {
|
if (gameScene == undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -38,13 +38,13 @@
|
||||||
fd.append('file', selectedFile);
|
fd.append('file', selectedFile);
|
||||||
const res = await gameScene.connection?.uploadAudio(fd);
|
const res = await gameScene.connection?.uploadAudio(fd);
|
||||||
|
|
||||||
const GlobalMessage: PlayGlobalMessageInterface = {
|
const audioGlobalMessage: PlayGlobalMessageInterface = {
|
||||||
id: (res as { id: string }).id,
|
content: (res as { path: string }).path,
|
||||||
message: (res as { path: string }).path,
|
type: AUDIO_TYPE,
|
||||||
type: AUDIO_TYPE
|
broadcastToWorld: broadcast
|
||||||
}
|
}
|
||||||
inputAudio.value = '';
|
inputAudio.value = '';
|
||||||
gameScene.connection?.emitGlobalMessage(GlobalMessage);
|
gameScene.connection?.emitGlobalMessage(audioGlobalMessage);
|
||||||
disableConsole();
|
disableConsole();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
96
front/src/Components/TypeMessage/BanMessage.svelte
Normal file
96
front/src/Components/TypeMessage/BanMessage.svelte
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { fly } from "svelte/transition";
|
||||||
|
import {banMessageVisibleStore, banMessageContentStore} from "../../Stores/TypeMessageStore/BanMessageStore";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
|
||||||
|
const text = $banMessageContentStore;
|
||||||
|
const NAME_BUTTON = 'Ok';
|
||||||
|
let nbSeconds = 10;
|
||||||
|
let nameButton = '';
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
timeToRead()
|
||||||
|
})
|
||||||
|
|
||||||
|
function timeToRead() {
|
||||||
|
nbSeconds -= 1;
|
||||||
|
nameButton = nbSeconds.toString();
|
||||||
|
if ( nbSeconds > 0 ) {
|
||||||
|
setTimeout( () => {
|
||||||
|
timeToRead();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
nameButton = NAME_BUTTON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeBanMessage() {
|
||||||
|
banMessageVisibleStore.set(false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="main-ban-message nes-container is-rounded" transition:fly="{{ y: -1000, duration: 500 }}">
|
||||||
|
<h2 class="title-ban-message"><img src="resources/logos/report.svg" alt="***"/> Important message <img src="resources/logos/report.svg" alt="***"/></h2>
|
||||||
|
<div class="content-ban-message">
|
||||||
|
<p>{text}</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-ban-message">
|
||||||
|
<button type="button" class="nes-btn {nameButton === NAME_BUTTON ? 'is-primary' : 'is-error'}" disabled="{!(nameButton === NAME_BUTTON)}" on:click|preventDefault={closeBanMessage}>{nameButton}</button>
|
||||||
|
</div>
|
||||||
|
<audio id="report-message" autoplay>
|
||||||
|
<source src="/resources/objects/report-message.mp3" type="audio/mp3">
|
||||||
|
</audio>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.main-ban-message {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
top: 15vh;
|
||||||
|
|
||||||
|
height: 70vh;
|
||||||
|
width: 60vw;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
padding-bottom: 0;
|
||||||
|
|
||||||
|
pointer-events: auto;
|
||||||
|
background-color: #333333;
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
h2.title-ban-message {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
max-height: 50px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content-ban-message {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
max-height: calc(100% - 50px);
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
p {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer-ban-message {
|
||||||
|
height: 50px;
|
||||||
|
margin-top: 10px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 88px;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
59
front/src/Components/TypeMessage/TextMessage.svelte
Normal file
59
front/src/Components/TypeMessage/TextMessage.svelte
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { fly } from "svelte/transition";
|
||||||
|
import {textMessageContentStore, textMessageVisibleStore} from "../../Stores/TypeMessageStore/TextMessageStore";
|
||||||
|
import { QuillDeltaToHtmlConverter } from "quill-delta-to-html";
|
||||||
|
|
||||||
|
const content = JSON.parse($textMessageContentStore);
|
||||||
|
const converter = new QuillDeltaToHtmlConverter(content.ops, {inlineStyles: true});
|
||||||
|
const NAME_BUTTON = 'Ok';
|
||||||
|
|
||||||
|
function closeTextMessage() {
|
||||||
|
textMessageVisibleStore.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(e:KeyboardEvent) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
closeTextMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:keydown={onKeyDown}/>
|
||||||
|
|
||||||
|
<div class="main-text-message nes-container is-rounded" transition:fly="{{ x: -1000, duration: 500 }}">
|
||||||
|
<div class="content-text-message">
|
||||||
|
{@html converter.convert()}
|
||||||
|
</div>
|
||||||
|
<div class="footer-text-message">
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click|preventDefault={closeTextMessage}>{NAME_BUTTON}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.main-text-message {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
max-height: 25vh;
|
||||||
|
width: 80vw;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
padding-bottom: 0;
|
||||||
|
|
||||||
|
pointer-events: auto;
|
||||||
|
background-color: #333333;
|
||||||
|
|
||||||
|
div.content-text-message {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
max-height: calc(100% - 50px);
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer-text-message {
|
||||||
|
height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -64,11 +64,8 @@ class ConnectionManager {
|
||||||
);
|
);
|
||||||
localUserStore.setAuthToken(authToken);
|
localUserStore.setAuthToken(authToken);
|
||||||
this.authToken = authToken;
|
this.authToken = authToken;
|
||||||
room = await Room.createRoom(
|
room = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
|
||||||
new URL(localUserStore.getLastRoomUrl())
|
|
||||||
);
|
|
||||||
urlManager.pushRoomIdToUrl(room);
|
urlManager.pushRoomIdToUrl(room);
|
||||||
|
|
||||||
} else if (connexionType === GameConnexionTypes.register) {
|
} else if (connexionType === GameConnexionTypes.register) {
|
||||||
//@deprecated
|
//@deprecated
|
||||||
const organizationMemberToken = urlManager.getOrganizationToken();
|
const organizationMemberToken = urlManager.getOrganizationToken();
|
||||||
|
|
|
@ -110,9 +110,9 @@ export interface RoomJoinedMessageInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlayGlobalMessageInterface {
|
export interface PlayGlobalMessageInterface {
|
||||||
id: string;
|
|
||||||
type: string;
|
type: string;
|
||||||
message: string;
|
content: string;
|
||||||
|
broadcastToWorld: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OnConnectInterface {
|
export interface OnConnectInterface {
|
||||||
|
|
|
@ -597,7 +597,7 @@ export class RoomConnection implements RoomConnection {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public receivePlayGlobalMessage(callback: (message: PlayGlobalMessageInterface) => void) {
|
/* public receivePlayGlobalMessage(callback: (message: PlayGlobalMessageInterface) => void) {
|
||||||
return this.onMessage(EventMessage.PLAY_GLOBAL_MESSAGE, (message: PlayGlobalMessage) => {
|
return this.onMessage(EventMessage.PLAY_GLOBAL_MESSAGE, (message: PlayGlobalMessage) => {
|
||||||
callback({
|
callback({
|
||||||
id: message.getId(),
|
id: message.getId(),
|
||||||
|
@ -605,7 +605,7 @@ export class RoomConnection implements RoomConnection {
|
||||||
message: message.getMessage(),
|
message: message.getMessage(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}*/
|
||||||
|
|
||||||
public receiveStopGlobalMessage(callback: (messageId: string) => void) {
|
public receiveStopGlobalMessage(callback: (messageId: string) => void) {
|
||||||
return this.onMessage(EventMessage.STOP_GLOBAL_MESSAGE, (message: StopGlobalMessage) => {
|
return this.onMessage(EventMessage.STOP_GLOBAL_MESSAGE, (message: StopGlobalMessage) => {
|
||||||
|
@ -619,11 +619,11 @@ export class RoomConnection implements RoomConnection {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public emitGlobalMessage(message: PlayGlobalMessageInterface) {
|
public emitGlobalMessage(message: PlayGlobalMessageInterface): void {
|
||||||
const playGlobalMessage = new PlayGlobalMessage();
|
const playGlobalMessage = new PlayGlobalMessage();
|
||||||
playGlobalMessage.setId(message.id);
|
|
||||||
playGlobalMessage.setType(message.type);
|
playGlobalMessage.setType(message.type);
|
||||||
playGlobalMessage.setMessage(message.message);
|
playGlobalMessage.setContent(message.content);
|
||||||
|
playGlobalMessage.setBroadcasttoworld(message.broadcastToWorld);
|
||||||
|
|
||||||
const clientToServerMessage = new ClientToServerMessage();
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
clientToServerMessage.setPlayglobalmessage(playGlobalMessage);
|
clientToServerMessage.setPlayglobalmessage(playGlobalMessage);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import type { Subscription } from "rxjs";
|
import type { Subscription } from "rxjs";
|
||||||
import { GlobalMessageManager } from "../../Administration/GlobalMessageManager";
|
|
||||||
import { userMessageManager } from "../../Administration/UserMessageManager";
|
import { userMessageManager } from "../../Administration/UserMessageManager";
|
||||||
import { iframeListener } from "../../Api/IframeListener";
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||||
|
@ -74,8 +73,6 @@ import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey }
|
||||||
import { waScaleManager } from "../Services/WaScaleManager";
|
import { waScaleManager } from "../Services/WaScaleManager";
|
||||||
import { EmoteManager } from "./EmoteManager";
|
import { EmoteManager } from "./EmoteManager";
|
||||||
import EVENT_TYPE = Phaser.Scenes.Events;
|
import EVENT_TYPE = Phaser.Scenes.Events;
|
||||||
import RenderTexture = Phaser.GameObjects.RenderTexture;
|
|
||||||
import Tilemap = Phaser.Tilemaps.Tilemap;
|
|
||||||
import type { HasPlayerMovedEvent } from "../../Api/Events/HasPlayerMovedEvent";
|
import type { HasPlayerMovedEvent } from "../../Api/Events/HasPlayerMovedEvent";
|
||||||
|
|
||||||
import AnimatedTiles from "phaser-animated-tiles";
|
import AnimatedTiles from "phaser-animated-tiles";
|
||||||
|
@ -87,6 +84,7 @@ import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStor
|
||||||
import { SharedVariablesManager } from "./SharedVariablesManager";
|
import { SharedVariablesManager } from "./SharedVariablesManager";
|
||||||
import { playersStore } from "../../Stores/PlayersStore";
|
import { playersStore } from "../../Stores/PlayersStore";
|
||||||
import { chatVisibilityStore } from "../../Stores/ChatStore";
|
import { chatVisibilityStore } from "../../Stores/ChatStore";
|
||||||
|
import Tileset = Phaser.Tilemaps.Tileset;
|
||||||
import { userIsAdminStore } from "../../Stores/GameStore";
|
import { userIsAdminStore } from "../../Stores/GameStore";
|
||||||
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../../Stores/LayoutManagerStore";
|
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../../Stores/LayoutManagerStore";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
@ -157,7 +155,6 @@ export class GameScene extends DirtyScene {
|
||||||
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
||||||
public connection: RoomConnection | undefined;
|
public connection: RoomConnection | undefined;
|
||||||
private simplePeer!: SimplePeer;
|
private simplePeer!: SimplePeer;
|
||||||
private GlobalMessageManager!: GlobalMessageManager;
|
|
||||||
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
||||||
private connectionAnswerPromiseResolve!: (
|
private connectionAnswerPromiseResolve!: (
|
||||||
value: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>
|
value: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>
|
||||||
|
@ -223,6 +220,9 @@ export class GameScene extends DirtyScene {
|
||||||
|
|
||||||
//hook preload scene
|
//hook preload scene
|
||||||
preload(): void {
|
preload(): void {
|
||||||
|
//initialize frame event of scripting API
|
||||||
|
this.listenToIframeEvents();
|
||||||
|
|
||||||
const localUser = localUserStore.getLocalUser();
|
const localUser = localUserStore.getLocalUser();
|
||||||
const textures = localUser?.textures;
|
const textures = localUser?.textures;
|
||||||
if (textures) {
|
if (textures) {
|
||||||
|
@ -551,7 +551,6 @@ export class GameScene extends DirtyScene {
|
||||||
);
|
);
|
||||||
|
|
||||||
this.triggerOnMapLayerPropertyChange();
|
this.triggerOnMapLayerPropertyChange();
|
||||||
this.listenToIframeEvents();
|
|
||||||
|
|
||||||
if (!this.room.isDisconnected()) {
|
if (!this.room.isDisconnected()) {
|
||||||
this.connect();
|
this.connect();
|
||||||
|
@ -694,7 +693,6 @@ export class GameScene extends DirtyScene {
|
||||||
peerStore.connectToSimplePeer(this.simplePeer);
|
peerStore.connectToSimplePeer(this.simplePeer);
|
||||||
screenSharingPeerStore.connectToSimplePeer(this.simplePeer);
|
screenSharingPeerStore.connectToSimplePeer(this.simplePeer);
|
||||||
videoFocusStore.connectToSimplePeer(this.simplePeer);
|
videoFocusStore.connectToSimplePeer(this.simplePeer);
|
||||||
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
|
||||||
userMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
|
userMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
@ -1083,8 +1081,74 @@ ${escapedMessage}
|
||||||
for (const eventTile of eventTiles) {
|
for (const eventTile of eventTiles) {
|
||||||
this.gameMap.putTile(eventTile.tile, eventTile.x, eventTile.y, eventTile.layer);
|
this.gameMap.putTile(eventTile.tile, eventTile.x, eventTile.y, eventTile.layer);
|
||||||
}
|
}
|
||||||
|
this.markDirty();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
iframeListener.registerAnswerer("loadTileset", (eventTileset) => {
|
||||||
|
return this.connectionAnswerPromise.then(() => {
|
||||||
|
const jsonTilesetDir = eventTileset.url.substr(0, eventTileset.url.lastIndexOf("/"));
|
||||||
|
//Initialise the firstgid to 1 because if there is no tileset in the tilemap, the firstgid will be 1
|
||||||
|
let newFirstgid = 1;
|
||||||
|
const lastTileset = this.mapFile.tilesets[this.mapFile.tilesets.length - 1];
|
||||||
|
if (lastTileset) {
|
||||||
|
//If there is at least one tileset in the tilemap then calculate the firstgid of the new tileset
|
||||||
|
newFirstgid = lastTileset.firstgid + lastTileset.tilecount;
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.load.on("filecomplete-json-" + eventTileset.url, () => {
|
||||||
|
let jsonTileset = this.cache.json.get(eventTileset.url);
|
||||||
|
const imageUrl = jsonTilesetDir + "/" + jsonTileset.image;
|
||||||
|
this.load.image(imageUrl, imageUrl);
|
||||||
|
this.load.on("filecomplete-image-" + imageUrl, () => {
|
||||||
|
//Add the firstgid of the tileset to the json file
|
||||||
|
jsonTileset = { ...jsonTileset, firstgid: newFirstgid };
|
||||||
|
this.mapFile.tilesets.push(jsonTileset);
|
||||||
|
this.Map.tilesets.push(
|
||||||
|
new Tileset(
|
||||||
|
jsonTileset.name,
|
||||||
|
jsonTileset.firstgid,
|
||||||
|
jsonTileset.tileWidth,
|
||||||
|
jsonTileset.tileHeight,
|
||||||
|
jsonTileset.margin,
|
||||||
|
jsonTileset.spacing,
|
||||||
|
jsonTileset.tiles
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.Terrains.push(
|
||||||
|
this.Map.addTilesetImage(
|
||||||
|
jsonTileset.name,
|
||||||
|
imageUrl,
|
||||||
|
jsonTileset.tilewidth,
|
||||||
|
jsonTileset.tileheight,
|
||||||
|
jsonTileset.margin,
|
||||||
|
jsonTileset.spacing
|
||||||
|
)
|
||||||
|
);
|
||||||
|
//destroy the tilemapayer because they are unique and we need to reuse their key and layerdData
|
||||||
|
for (const layer of this.Map.layers) {
|
||||||
|
layer.tilemapLayer.destroy(false);
|
||||||
|
}
|
||||||
|
//Create a new GameMap with the changed file
|
||||||
|
this.gameMap = new GameMap(this.mapFile, this.Map, this.Terrains);
|
||||||
|
//Destroy the colliders of the old tilemapLayer
|
||||||
|
this.physics.add.world.colliders.destroy();
|
||||||
|
//Create new colliders with the new GameMap
|
||||||
|
this.createCollisionWithPlayer();
|
||||||
|
//Create new trigger with the new GameMap
|
||||||
|
this.triggerOnMapLayerPropertyChange();
|
||||||
|
resolve(newFirstgid);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.load.on("loaderror", () => {
|
||||||
|
console.error("Error while loading " + eventTileset.url + ".");
|
||||||
|
reject(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.load.json(eventTileset.url, eventTileset.url);
|
||||||
|
this.load.start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private setPropertyLayer(
|
private setPropertyLayer(
|
||||||
|
@ -1206,6 +1270,7 @@ ${escapedMessage}
|
||||||
this.chatVisibilityUnsubscribe();
|
this.chatVisibilityUnsubscribe();
|
||||||
this.biggestAvailableAreaStoreUnsubscribe();
|
this.biggestAvailableAreaStoreUnsubscribe();
|
||||||
iframeListener.unregisterAnswerer("getState");
|
iframeListener.unregisterAnswerer("getState");
|
||||||
|
iframeListener.unregisterAnswerer("loadTileset");
|
||||||
this.sharedVariablesManager?.close();
|
this.sharedVariablesManager?.close();
|
||||||
|
|
||||||
mediaManager.hideGameOverlay();
|
mediaManager.hideGameOverlay();
|
||||||
|
|
|
@ -387,7 +387,11 @@ export class MenuScene extends Phaser.Scene {
|
||||||
private gotToCreateMapPage() {
|
private gotToCreateMapPage() {
|
||||||
//const sparkHost = 'https://'+window.location.host.replace('play.', '')+'/choose-map.html';
|
//const sparkHost = 'https://'+window.location.host.replace('play.', '')+'/choose-map.html';
|
||||||
//TODO fix me: this button can to send us on WorkAdventure BO.
|
//TODO fix me: this button can to send us on WorkAdventure BO.
|
||||||
const sparkHost = ADMIN_URL + "/getting-started";
|
//const sparkHost = ADMIN_URL + "/getting-started";
|
||||||
|
|
||||||
|
//The redirection must be only on workadventu.re domain
|
||||||
|
//To day the domain staging cannot be use by customer
|
||||||
|
const sparkHost = "https://workadventu.re/getting-started";
|
||||||
window.open(sparkHost, "_blank");
|
window.open(sparkHost, "_blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import type { Direction } from "../../types";
|
import type { Direction } from "../../types";
|
||||||
import type {GameScene} from "../Game/GameScene";
|
import type { GameScene } from "../Game/GameScene";
|
||||||
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
||||||
import {MobileJoystick} from "../Components/MobileJoystick";
|
import { MobileJoystick } from "../Components/MobileJoystick";
|
||||||
import {enableUserInputsStore} from "../../Stores/UserInputStore";
|
import { enableUserInputsStore } from "../../Stores/UserInputStore";
|
||||||
|
|
||||||
interface UserInputManagerDatum {
|
interface UserInputManagerDatum {
|
||||||
keyInstance: Phaser.Input.Keyboard.Key;
|
keyInstance: Phaser.Input.Keyboard.Key;
|
||||||
event: UserInputEvent
|
event: UserInputEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum UserInputEvent {
|
export enum UserInputEvent {
|
||||||
|
@ -20,10 +20,9 @@ export enum UserInputEvent {
|
||||||
JoystickMove,
|
JoystickMove,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//we cannot use a map structure so we have to create a replacement
|
//we cannot use a map structure so we have to create a replacement
|
||||||
export class ActiveEventList {
|
export class ActiveEventList {
|
||||||
private eventMap : Map<UserInputEvent, boolean> = new Map<UserInputEvent, boolean>();
|
private eventMap: Map<UserInputEvent, boolean> = new Map<UserInputEvent, boolean>();
|
||||||
|
|
||||||
get(event: UserInputEvent): boolean {
|
get(event: UserInputEvent): boolean {
|
||||||
return this.eventMap.get(event) || false;
|
return this.eventMap.get(event) || false;
|
||||||
|
@ -43,7 +42,7 @@ export class ActiveEventList {
|
||||||
export class UserInputManager {
|
export class UserInputManager {
|
||||||
private KeysCode!: UserInputManagerDatum[];
|
private KeysCode!: UserInputManagerDatum[];
|
||||||
private Scene: GameScene;
|
private Scene: GameScene;
|
||||||
private isInputDisabled : boolean;
|
private isInputDisabled: boolean;
|
||||||
|
|
||||||
private joystick!: MobileJoystick;
|
private joystick!: MobileJoystick;
|
||||||
private joystickEvents = new ActiveEventList();
|
private joystickEvents = new ActiveEventList();
|
||||||
|
@ -61,8 +60,8 @@ export class UserInputManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
enableUserInputsStore.subscribe((enable) => {
|
enableUserInputsStore.subscribe((enable) => {
|
||||||
enable ? this.restoreControls() : this.disableControls()
|
enable ? this.restoreControls() : this.disableControls();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initVirtualJoystick() {
|
initVirtualJoystick() {
|
||||||
|
@ -91,39 +90,81 @@ export class UserInputManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initKeyBoardEvent(){
|
initKeyBoardEvent() {
|
||||||
this.KeysCode = [
|
this.KeysCode = [
|
||||||
{event: UserInputEvent.MoveUp, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z, false) },
|
{
|
||||||
{event: UserInputEvent.MoveUp, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W, false) },
|
event: UserInputEvent.MoveUp,
|
||||||
{event: UserInputEvent.MoveLeft, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q, false) },
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z, false),
|
||||||
{event: UserInputEvent.MoveLeft, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A, false) },
|
},
|
||||||
{event: UserInputEvent.MoveDown, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S, false) },
|
{
|
||||||
{event: UserInputEvent.MoveRight, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D, false) },
|
event: UserInputEvent.MoveUp,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W, false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.MoveLeft,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q, false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.MoveLeft,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A, false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.MoveDown,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S, false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.MoveRight,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D, false),
|
||||||
|
},
|
||||||
|
|
||||||
{event: UserInputEvent.MoveUp, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.UP, false) },
|
{
|
||||||
{event: UserInputEvent.MoveLeft, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT, false) },
|
event: UserInputEvent.MoveUp,
|
||||||
{event: UserInputEvent.MoveDown, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN, false) },
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.UP, false),
|
||||||
{event: UserInputEvent.MoveRight, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT, false) },
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.MoveLeft,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT, false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.MoveDown,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN, false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.MoveRight,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT, false),
|
||||||
|
},
|
||||||
|
|
||||||
{event: UserInputEvent.SpeedUp, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT, false) },
|
{
|
||||||
|
event: UserInputEvent.SpeedUp,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT, false),
|
||||||
|
},
|
||||||
|
|
||||||
{event: UserInputEvent.Interact, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E, false) },
|
{
|
||||||
{event: UserInputEvent.Interact, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE, false) },
|
event: UserInputEvent.Interact,
|
||||||
{event: UserInputEvent.Shout, keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F, false) },
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E, false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.Interact,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE, false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: UserInputEvent.Shout,
|
||||||
|
keyInstance: this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F, false),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
clearAllListeners(){
|
clearAllListeners() {
|
||||||
this.Scene.input.keyboard.removeAllListeners();
|
this.Scene.input.keyboard.removeAllListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: should we also disable the joystick?
|
//todo: should we also disable the joystick?
|
||||||
disableControls(){
|
disableControls() {
|
||||||
this.Scene.input.keyboard.removeAllKeys();
|
this.Scene.input.keyboard.removeAllKeys();
|
||||||
this.isInputDisabled = true;
|
this.isInputDisabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreControls(){
|
restoreControls() {
|
||||||
this.initKeyBoardEvent();
|
this.initKeyBoardEvent();
|
||||||
this.isInputDisabled = false;
|
this.isInputDisabled = false;
|
||||||
}
|
}
|
||||||
|
@ -155,7 +196,7 @@ export class UserInputManager {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
eventsMap.set(UserInputEvent.JoystickMove, this.joystickEvents.any());
|
eventsMap.set(UserInputEvent.JoystickMove, this.joystickEvents.any());
|
||||||
this.KeysCode.forEach(d => {
|
this.KeysCode.forEach((d) => {
|
||||||
if (d.keyInstance.isDown) {
|
if (d.keyInstance.isDown) {
|
||||||
eventsMap.set(d.event, true);
|
eventsMap.set(d.event, true);
|
||||||
}
|
}
|
||||||
|
@ -163,18 +204,18 @@ export class UserInputManager {
|
||||||
return eventsMap;
|
return eventsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
spaceEvent(callback : Function){
|
spaceEvent(callback: Function) {
|
||||||
this.Scene.input.keyboard.on('keyup-SPACE', (event: Event) => {
|
this.Scene.input.keyboard.on("keyup-SPACE", (event: Event) => {
|
||||||
callback();
|
callback();
|
||||||
return event;
|
return event;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addSpaceEventListner(callback : Function){
|
addSpaceEventListner(callback: Function) {
|
||||||
this.Scene.input.keyboard.addListener('keyup-SPACE', callback);
|
this.Scene.input.keyboard.addListener("keyup-SPACE", callback);
|
||||||
}
|
}
|
||||||
removeSpaceEventListner(callback : Function){
|
removeSpaceEventListner(callback: Function) {
|
||||||
this.Scene.input.keyboard.removeListener('keyup-SPACE', callback);
|
this.Scene.input.keyboard.removeListener("keyup-SPACE", callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
|
@ -182,8 +223,11 @@ export class UserInputManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private initMouseWheel() {
|
private initMouseWheel() {
|
||||||
this.Scene.input.on('wheel', (pointer: unknown, gameObjects: unknown, deltaX: number, deltaY: number, deltaZ: number) => {
|
this.Scene.input.on(
|
||||||
this.Scene.zoomByFactor(1 - deltaY / 53 * 0.1);
|
"wheel",
|
||||||
});
|
(pointer: unknown, gameObjects: unknown, deltaX: number, deltaY: number, deltaZ: number) => {
|
||||||
|
this.Scene.zoomByFactor(1 - (deltaY / 53) * 0.1);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
5
front/src/Stores/TypeMessageStore/BanMessageStore.ts
Normal file
5
front/src/Stores/TypeMessageStore/BanMessageStore.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const banMessageVisibleStore = writable(false);
|
||||||
|
|
||||||
|
export const banMessageContentStore = writable("");
|
5
front/src/Stores/TypeMessageStore/TextMessageStore.ts
Normal file
5
front/src/Stores/TypeMessageStore/TextMessageStore.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const textMessageVisibleStore = writable(false);
|
||||||
|
|
||||||
|
export const textMessageContentStore = writable("");
|
|
@ -9,8 +9,7 @@ section.section-input-send-text {
|
||||||
}
|
}
|
||||||
|
|
||||||
div.input-send-text{
|
div.input-send-text{
|
||||||
height: auto;
|
height: calc(100% - 100px);
|
||||||
max-height: calc(100% - 100px);
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
|
@ -20,5 +19,13 @@ section.section-input-send-text {
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ql-tooltip {
|
||||||
|
top: 40% !important;
|
||||||
|
left: 20% !important;
|
||||||
|
|
||||||
|
color: whitesmoke;
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
import "jasmine";
|
import "jasmine";
|
||||||
import {getRessourceDescriptor} from "../../../src/Phaser/Entity/PlayerTexturesLoadingManager";
|
import { getRessourceDescriptor } from "../../../src/Phaser/Entity/PlayerTexturesLoadingManager";
|
||||||
|
|
||||||
describe("getRessourceDescriptor()", () => {
|
describe("getRessourceDescriptor()", () => {
|
||||||
it(", if given a valid descriptor as parameter, should return it", () => {
|
it(", if given a valid descriptor as parameter, should return it", () => {
|
||||||
const desc = getRessourceDescriptor({name: 'name', img: 'url'});
|
const desc = getRessourceDescriptor({ name: "name", img: "url" });
|
||||||
expect(desc.name).toEqual('name');
|
expect(desc.name).toEqual("name");
|
||||||
expect(desc.img).toEqual('url');
|
expect(desc.img).toEqual("url");
|
||||||
});
|
});
|
||||||
|
|
||||||
it(", if given a string as parameter, should search through hardcoded values", () => {
|
it(", if given a string as parameter, should search through hardcoded values", () => {
|
||||||
const desc = getRessourceDescriptor('male1');
|
const desc = getRessourceDescriptor("male1");
|
||||||
expect(desc.name).toEqual('male1');
|
expect(desc.name).toEqual("male1");
|
||||||
expect(desc.img).toEqual("resources/characters/pipoya/Male 01-1.png");
|
expect(desc.img).toEqual("resources/characters/pipoya/Male 01-1.png");
|
||||||
});
|
});
|
||||||
|
|
||||||
it(", if given a string as parameter, should search through hardcoded values (bis)", () => {
|
it(", if given a string as parameter, should search through hardcoded values (bis)", () => {
|
||||||
const desc = getRessourceDescriptor('color_2');
|
const desc = getRessourceDescriptor("color_2");
|
||||||
expect(desc.name).toEqual('color_2');
|
expect(desc.name).toEqual("color_2");
|
||||||
expect(desc.img).toEqual("resources/customisation/character_color/character_color1.png");
|
expect(desc.img).toEqual("resources/customisation/character_color/character_color1.png");
|
||||||
});
|
});
|
||||||
|
|
||||||
it(", if given a descriptor without url as parameter, should search through hardcoded values", () => {
|
it(", if given a descriptor without url as parameter, should search through hardcoded values", () => {
|
||||||
const desc = getRessourceDescriptor({name: 'male1', img: ''});
|
const desc = getRessourceDescriptor({ name: "male1", img: "" });
|
||||||
expect(desc.name).toEqual('male1');
|
expect(desc.name).toEqual("male1");
|
||||||
expect(desc.img).toEqual("resources/characters/pipoya/Male 01-1.png");
|
expect(desc.img).toEqual("resources/characters/pipoya/Male 01-1.png");
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -3475,6 +3475,11 @@ lodash.clonedeep@^4.5.0:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||||
|
|
||||||
|
lodash.isequal@^4.5.0:
|
||||||
|
version "4.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||||
|
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
||||||
|
|
||||||
lodash.truncate@^4.4.2:
|
lodash.truncate@^4.4.2:
|
||||||
version "4.4.2"
|
version "4.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
||||||
|
@ -4497,6 +4502,13 @@ queue-typescript@^1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
linked-list-typescript "^1.0.11"
|
linked-list-typescript "^1.0.11"
|
||||||
|
|
||||||
|
quill-delta-to-html@^0.12.0:
|
||||||
|
version "0.12.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/quill-delta-to-html/-/quill-delta-to-html-0.12.0.tgz#ee572cfa208390d99d7646795358ddb81eaea17c"
|
||||||
|
integrity sha512-Yy6U2e7ov+ZlrFbj5/GbqOBCRjyNu+vuphy0Pk+7668zIMTVHJglZY2JNa++1/zkSiqptPBmP/CpsDzC4Wznsw==
|
||||||
|
dependencies:
|
||||||
|
lodash.isequal "^4.5.0"
|
||||||
|
|
||||||
quill-delta@^3.6.2:
|
quill-delta@^3.6.2:
|
||||||
version "3.6.3"
|
version "3.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032"
|
resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032"
|
||||||
|
|
159
maps/tests/LoadTileset/LoadTileset.json
Normal file
159
maps/tests/LoadTileset/LoadTileset.json
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[33, 34, 33, 34, 34, 34, 35, 37, 38, 39, 41, 42, 41, 42, 42, 42, 43, 45, 46, 47, 33, 34, 60, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 41, 42, 42, 42, 42, 42, 43, 45, 46, 47, 49, 50, 50, 50, 50, 50, 51, 53, 54, 55],
|
||||||
|
"height":10,
|
||||||
|
"id":2,
|
||||||
|
"name":"bottom",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":3,
|
||||||
|
"name":"openwebsite",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"https:\/\/fr.wikipedia.org\/wiki\/Wikip%C3%A9dia:Accueil_principal"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":4,
|
||||||
|
"nextobjectid":1,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"script",
|
||||||
|
"type":"string",
|
||||||
|
"value":"scriptTileset.js"
|
||||||
|
}],
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.7.0",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":8,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"tileset_dungeon.png",
|
||||||
|
"imageheight":256,
|
||||||
|
"imagewidth":256,
|
||||||
|
"margin":0,
|
||||||
|
"name":"Dungeon",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":64,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"id":36,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":37,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":38,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":44,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":45,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":46,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":52,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":53,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":54,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.6",
|
||||||
|
"width":10
|
||||||
|
}
|
BIN
maps/tests/LoadTileset/Yellow.jpg
Normal file
BIN
maps/tests/LoadTileset/Yellow.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
106
maps/tests/LoadTileset/Yellow.json
Normal file
106
maps/tests/LoadTileset/Yellow.json
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
{ "columns":11,
|
||||||
|
"image":"Yellow.jpg",
|
||||||
|
"imageheight":128,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"Yellow",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":44,
|
||||||
|
"tiledversion":"1.7.0",
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"id":0,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"name",
|
||||||
|
"type":"string",
|
||||||
|
"value":"Mur"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":2,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":11,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":12,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"name",
|
||||||
|
"type":"string",
|
||||||
|
"value":"sol"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"https:\/\/fr.wikipedia.org\/wiki\/Wikip%C3%A9dia:Accueil_principal"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":13,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":22,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":23,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":24,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"tileset",
|
||||||
|
"version":"1.6"
|
||||||
|
}
|
6
maps/tests/LoadTileset/scriptTileset.js
Normal file
6
maps/tests/LoadTileset/scriptTileset.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
WA.room.loadTileset("http://maps.workadventure.localhost/tests/LoadTileset/Yellow.json").then((firstgid) => {
|
||||||
|
WA.room.setTiles([
|
||||||
|
{x: 5, y: 5, tile: firstgid + 1, layer: 'bottom'},
|
||||||
|
{x: 5, y: 3, tile: 'sol', layer: 'bottom'}
|
||||||
|
]);
|
||||||
|
});
|
BIN
maps/tests/LoadTileset/tileset_dungeon.png
Normal file
BIN
maps/tests/LoadTileset/tileset_dungeon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
|
@ -123,9 +123,9 @@ message VariableWithTagMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
message PlayGlobalMessage {
|
message PlayGlobalMessage {
|
||||||
string id = 1;
|
string type = 1;
|
||||||
string type = 2;
|
string content = 2;
|
||||||
string message = 3;
|
bool broadcastToWorld = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message StopGlobalMessage {
|
message StopGlobalMessage {
|
||||||
|
@ -445,6 +445,7 @@ message AdminMessage {
|
||||||
message AdminRoomMessage {
|
message AdminRoomMessage {
|
||||||
string message = 1;
|
string message = 1;
|
||||||
string roomId = 2;
|
string roomId = 2;
|
||||||
|
string type = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A message sent by an administrator to absolutely everybody
|
// A message sent by an administrator to absolutely everybody
|
||||||
|
|
|
@ -123,6 +123,18 @@ class AdminApi {
|
||||||
return data.data;
|
return data.data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getUrlRoomsFromSameWorld(roomUrl: string): Promise<string[]> {
|
||||||
|
if (!ADMIN_API_URL) {
|
||||||
|
return Promise.reject(new Error("No admin backoffice set!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Axios.get(ADMIN_API_URL + "/api/room/sameWorld" + "?roomUrl=" + encodeURIComponent(roomUrl), {
|
||||||
|
headers: { Authorization: `${ADMIN_API_TOKEN}` },
|
||||||
|
}).then((data) => {
|
||||||
|
return data.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const adminApi = new AdminApi();
|
export const adminApi = new AdminApi();
|
||||||
|
|
|
@ -1,45 +1,45 @@
|
||||||
import { PusherRoom } from "../Model/PusherRoom";
|
import { PusherRoom } from "../Model/PusherRoom";
|
||||||
import { CharacterLayer, ExSocketInterface } from "../Model/Websocket/ExSocketInterface";
|
import { CharacterLayer, ExSocketInterface } from "../Model/Websocket/ExSocketInterface";
|
||||||
import {
|
import {
|
||||||
|
AdminMessage,
|
||||||
|
AdminPusherToBackMessage,
|
||||||
|
AdminRoomMessage,
|
||||||
|
BanMessage,
|
||||||
|
CharacterLayerMessage,
|
||||||
|
EmoteEventMessage,
|
||||||
|
EmotePromptMessage,
|
||||||
GroupDeleteMessage,
|
GroupDeleteMessage,
|
||||||
ItemEventMessage,
|
ItemEventMessage,
|
||||||
|
JoinRoomMessage,
|
||||||
PlayGlobalMessage,
|
PlayGlobalMessage,
|
||||||
|
PusherToBackMessage,
|
||||||
|
QueryJitsiJwtMessage,
|
||||||
|
RefreshRoomMessage,
|
||||||
|
ReportPlayerMessage,
|
||||||
RoomJoinedMessage,
|
RoomJoinedMessage,
|
||||||
|
SendJitsiJwtMessage,
|
||||||
|
ServerToAdminClientMessage,
|
||||||
ServerToClientMessage,
|
ServerToClientMessage,
|
||||||
SetPlayerDetailsMessage,
|
SetPlayerDetailsMessage,
|
||||||
SilentMessage,
|
SilentMessage,
|
||||||
SubMessage,
|
SubMessage,
|
||||||
ReportPlayerMessage,
|
UserJoinedRoomMessage,
|
||||||
UserLeftMessage,
|
UserLeftMessage,
|
||||||
|
UserLeftRoomMessage,
|
||||||
UserMovesMessage,
|
UserMovesMessage,
|
||||||
ViewportMessage,
|
ViewportMessage,
|
||||||
WebRtcSignalToServerMessage,
|
WebRtcSignalToServerMessage,
|
||||||
QueryJitsiJwtMessage,
|
|
||||||
SendJitsiJwtMessage,
|
|
||||||
JoinRoomMessage,
|
|
||||||
CharacterLayerMessage,
|
|
||||||
PusherToBackMessage,
|
|
||||||
WorldFullMessage,
|
|
||||||
WorldConnexionMessage,
|
WorldConnexionMessage,
|
||||||
AdminPusherToBackMessage,
|
|
||||||
ServerToAdminClientMessage,
|
|
||||||
EmoteEventMessage,
|
|
||||||
UserJoinedRoomMessage,
|
|
||||||
UserLeftRoomMessage,
|
|
||||||
AdminMessage,
|
|
||||||
BanMessage,
|
|
||||||
TokenExpiredMessage,
|
TokenExpiredMessage,
|
||||||
RefreshRoomMessage,
|
|
||||||
EmotePromptMessage,
|
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
|
WorldFullMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
||||||
import { ADMIN_API_URL, JITSI_ISS, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_URL, JITSI_ISS, JITSI_URL, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable";
|
||||||
import { adminApi } from "./AdminApi";
|
import { adminApi } from "./AdminApi";
|
||||||
import { emitInBatch } from "./IoSocketHelpers";
|
import { emitInBatch } from "./IoSocketHelpers";
|
||||||
import Jwt from "jsonwebtoken";
|
import Jwt from "jsonwebtoken";
|
||||||
import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
|
||||||
import { clientEventsEmitter } from "./ClientEventsEmitter";
|
import { clientEventsEmitter } from "./ClientEventsEmitter";
|
||||||
import { gaugeManager } from "./GaugeManager";
|
import { gaugeManager } from "./GaugeManager";
|
||||||
import { apiClientRepository } from "./ApiClientRepository";
|
import { apiClientRepository } from "./ApiClientRepository";
|
||||||
|
@ -389,17 +389,6 @@ export class SocketManager implements ZoneEventListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitPlayGlobalMessage(client: ExSocketInterface, playglobalmessage: PlayGlobalMessage) {
|
|
||||||
if (!client.tags.includes("admin")) {
|
|
||||||
//In case of xss injection, we just kill the connection.
|
|
||||||
throw "Client is not an admin!";
|
|
||||||
}
|
|
||||||
const pusherToBackMessage = new PusherToBackMessage();
|
|
||||||
pusherToBackMessage.setPlayglobalmessage(playglobalmessage);
|
|
||||||
|
|
||||||
client.backConnection.write(pusherToBackMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getWorlds(): Map<string, PusherRoom> {
|
public getWorlds(): Map<string, PusherRoom> {
|
||||||
return this.rooms;
|
return this.rooms;
|
||||||
}
|
}
|
||||||
|
@ -585,6 +574,7 @@ export class SocketManager implements ZoneEventListener {
|
||||||
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public emitTokenExpiredMessage(client: WebSocket) {
|
public emitTokenExpiredMessage(client: WebSocket) {
|
||||||
const errorMessage = new TokenExpiredMessage();
|
const errorMessage = new TokenExpiredMessage();
|
||||||
|
|
||||||
|
@ -620,6 +610,36 @@ export class SocketManager implements ZoneEventListener {
|
||||||
|
|
||||||
client.backConnection.write(pusherToBackMessage);
|
client.backConnection.write(pusherToBackMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async emitPlayGlobalMessage(
|
||||||
|
client: ExSocketInterface,
|
||||||
|
playGlobalMessageEvent: PlayGlobalMessage
|
||||||
|
): Promise<void> {
|
||||||
|
if (!client.tags.includes("admin")) {
|
||||||
|
throw "Client is not an admin!";
|
||||||
|
}
|
||||||
|
|
||||||
|
const clientRoomUrl = client.roomId;
|
||||||
|
let tabUrlRooms: string[];
|
||||||
|
|
||||||
|
if (playGlobalMessageEvent.getBroadcasttoworld()) {
|
||||||
|
tabUrlRooms = await adminApi.getUrlRoomsFromSameWorld(clientRoomUrl);
|
||||||
|
} else {
|
||||||
|
tabUrlRooms = [clientRoomUrl];
|
||||||
|
}
|
||||||
|
|
||||||
|
const roomMessage = new AdminRoomMessage();
|
||||||
|
roomMessage.setMessage(playGlobalMessageEvent.getContent());
|
||||||
|
roomMessage.setType(playGlobalMessageEvent.getType());
|
||||||
|
|
||||||
|
for (const roomUrl of tabUrlRooms) {
|
||||||
|
const apiRoom = await apiClientRepository.getClient(roomUrl);
|
||||||
|
roomMessage.setRoomid(roomUrl);
|
||||||
|
apiRoom.sendAdminMessageToRoom(roomMessage, (response) => {
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketManager = new SocketManager();
|
export const socketManager = new SocketManager();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue