Merge remote-tracking branch 'upstream/develop' into next
This commit is contained in:
commit
7d8e18f8c3
@ -16,6 +16,11 @@
|
|||||||
- We now create a GameObject.Text instead of GameObject.BitmapText
|
- We now create a GameObject.Text instead of GameObject.BitmapText
|
||||||
- now use the 'Press Start 2P' font family and added an outline
|
- now use the 'Press Start 2P' font family and added an outline
|
||||||
- As a result, we can now allow non-standard letters like french accents or chinese characters!
|
- As a result, we can now allow non-standard letters like french accents or chinese characters!
|
||||||
|
|
||||||
|
- Added the contact card feature. (@Kharhamel)
|
||||||
|
- Click on another player to see its contact info.
|
||||||
|
- Premium-only feature unfortunately. I need to find a way to make it available for all.
|
||||||
|
- If no contact data is found (either because the user is anonymous or because no admin backend), display an error card.
|
||||||
|
|
||||||
- Mobile support has been improved
|
- Mobile support has been improved
|
||||||
- WorkAdventure automatically sets the zoom level based on the viewport size to ensure a sensible size of the map is visible, whatever the viewport used
|
- WorkAdventure automatically sets the zoom level based on the viewport size to ensure a sensible size of the map is visible, whatever the viewport used
|
||||||
|
@ -89,7 +89,10 @@ export class GameRoom {
|
|||||||
public getUserByUuid(uuid: string): User|undefined {
|
public getUserByUuid(uuid: string): User|undefined {
|
||||||
return this.usersByUuid.get(uuid);
|
return this.usersByUuid.get(uuid);
|
||||||
}
|
}
|
||||||
|
public getUserById(id: number): User|undefined {
|
||||||
|
return this.users.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
public join(socket : UserSocket, joinRoomMessage: JoinRoomMessage): User {
|
public join(socket : UserSocket, joinRoomMessage: JoinRoomMessage): User {
|
||||||
const positionMessage = joinRoomMessage.getPositionmessage();
|
const positionMessage = joinRoomMessage.getPositionmessage();
|
||||||
if (positionMessage === undefined) {
|
if (positionMessage === undefined) {
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
JoinRoomMessage,
|
JoinRoomMessage,
|
||||||
PlayGlobalMessage,
|
PlayGlobalMessage,
|
||||||
PusherToBackMessage,
|
PusherToBackMessage,
|
||||||
QueryJitsiJwtMessage, RefreshRoomPromptMessage,
|
QueryJitsiJwtMessage, RefreshRoomPromptMessage, RequestVisitCardMessage,
|
||||||
ServerToAdminClientMessage,
|
ServerToAdminClientMessage,
|
||||||
ServerToClientMessage,
|
ServerToClientMessage,
|
||||||
SilentMessage,
|
SilentMessage,
|
||||||
@ -74,6 +74,8 @@ const roomManager: IRoomManagerServer = {
|
|||||||
socketManager.handleQueryJitsiJwtMessage(user, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
socketManager.handleQueryJitsiJwtMessage(user, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
||||||
} else if (message.hasEmotepromptmessage()){
|
} else if (message.hasEmotepromptmessage()){
|
||||||
socketManager.handleEmoteEventMessage(room, user, message.getEmotepromptmessage() as EmotePromptMessage);
|
socketManager.handleEmoteEventMessage(room, user, message.getEmotepromptmessage() as EmotePromptMessage);
|
||||||
|
} else if (message.hasRequestvisitcardmessage()) {
|
||||||
|
socketManager.handleRequestVisitCardMessage(room, user, message.getRequestvisitcardmessage() as RequestVisitCardMessage);
|
||||||
}else if (message.hasSendusermessage()) {
|
}else if (message.hasSendusermessage()) {
|
||||||
const sendUserMessage = message.getSendusermessage();
|
const sendUserMessage = message.getSendusermessage();
|
||||||
if(sendUserMessage !== undefined) {
|
if(sendUserMessage !== undefined) {
|
||||||
|
22
back/src/Services/AdminApi.ts
Normal file
22
back/src/Services/AdminApi.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
|
||||||
|
import Axios from "axios";
|
||||||
|
|
||||||
|
|
||||||
|
class AdminApi {
|
||||||
|
|
||||||
|
fetchVisitCardUrl(membershipUuid: string): Promise<string> {
|
||||||
|
if (ADMIN_API_URL) {
|
||||||
|
return Axios.get(ADMIN_API_URL + '/api/membership/'+membershipUuid,
|
||||||
|
{headers: {"Authorization": `${ADMIN_API_TOKEN}`}}
|
||||||
|
).then((res) => {
|
||||||
|
return res.data;
|
||||||
|
}).catch(() => {
|
||||||
|
return 'INVALID';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Promise.resolve('INVALID')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const adminApi = new AdminApi();
|
@ -27,7 +27,7 @@ import {
|
|||||||
WorldFullWarningMessage,
|
WorldFullWarningMessage,
|
||||||
UserLeftZoneMessage,
|
UserLeftZoneMessage,
|
||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
BanUserMessage, RefreshRoomMessage, EmotePromptMessage,
|
BanUserMessage, RefreshRoomMessage, EmotePromptMessage, RequestVisitCardMessage, VisitCardMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {User, UserSocket} from "../Model/User";
|
import {User, UserSocket} from "../Model/User";
|
||||||
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
@ -51,6 +51,7 @@ import {Zone} from "_Model/Zone";
|
|||||||
import Debug from "debug";
|
import Debug from "debug";
|
||||||
import {Admin} from "_Model/Admin";
|
import {Admin} from "_Model/Admin";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
|
import {adminApi} from "./AdminApi";
|
||||||
|
|
||||||
|
|
||||||
const debug = Debug('sockermanager');
|
const debug = Debug('sockermanager');
|
||||||
@ -769,6 +770,21 @@ export class SocketManager {
|
|||||||
emoteEventMessage.setActoruserid(user.id);
|
emoteEventMessage.setActoruserid(user.id);
|
||||||
room.emitEmoteEvent(user, emoteEventMessage);
|
room.emitEmoteEvent(user, emoteEventMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handleRequestVisitCardMessage(room: GameRoom, user: User, requestvisitcardmessage: RequestVisitCardMessage): Promise<void> {
|
||||||
|
const targetUser = room.getUserById(requestvisitcardmessage.getTargetuserid());
|
||||||
|
if (!targetUser) {
|
||||||
|
throw 'Could not find user for id '+requestvisitcardmessage.getTargetuserid();
|
||||||
|
}
|
||||||
|
const url = await adminApi.fetchVisitCardUrl(targetUser.uuid);
|
||||||
|
|
||||||
|
const visitCardMessage = new VisitCardMessage();
|
||||||
|
visitCardMessage.setUrl(url);
|
||||||
|
const clientMessage = new ServerToClientMessage();
|
||||||
|
clientMessage.setVisitcardmessage(visitCardMessage);
|
||||||
|
|
||||||
|
user.socket.write(clientMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketManager = new SocketManager();
|
export const socketManager = new SocketManager();
|
||||||
|
6
front/dist/index.tmpl.html
vendored
6
front/dist/index.tmpl.html
vendored
@ -112,12 +112,6 @@
|
|||||||
|
|
||||||
<div id="activeScreenSharing" class="active-screen-sharing active">
|
<div id="activeScreenSharing" class="active-screen-sharing active">
|
||||||
</div>
|
</div>
|
||||||
<audio id="audio-webrtc-in">
|
|
||||||
<source src="/resources/objects/webrtc-in.mp3" type="audio/mp3">
|
|
||||||
</audio>
|
|
||||||
<audio id="audio-webrtc-out">
|
|
||||||
<source src="/resources/objects/webrtc-out.mp3" type="audio/mp3">
|
|
||||||
</audio>
|
|
||||||
<audio id="report-message">
|
<audio id="report-message">
|
||||||
<source src="/resources/objects/report-message.mp3" type="audio/mp3">
|
<source src="/resources/objects/report-message.mp3" type="audio/mp3">
|
||||||
</audio>
|
</audio>
|
||||||
|
@ -44,7 +44,13 @@ export class TypeMessageExt implements TypeMessageInterface{
|
|||||||
mainSectionDiv.appendChild(div);
|
mainSectionDiv.appendChild(div);
|
||||||
|
|
||||||
const reportMessageAudio = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('report-message');
|
const reportMessageAudio = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('report-message');
|
||||||
reportMessageAudio.play();
|
// 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;
|
this.nbSecond = this.maxNbSecond;
|
||||||
setTimeout((c) => {
|
setTimeout((c) => {
|
||||||
|
@ -9,16 +9,20 @@
|
|||||||
import {selectCharacterSceneVisibleStore} from "../Stores/SelectCharacterStore";
|
import {selectCharacterSceneVisibleStore} from "../Stores/SelectCharacterStore";
|
||||||
import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte";
|
import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte";
|
||||||
import {customCharacterSceneVisibleStore} from "../Stores/CustomCharacterStore";
|
import {customCharacterSceneVisibleStore} from "../Stores/CustomCharacterStore";
|
||||||
|
import {errorStore} from "../Stores/ErrorStore";
|
||||||
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
|
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
|
||||||
import LoginScene from "./Login/LoginScene.svelte";
|
import LoginScene from "./Login/LoginScene.svelte";
|
||||||
import {loginSceneVisibleStore} from "../Stores/LoginSceneStore";
|
import {loginSceneVisibleStore} from "../Stores/LoginSceneStore";
|
||||||
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
|
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
|
||||||
|
import VisitCard from "./VisitCard/VisitCard.svelte";
|
||||||
|
import {requestVisitCardsStore} from "../Stores/GameStore";
|
||||||
|
|
||||||
import {Game} from "../Phaser/Game/Game";
|
import {Game} from "../Phaser/Game/Game";
|
||||||
import {helpCameraSettingsVisibleStore} from "../Stores/HelpCameraSettingsStore";
|
import {helpCameraSettingsVisibleStore} from "../Stores/HelpCameraSettingsStore";
|
||||||
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
|
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
|
||||||
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
||||||
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
||||||
|
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
</script>
|
</script>
|
||||||
@ -73,4 +77,12 @@
|
|||||||
<HelpCameraSettingsPopup game={ game }></HelpCameraSettingsPopup>
|
<HelpCameraSettingsPopup game={ game }></HelpCameraSettingsPopup>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $requestVisitCardsStore}
|
||||||
|
<VisitCard visitCardUrl={$requestVisitCardsStore}></VisitCard>
|
||||||
|
{/if}
|
||||||
|
{#if $errorStore.length > 0}
|
||||||
|
<div>
|
||||||
|
<ErrorDialog></ErrorDialog>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
48
front/src/Components/UI/ErrorDialog.svelte
Normal file
48
front/src/Components/UI/ErrorDialog.svelte
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {errorStore} from "../../Stores/ErrorStore";
|
||||||
|
|
||||||
|
function close(): boolean {
|
||||||
|
errorStore.clearMessages();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="error-div nes-container is-dark is-rounded" open>
|
||||||
|
<p class="nes-text is-error title">Error</p>
|
||||||
|
<div class="body">
|
||||||
|
{#each $errorStore as error}
|
||||||
|
<p>{error}</p>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="button-bar">
|
||||||
|
<button class="nes-btn is-error" on:click={close}>Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.error-div {
|
||||||
|
pointer-events: auto;
|
||||||
|
margin-top: 10vh;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
width: max-content;
|
||||||
|
max-width: 80vw;
|
||||||
|
|
||||||
|
.button-bar {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
max-height: 50vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
|
||||||
|
&.title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
64
front/src/Components/VisitCard/VisitCard.svelte
Normal file
64
front/src/Components/VisitCard/VisitCard.svelte
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import { fly } from 'svelte/transition';
|
||||||
|
import {requestVisitCardsStore} from "../../Stores/GameStore";
|
||||||
|
|
||||||
|
export let visitCardUrl: string;
|
||||||
|
|
||||||
|
function closeCard() {
|
||||||
|
requestVisitCardsStore.set(null);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.visitCard {
|
||||||
|
pointer-events: all;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: 515px;
|
||||||
|
margin-top: 200px;
|
||||||
|
|
||||||
|
.defaultCard {
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 2px black solid;
|
||||||
|
background-color: whitesmoke;
|
||||||
|
width: 500px;
|
||||||
|
|
||||||
|
header {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
border: 0;
|
||||||
|
width: 515px;
|
||||||
|
height: 270px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="visitCard" transition:fly="{{ y: -200, duration: 1000 }}">
|
||||||
|
{#if visitCardUrl === 'INVALID'}
|
||||||
|
<div class="defaultCard">
|
||||||
|
<header>
|
||||||
|
<h2>Sorry</h2>
|
||||||
|
<p style="font-style: italic;">This user doesn't have a contact card.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main style="padding: 5px; background-color: gray">
|
||||||
|
<p>Maybe he is offline, or this feature is deactivated.</p>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<iframe title="visitCardTitle" src={visitCardUrl}></iframe>
|
||||||
|
{/if}
|
||||||
|
<div class="buttonContainer">
|
||||||
|
<button class="nes-btn is-popUpElement" on:click={closeCard}>Close</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
@ -30,7 +30,7 @@ import {
|
|||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
EmotePromptMessage,
|
EmotePromptMessage,
|
||||||
SendUserMessage,
|
SendUserMessage,
|
||||||
BanUserMessage
|
BanUserMessage, RequestVisitCardMessage
|
||||||
} from "../Messages/generated/messages_pb"
|
} from "../Messages/generated/messages_pb"
|
||||||
|
|
||||||
import type {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
import type {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
||||||
@ -50,6 +50,7 @@ import {worldFullMessageStream} from "./WorldFullMessageStream";
|
|||||||
import {worldFullWarningStream} from "./WorldFullWarningStream";
|
import {worldFullWarningStream} from "./WorldFullWarningStream";
|
||||||
import {connectionManager} from "./ConnectionManager";
|
import {connectionManager} from "./ConnectionManager";
|
||||||
import {emoteEventStream} from "./EmoteEventStream";
|
import {emoteEventStream} from "./EmoteEventStream";
|
||||||
|
import {requestVisitCardsStore} from "../Stores/GameStore";
|
||||||
|
|
||||||
const manualPingDelay = 20000;
|
const manualPingDelay = 20000;
|
||||||
|
|
||||||
@ -203,6 +204,8 @@ export class RoomConnection implements RoomConnection {
|
|||||||
adminMessagesService.onSendusermessage(message.getBanusermessage() as BanUserMessage);
|
adminMessagesService.onSendusermessage(message.getBanusermessage() as BanUserMessage);
|
||||||
} else if (message.hasWorldfullwarningmessage()) {
|
} else if (message.hasWorldfullwarningmessage()) {
|
||||||
worldFullWarningStream.onMessage();
|
worldFullWarningStream.onMessage();
|
||||||
|
} else if (message.hasVisitcardmessage()) {
|
||||||
|
requestVisitCardsStore.set(message?.getVisitcardmessage()?.getUrl() as unknown as string);
|
||||||
} else if (message.hasRefreshroommessage()) {
|
} else if (message.hasRefreshroommessage()) {
|
||||||
//todo: implement a way to notify the user the room was refreshed.
|
//todo: implement a way to notify the user the room was refreshed.
|
||||||
} else {
|
} else {
|
||||||
@ -617,4 +620,14 @@ export class RoomConnection implements RoomConnection {
|
|||||||
|
|
||||||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public requestVisitCardUrl(targetUserId: number): void {
|
||||||
|
const message = new RequestVisitCardMessage();
|
||||||
|
message.setTargetuserid(targetUserId);
|
||||||
|
|
||||||
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
|
clientToServerMessage.setRequestvisitcardmessage(message);
|
||||||
|
|
||||||
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ import type {PointInterface} from "../../Connexion/ConnexionModels";
|
|||||||
import {Character} from "../Entity/Character";
|
import {Character} from "../Entity/Character";
|
||||||
import type {PlayerAnimationDirections} from "../Player/Animation";
|
import type {PlayerAnimationDirections} from "../Player/Animation";
|
||||||
|
|
||||||
|
export const playerClickedEvent = 'playerClickedEvent';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing the sprite of a remote player (a player that plays on another computer)
|
* Class representing the sprite of a remote player (a player that plays on another computer)
|
||||||
*/
|
*/
|
||||||
@ -25,6 +27,10 @@ export class RemotePlayer extends Character {
|
|||||||
|
|
||||||
//set data
|
//set data
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
|
||||||
|
this.on('pointerdown', () => {
|
||||||
|
this.emit(playerClickedEvent, this.userId);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePosition(position: PointInterface): void {
|
updatePosition(position: PointInterface): void {
|
||||||
@ -40,6 +46,6 @@ export class RemotePlayer extends Character {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isClickable(): boolean {
|
isClickable(): boolean {
|
||||||
return false; //todo: make remote players clickable if they are logged in.
|
return true; //todo: make remote players clickable if they are logged in.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import type {AddPlayerInterface} from "./AddPlayerInterface";
|
|||||||
import {PlayerAnimationDirections} from "../Player/Animation";
|
import {PlayerAnimationDirections} from "../Player/Animation";
|
||||||
import {PlayerMovement} from "./PlayerMovement";
|
import {PlayerMovement} from "./PlayerMovement";
|
||||||
import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator";
|
import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator";
|
||||||
import {RemotePlayer} from "../Entity/RemotePlayer";
|
import {playerClickedEvent, RemotePlayer} from "../Entity/RemotePlayer";
|
||||||
import {Queue} from 'queue-typescript';
|
import {Queue} from 'queue-typescript';
|
||||||
import {SimplePeer, UserSimplePeerInterface} from "../../WebRtc/SimplePeer";
|
import {SimplePeer, UserSimplePeerInterface} from "../../WebRtc/SimplePeer";
|
||||||
import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene";
|
import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene";
|
||||||
@ -184,6 +184,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
private createPromise: Promise<void>;
|
private createPromise: Promise<void>;
|
||||||
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
|
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
|
||||||
private iframeSubscriptionList! : Array<Subscription>;
|
private iframeSubscriptionList! : Array<Subscription>;
|
||||||
|
private peerStoreUnsubscribe!: () => void;
|
||||||
MapUrlFile: string;
|
MapUrlFile: string;
|
||||||
RoomId: string;
|
RoomId: string;
|
||||||
instance: string;
|
instance: string;
|
||||||
@ -253,6 +254,11 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
this.load.image(joystickBaseKey, joystickBaseImg);
|
this.load.image(joystickBaseKey, joystickBaseImg);
|
||||||
this.load.image(joystickThumbKey, joystickThumbImg);
|
this.load.image(joystickThumbKey, joystickThumbImg);
|
||||||
}
|
}
|
||||||
|
this.load.audio('audio-webrtc-in', '/resources/objects/webrtc-in.mp3');
|
||||||
|
this.load.audio('audio-webrtc-out', '/resources/objects/webrtc-out.mp3');
|
||||||
|
//this.load.audio('audio-report-message', '/resources/objects/report-message.mp3');
|
||||||
|
this.sound.pauseOnBlur = false;
|
||||||
|
|
||||||
this.load.on(FILE_LOAD_ERROR, (file: {src: string}) => {
|
this.load.on(FILE_LOAD_ERROR, (file: {src: string}) => {
|
||||||
// If we happen to be in HTTP and we are trying to load a URL in HTTPS only... (this happens only in dev environments)
|
// If we happen to be in HTTP and we are trying to load a URL in HTTPS only... (this happens only in dev environments)
|
||||||
if (window.location.protocol === 'http:' && file.src === this.MapUrlFile && file.src.startsWith('http:') && this.originalMapUrl === undefined) {
|
if (window.location.protocol === 'http:' && file.src === this.MapUrlFile && file.src.startsWith('http:') && this.originalMapUrl === undefined) {
|
||||||
@ -557,6 +563,21 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.emoteManager = new EmoteManager(this);
|
this.emoteManager = new EmoteManager(this);
|
||||||
|
|
||||||
|
let oldPeerNumber = 0;
|
||||||
|
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
||||||
|
const newPeerNumber = peers.size;
|
||||||
|
if (newPeerNumber > oldPeerNumber) {
|
||||||
|
this.sound.play('audio-webrtc-in', {
|
||||||
|
volume: 0.2
|
||||||
|
});
|
||||||
|
} else if (newPeerNumber < oldPeerNumber) {
|
||||||
|
this.sound.play('audio-webrtc-out', {
|
||||||
|
volume: 0.2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
oldPeerNumber = newPeerNumber;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1046,6 +1067,7 @@ ${escapedMessage}
|
|||||||
this.userInputManager.destroy();
|
this.userInputManager.destroy();
|
||||||
this.pinchManager?.destroy();
|
this.pinchManager?.destroy();
|
||||||
this.emoteManager.destroy();
|
this.emoteManager.destroy();
|
||||||
|
this.peerStoreUnsubscribe();
|
||||||
|
|
||||||
mediaManager.hideGameOverlay();
|
mediaManager.hideGameOverlay();
|
||||||
|
|
||||||
@ -1455,6 +1477,9 @@ ${escapedMessage}
|
|||||||
addPlayerData.companion,
|
addPlayerData.companion,
|
||||||
addPlayerData.companion !== null ? lazyLoadCompanionResource(this.load, addPlayerData.companion) : undefined
|
addPlayerData.companion !== null ? lazyLoadCompanionResource(this.load, addPlayerData.companion) : undefined
|
||||||
);
|
);
|
||||||
|
player.on(playerClickedEvent, (userID:number) => {
|
||||||
|
this.connection?.requestVisitCardUrl(userID);
|
||||||
|
})
|
||||||
this.MapPlayers.add(player);
|
this.MapPlayers.add(player);
|
||||||
this.MapPlayersByKey.set(player.userId, player);
|
this.MapPlayersByKey.set(player.userId, player);
|
||||||
player.updatePosition(addPlayerData.position);
|
player.updatePosition(addPlayerData.position);
|
||||||
|
@ -236,6 +236,9 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public onResize(): void {
|
public onResize(): void {
|
||||||
this.moveLayers();
|
this.moveLayers();
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||||||
|
|
||||||
update(time: number, delta: number): void {
|
update(time: number, delta: number): void {
|
||||||
if(this.lazyloadingAttempt){
|
if(this.lazyloadingAttempt){
|
||||||
this.createCurrentPlayer();
|
this.moveUser();
|
||||||
this.lazyloadingAttempt = false;
|
this.lazyloadingAttempt = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,6 @@ class WaScaleManager {
|
|||||||
|
|
||||||
public saveZoom(): void {
|
public saveZoom(): void {
|
||||||
this._saveZoom = this.hdpiManager.zoomModifier;
|
this._saveZoom = this.hdpiManager.zoomModifier;
|
||||||
console.log(this._saveZoom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public restoreZoom(): void{
|
public restoreZoom(): void{
|
||||||
|
33
front/src/Stores/ErrorStore.ts
Normal file
33
front/src/Stores/ErrorStore.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import {writable} from "svelte/store";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A store that contains a list of error messages to be displayed.
|
||||||
|
*/
|
||||||
|
function createErrorStore() {
|
||||||
|
const { subscribe, set, update } = writable<string[]>([]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
addErrorMessage: (e: string|Error): void => {
|
||||||
|
update((messages: string[]) => {
|
||||||
|
let message: string;
|
||||||
|
if (e instanceof Error) {
|
||||||
|
message = e.message;
|
||||||
|
} else {
|
||||||
|
message = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messages.includes(message)) {
|
||||||
|
messages.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearMessages: (): void => {
|
||||||
|
set([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const errorStore = createErrorStore();
|
8
front/src/Stores/Errors/BrowserTooOldError.ts
Normal file
8
front/src/Stores/Errors/BrowserTooOldError.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export class BrowserTooOldError extends Error {
|
||||||
|
static NAME = 'BrowserTooOldError';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super('Unable to access your camera or microphone. Your browser is too old. Please consider upgrading your browser or try using a recent version of Chrome.');
|
||||||
|
this.name = BrowserTooOldError.NAME;
|
||||||
|
}
|
||||||
|
}
|
8
front/src/Stores/Errors/WebviewOnOldIOS.ts
Normal file
8
front/src/Stores/Errors/WebviewOnOldIOS.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export class WebviewOnOldIOS extends Error {
|
||||||
|
static NAME = 'WebviewOnOldIOS';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super('Your iOS version cannot use video/audio in the browser unless you are using Safari. Please switch to Safari or upgrade iOS to 14.3 or above.');
|
||||||
|
this.name = WebviewOnOldIOS.NAME;
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
import { derived, writable, Writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
export const userMovingStore = writable(false);
|
export const userMovingStore = writable(false);
|
||||||
|
|
||||||
|
export const requestVisitCardsStore = writable<string|null>(null);
|
||||||
|
@ -4,6 +4,10 @@ import {localUserStore} from "../Connexion/LocalUserStore";
|
|||||||
import {ITiledMapGroupLayer, ITiledMapObjectLayer, ITiledMapTileLayer} from "../Phaser/Map/ITiledMap";
|
import {ITiledMapGroupLayer, ITiledMapObjectLayer, ITiledMapTileLayer} from "../Phaser/Map/ITiledMap";
|
||||||
import {userMovingStore} from "./GameStore";
|
import {userMovingStore} from "./GameStore";
|
||||||
import {HtmlUtils} from "../WebRtc/HtmlUtils";
|
import {HtmlUtils} from "../WebRtc/HtmlUtils";
|
||||||
|
import {BrowserTooOldError} from "./Errors/BrowserTooOldError";
|
||||||
|
import {errorStore} from "./ErrorStore";
|
||||||
|
import {isIOS} from "../WebRtc/DeviceUtils";
|
||||||
|
import {WebviewOnOldIOS} from "./Errors/WebviewOnOldIOS";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A store that contains the camera state requested by the user (on or off).
|
* A store that contains the camera state requested by the user (on or off).
|
||||||
@ -419,11 +423,17 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
|
|||||||
constraints
|
constraints
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else {
|
} else if (isIOS()) {
|
||||||
//throw new Error('Unable to access your camera or microphone. Your browser is too old.');
|
|
||||||
set({
|
set({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
error: new Error('Unable to access your camera or microphone. Your browser is too old. Please consider upgrading your browser or try using a recent version of Chrome.'),
|
error: new WebviewOnOldIOS(),
|
||||||
|
constraints
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
set({
|
||||||
|
type: 'error',
|
||||||
|
error: new BrowserTooOldError(),
|
||||||
constraints
|
constraints
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@ -594,3 +604,11 @@ microphoneListStore.subscribe((devices) => {
|
|||||||
audioConstraintStore.setDeviceId(undefined);
|
audioConstraintStore.setDeviceId(undefined);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
localStreamStore.subscribe(streamResult => {
|
||||||
|
if (streamResult.type === 'error') {
|
||||||
|
if (streamResult.error.name === BrowserTooOldError.NAME || streamResult.error.name === WebviewOnOldIOS.NAME) {
|
||||||
|
errorStore.addErrorMessage(streamResult.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -11,7 +11,7 @@ enum iframeStates {
|
|||||||
const cowebsiteDivId = 'cowebsite'; // the id of the whole container.
|
const cowebsiteDivId = 'cowebsite'; // the id of the whole container.
|
||||||
const cowebsiteMainDomId = 'cowebsite-main'; // the id of the parent div of the iframe.
|
const cowebsiteMainDomId = 'cowebsite-main'; // the id of the parent div of the iframe.
|
||||||
const cowebsiteAsideDomId = 'cowebsite-aside'; // the id of the parent div of the iframe.
|
const cowebsiteAsideDomId = 'cowebsite-aside'; // the id of the parent div of the iframe.
|
||||||
const cowebsiteCloseButtonId = 'cowebsite-close';
|
export const cowebsiteCloseButtonId = 'cowebsite-close';
|
||||||
const cowebsiteFullScreenButtonId = 'cowebsite-fullscreen';
|
const cowebsiteFullScreenButtonId = 'cowebsite-fullscreen';
|
||||||
const cowebsiteOpenFullScreenImageId = 'cowebsite-fullscreen-open';
|
const cowebsiteOpenFullScreenImageId = 'cowebsite-fullscreen-open';
|
||||||
const cowebsiteCloseFullScreenImageId = 'cowebsite-fullscreen-close';
|
const cowebsiteCloseFullScreenImageId = 'cowebsite-fullscreen-close';
|
||||||
@ -64,10 +64,15 @@ class CoWebsiteManager {
|
|||||||
|
|
||||||
this.initResizeListeners();
|
this.initResizeListeners();
|
||||||
|
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId).addEventListener('click', () => {
|
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
||||||
|
buttonCloseFrame.addEventListener('click', () => {
|
||||||
|
buttonCloseFrame.blur();
|
||||||
this.closeCoWebsite();
|
this.closeCoWebsite();
|
||||||
});
|
});
|
||||||
HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId).addEventListener('click', () => {
|
|
||||||
|
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
|
||||||
|
buttonFullScreenFrame.addEventListener('click', () => {
|
||||||
|
buttonFullScreenFrame.blur();
|
||||||
this.fullscreen();
|
this.fullscreen();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -152,7 +157,10 @@ class CoWebsiteManager {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.fire();
|
this.fire();
|
||||||
}, animationTime)
|
}, animationTime)
|
||||||
}).catch(() => this.closeCoWebsite());
|
}).catch((err) => {
|
||||||
|
console.error('Error loadCoWebsite => ', err);
|
||||||
|
this.closeCoWebsite()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,7 +174,10 @@ class CoWebsiteManager {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.fire();
|
this.fire();
|
||||||
}, animationTime);
|
}, animationTime);
|
||||||
}).catch(() => this.closeCoWebsite());
|
}).catch((err) => {
|
||||||
|
console.error('Error insertCoWebsite => ', err);
|
||||||
|
this.closeCoWebsite();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeCoWebsite(): Promise<void> {
|
public closeCoWebsite(): Promise<void> {
|
||||||
|
12
front/src/WebRtc/DeviceUtils.ts
Normal file
12
front/src/WebRtc/DeviceUtils.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export function isIOS(): boolean {
|
||||||
|
return [
|
||||||
|
'iPad Simulator',
|
||||||
|
'iPhone Simulator',
|
||||||
|
'iPod Simulator',
|
||||||
|
'iPad',
|
||||||
|
'iPhone',
|
||||||
|
'iPod'
|
||||||
|
].includes(navigator.platform)
|
||||||
|
// iPad on iOS 13 detection
|
||||||
|
|| (navigator.userAgent.includes("Mac") && "ontouchend" in document)
|
||||||
|
}
|
@ -35,7 +35,12 @@ export class HtmlUtils {
|
|||||||
const urlRegex = /(https?:\/\/[^\s]+)/g;
|
const urlRegex = /(https?:\/\/[^\s]+)/g;
|
||||||
text = HtmlUtils.escapeHtml(text);
|
text = HtmlUtils.escapeHtml(text);
|
||||||
return text.replace(urlRegex, (url: string) => {
|
return text.replace(urlRegex, (url: string) => {
|
||||||
return '<a href="' + url + '" target="_blank" style=":visited {color: white}">' + url + '</a>';
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.target = "_blank";
|
||||||
|
const text = document.createTextNode(url);
|
||||||
|
link.appendChild(text);
|
||||||
|
return link.outerHTML;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,12 +21,12 @@ export type ReportCallback = (message: string) => void;
|
|||||||
export type ShowReportCallBack = (userId: string, userName: string|undefined) => void;
|
export type ShowReportCallBack = (userId: string, userName: string|undefined) => void;
|
||||||
export type HelpCameraSettingsCallBack = () => void;
|
export type HelpCameraSettingsCallBack = () => void;
|
||||||
|
|
||||||
|
import {cowebsiteCloseButtonId} from "./CoWebsiteManager";
|
||||||
|
|
||||||
export class MediaManager {
|
export class MediaManager {
|
||||||
private remoteVideo: Map<string, HTMLVideoElement> = new Map<string, HTMLVideoElement>();
|
private remoteVideo: Map<string, HTMLVideoElement> = new Map<string, HTMLVideoElement>();
|
||||||
webrtcInAudio: HTMLAudioElement;
|
|
||||||
//FIX ME SOUNDMETER: check stalability of sound meter calculation
|
//FIX ME SOUNDMETER: check stalability of sound meter calculation
|
||||||
//mySoundMeterElement: HTMLDivElement;
|
//mySoundMeterElement: HTMLDivElement;
|
||||||
private webrtcOutAudio: HTMLAudioElement;
|
|
||||||
startScreenSharingCallBacks : Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
startScreenSharingCallBacks : Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
||||||
stopScreenSharingCallBacks : Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
|
stopScreenSharingCallBacks : Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
|
||||||
showReportModalCallBacks : Set<ShowReportCallBack> = new Set<ShowReportCallBack>();
|
showReportModalCallBacks : Set<ShowReportCallBack> = new Set<ShowReportCallBack>();
|
||||||
@ -44,11 +44,6 @@ export class MediaManager {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
this.webrtcInAudio = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('audio-webrtc-in');
|
|
||||||
this.webrtcOutAudio = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('audio-webrtc-out');
|
|
||||||
this.webrtcInAudio.volume = 0.2;
|
|
||||||
this.webrtcOutAudio.volume = 0.2;
|
|
||||||
|
|
||||||
this.pingCameraStatus();
|
this.pingCameraStatus();
|
||||||
|
|
||||||
//FIX ME SOUNDMETER: check stability of sound meter calculation
|
//FIX ME SOUNDMETER: check stability of sound meter calculation
|
||||||
@ -70,6 +65,7 @@ export class MediaManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let isScreenSharing = false;
|
||||||
screenSharingLocalStreamStore.subscribe((result) => {
|
screenSharingLocalStreamStore.subscribe((result) => {
|
||||||
if (result.type === 'error') {
|
if (result.type === 'error') {
|
||||||
console.error(result.error);
|
console.error(result.error);
|
||||||
@ -80,10 +76,14 @@ export class MediaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.stream !== null) {
|
if (result.stream !== null) {
|
||||||
|
isScreenSharing = true;
|
||||||
this.addScreenSharingActiveVideo('me', DivImportance.Normal);
|
this.addScreenSharingActiveVideo('me', DivImportance.Normal);
|
||||||
HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('screen-sharing-me').srcObject = result.stream;
|
HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('screen-sharing-me').srcObject = result.stream;
|
||||||
} else {
|
} else {
|
||||||
this.removeActiveScreenSharingVideo('me');
|
if (isScreenSharing) {
|
||||||
|
isScreenSharing = false;
|
||||||
|
this.removeActiveScreenSharingVideo('me');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -106,11 +106,14 @@ export class MediaManager {
|
|||||||
const gameOverlay = HtmlUtils.getElementByIdOrFail('game-overlay');
|
const gameOverlay = HtmlUtils.getElementByIdOrFail('game-overlay');
|
||||||
gameOverlay.classList.add('active');
|
gameOverlay.classList.add('active');
|
||||||
|
|
||||||
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail('cowebsite-close');
|
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
||||||
const functionTrigger = () => {
|
const functionTrigger = () => {
|
||||||
this.triggerCloseJitsiFrameButton();
|
this.triggerCloseJitsiFrameButton();
|
||||||
}
|
}
|
||||||
buttonCloseFrame.removeEventListener('click', functionTrigger);
|
buttonCloseFrame.removeEventListener('click', () => {
|
||||||
|
buttonCloseFrame.blur();
|
||||||
|
functionTrigger();
|
||||||
|
});
|
||||||
|
|
||||||
gameOverlayVisibilityStore.showGameOverlay();
|
gameOverlayVisibilityStore.showGameOverlay();
|
||||||
}
|
}
|
||||||
@ -119,17 +122,19 @@ export class MediaManager {
|
|||||||
const gameOverlay = HtmlUtils.getElementByIdOrFail('game-overlay');
|
const gameOverlay = HtmlUtils.getElementByIdOrFail('game-overlay');
|
||||||
gameOverlay.classList.remove('active');
|
gameOverlay.classList.remove('active');
|
||||||
|
|
||||||
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail('cowebsite-close');
|
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
||||||
const functionTrigger = () => {
|
const functionTrigger = () => {
|
||||||
this.triggerCloseJitsiFrameButton();
|
this.triggerCloseJitsiFrameButton();
|
||||||
}
|
}
|
||||||
buttonCloseFrame.addEventListener('click', functionTrigger);
|
buttonCloseFrame.addEventListener('click', () => {
|
||||||
|
buttonCloseFrame.blur();
|
||||||
|
functionTrigger();
|
||||||
|
});
|
||||||
|
|
||||||
gameOverlayVisibilityStore.hideGameOverlay();
|
gameOverlayVisibilityStore.hideGameOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
addActiveVideo(user: UserSimplePeerInterface, userName: string = ""){
|
addActiveVideo(user: UserSimplePeerInterface, userName: string = ""){
|
||||||
this.webrtcInAudio.play();
|
|
||||||
const userId = ''+user.userId
|
const userId = ''+user.userId
|
||||||
|
|
||||||
userName = userName.toUpperCase();
|
userName = userName.toUpperCase();
|
||||||
@ -145,7 +150,7 @@ export class MediaManager {
|
|||||||
<img title="report this user" src="resources/logos/report.svg">
|
<img title="report this user" src="resources/logos/report.svg">
|
||||||
<span>Report/Block</span>
|
<span>Report/Block</span>
|
||||||
</button>
|
</button>
|
||||||
<video id="${userId}" autoplay></video>
|
<video id="${userId}" autoplay playsinline></video>
|
||||||
<img src="resources/logos/blockSign.svg" id="blocking-${userId}" class="block-logo">
|
<img src="resources/logos/blockSign.svg" id="blocking-${userId}" class="block-logo">
|
||||||
<div id="soundMeter-${userId}" class="sound-progress">
|
<div id="soundMeter-${userId}" class="sound-progress">
|
||||||
<span></span>
|
<span></span>
|
||||||
@ -182,7 +187,7 @@ export class MediaManager {
|
|||||||
userId = this.getScreenSharingId(userId);
|
userId = this.getScreenSharingId(userId);
|
||||||
const html = `
|
const html = `
|
||||||
<div id="div-${userId}" class="video-container">
|
<div id="div-${userId}" class="video-container">
|
||||||
<video id="${userId}" autoplay></video>
|
<video id="${userId}" autoplay playsinline></video>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -277,10 +282,6 @@ export class MediaManager {
|
|||||||
this.removeActiveVideo(this.getScreenSharingId(userId))
|
this.removeActiveVideo(this.getScreenSharingId(userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
playWebrtcOutSound(): void {
|
|
||||||
this.webrtcOutAudio.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
isConnecting(userId: string): void {
|
isConnecting(userId: string): void {
|
||||||
const connectingSpinnerDiv = this.getSpinner(userId);
|
const connectingSpinnerDiv = this.getSpinner(userId);
|
||||||
if (connectingSpinnerDiv === null) {
|
if (connectingSpinnerDiv === null) {
|
||||||
|
@ -246,7 +246,6 @@ export class SimplePeer {
|
|||||||
* This is triggered twice. Once by the server, and once by a remote client disconnecting
|
* This is triggered twice. Once by the server, and once by a remote client disconnecting
|
||||||
*/
|
*/
|
||||||
private closeConnection(userId : number) {
|
private closeConnection(userId : number) {
|
||||||
mediaManager.playWebrtcOutSound();
|
|
||||||
try {
|
try {
|
||||||
const peer = this.PeerConnectionArray.get(userId);
|
const peer = this.PeerConnectionArray.get(userId);
|
||||||
if (peer === undefined) {
|
if (peer === undefined) {
|
||||||
|
@ -1146,6 +1146,10 @@ div.modal-report-user{
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.discussion .messages .message p a:visited{
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.discussion .send-message{
|
.discussion .send-message{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 45px;
|
bottom: 45px;
|
||||||
|
@ -75,6 +75,14 @@ message EmoteEventMessage {
|
|||||||
string emote = 2;
|
string emote = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message RequestVisitCardMessage {
|
||||||
|
int32 targetUserId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message VisitCardMessage {
|
||||||
|
string url = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message QueryJitsiJwtMessage {
|
message QueryJitsiJwtMessage {
|
||||||
string jitsiRoom = 1;
|
string jitsiRoom = 1;
|
||||||
string tag = 2; // FIXME: rather than reading the tag from the query, we should read it from the current map!
|
string tag = 2; // FIXME: rather than reading the tag from the query, we should read it from the current map!
|
||||||
@ -94,6 +102,7 @@ message ClientToServerMessage {
|
|||||||
ReportPlayerMessage reportPlayerMessage = 11;
|
ReportPlayerMessage reportPlayerMessage = 11;
|
||||||
QueryJitsiJwtMessage queryJitsiJwtMessage = 12;
|
QueryJitsiJwtMessage queryJitsiJwtMessage = 12;
|
||||||
EmotePromptMessage emotePromptMessage = 13;
|
EmotePromptMessage emotePromptMessage = 13;
|
||||||
|
RequestVisitCardMessage requestVisitCardMessage = 14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,6 +268,7 @@ message ServerToClientMessage {
|
|||||||
RefreshRoomMessage refreshRoomMessage = 17;
|
RefreshRoomMessage refreshRoomMessage = 17;
|
||||||
WorldConnexionMessage worldConnexionMessage = 18;
|
WorldConnexionMessage worldConnexionMessage = 18;
|
||||||
EmoteEventMessage emoteEventMessage = 19;
|
EmoteEventMessage emoteEventMessage = 19;
|
||||||
|
VisitCardMessage visitCardMessage = 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,6 +340,7 @@ message PusherToBackMessage {
|
|||||||
SendUserMessage sendUserMessage = 12;
|
SendUserMessage sendUserMessage = 12;
|
||||||
BanUserMessage banUserMessage = 13;
|
BanUserMessage banUserMessage = 13;
|
||||||
EmotePromptMessage emotePromptMessage = 14;
|
EmotePromptMessage emotePromptMessage = 14;
|
||||||
|
RequestVisitCardMessage requestVisitCardMessage = 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,12 @@ import {
|
|||||||
PlayGlobalMessage,
|
PlayGlobalMessage,
|
||||||
ReportPlayerMessage,
|
ReportPlayerMessage,
|
||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
QueryJitsiJwtMessage, SendUserMessage, ServerToClientMessage, CompanionMessage, EmotePromptMessage
|
QueryJitsiJwtMessage,
|
||||||
|
SendUserMessage,
|
||||||
|
ServerToClientMessage,
|
||||||
|
CompanionMessage,
|
||||||
|
EmotePromptMessage,
|
||||||
|
RequestVisitCardMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
||||||
import {TemplatedApp} from "uWebSockets.js"
|
import {TemplatedApp} from "uWebSockets.js"
|
||||||
@ -333,6 +338,9 @@ export class IoSocketController {
|
|||||||
socketManager.handleQueryJitsiJwtMessage(client, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
socketManager.handleQueryJitsiJwtMessage(client, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
||||||
} else if (message.hasEmotepromptmessage()){
|
} else if (message.hasEmotepromptmessage()){
|
||||||
socketManager.handleEmotePromptMessage(client, message.getEmotepromptmessage() as EmotePromptMessage);
|
socketManager.handleEmotePromptMessage(client, message.getEmotepromptmessage() as EmotePromptMessage);
|
||||||
|
} else if (message.hasRequestvisitcardmessage()) {
|
||||||
|
|
||||||
|
socketManager.handleRequestVisitCardMessage(client, message.getRequestvisitcardmessage() as RequestVisitCardMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ok is false if backpressure was built up, wait for drain */
|
/* Ok is false if backpressure was built up, wait for drain */
|
||||||
|
@ -24,7 +24,13 @@ import {
|
|||||||
AdminPusherToBackMessage,
|
AdminPusherToBackMessage,
|
||||||
ServerToAdminClientMessage,
|
ServerToAdminClientMessage,
|
||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
UserJoinedRoomMessage, UserLeftRoomMessage, AdminMessage, BanMessage, RefreshRoomMessage, EmotePromptMessage
|
UserJoinedRoomMessage,
|
||||||
|
UserLeftRoomMessage,
|
||||||
|
AdminMessage,
|
||||||
|
BanMessage,
|
||||||
|
RefreshRoomMessage,
|
||||||
|
EmotePromptMessage,
|
||||||
|
RequestVisitCardMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
import {JITSI_ISS, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
|
import {JITSI_ISS, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
|
||||||
@ -294,6 +300,7 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
throw 'reported socket user not found';
|
throw 'reported socket user not found';
|
||||||
}
|
}
|
||||||
//TODO report user on admin application
|
//TODO report user on admin application
|
||||||
|
//todo: move to back because this fail if the reported player is in another pusher.
|
||||||
await adminApi.reportPlayer(reportedSocket.userUuid, reportPlayerMessage.getReportcomment(), client.userUuid, client.roomId.split('/')[2])
|
await adminApi.reportPlayer(reportedSocket.userUuid, reportPlayerMessage.getReportcomment(), client.userUuid, client.roomId.split('/')[2])
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('An error occurred on "handleReportMessage"');
|
console.error('An error occurred on "handleReportMessage"');
|
||||||
@ -597,6 +604,13 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
|
|
||||||
client.backConnection.write(pusherToBackMessage);
|
client.backConnection.write(pusherToBackMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleRequestVisitCardMessage(client: ExSocketInterface, requestVisitCardMessage: RequestVisitCardMessage) {
|
||||||
|
const pusherToBackMessage = new PusherToBackMessage();
|
||||||
|
pusherToBackMessage.setRequestvisitcardmessage(requestVisitCardMessage);
|
||||||
|
|
||||||
|
client.backConnection.write(pusherToBackMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketManager = new SocketManager();
|
export const socketManager = new SocketManager();
|
||||||
|
Loading…
Reference in New Issue
Block a user