Merge branch 'develop' of github.com:thecodingmachine/workadventure into develop

This commit is contained in:
_Bastler
2022-02-12 13:36:30 +01:00
25 changed files with 642 additions and 382 deletions
+3 -2
View File
@@ -73,7 +73,7 @@
"zod": "^3.11.6"
},
"scripts": {
"start": "run-p templater serve svelte-check-watch typesafe-i18n",
"start": "run-p templater serve svelte-check-watch typesafe-i18n-watch",
"templater": "cross-env ./templater.sh",
"serve": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" webpack serve --open",
"build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production webpack",
@@ -86,7 +86,8 @@
"svelte-check": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore\"",
"pretty": "yarn prettier --write 'src/**/*.{ts,svelte}'",
"pretty-check": "yarn prettier --check 'src/**/*.{ts,svelte}'",
"typesafe-i18n": "typesafe-i18n --no-watch"
"typesafe-i18n": "typesafe-i18n --no-watch",
"typesafe-i18n-watch": "typesafe-i18n"
},
"lint-staged": {
"*.svelte": [
@@ -2,9 +2,10 @@
import { onMount } from "svelte";
import { ICON_URL } from "../../Enum/EnvironmentVariable";
import { coWebsitesNotAsleep, mainCoWebsite, jitsiCoWebsite } from "../../Stores/CoWebsiteStore";
import { mainCoWebsite } from "../../Stores/CoWebsiteStore";
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
@@ -15,10 +16,10 @@
let icon: HTMLImageElement;
let iconLoaded = false;
let state = coWebsite.getStateSubscriber();
let isJitsi: boolean = false;
let isJitsi: boolean = coWebsite instanceof JitsiCoWebsite;
const mainState = coWebsiteManager.getMainStateSubscriber();
onMount(() => {
isJitsi = Boolean($jitsiCoWebsite && $jitsiCoWebsite.getId() === coWebsite.getId());
icon.src = isJitsi
? "/resources/logos/meet.svg"
: `${ICON_URL}/icon?url=${coWebsite.getUrl().hostname}&size=64..96..256&fallback_icon_color=14304c`;
@@ -33,20 +34,23 @@
coWebsiteManager.goToMain(coWebsite);
} else if ($mainCoWebsite) {
if ($mainCoWebsite.getId() === coWebsite.getId()) {
const coWebsites = $coWebsitesNotAsleep;
const newMain = $highlightedEmbedScreen ?? coWebsites.length > 1 ? coWebsites[1] : undefined;
if (newMain && newMain.getId() !== $mainCoWebsite.getId()) {
coWebsiteManager.goToMain(newMain);
} else if (coWebsiteManager.getMainState() === iframeStates.closed) {
if (coWebsiteManager.getMainState() === iframeStates.closed) {
coWebsiteManager.displayMain();
} else if ($highlightedEmbedScreen?.type === "cowebsite") {
coWebsiteManager.goToMain($highlightedEmbedScreen.embed);
} else {
coWebsiteManager.hideMain();
}
} else {
highlightedEmbedScreen.toggleHighlight({
type: "cowebsite",
embed: coWebsite,
});
if (coWebsiteManager.getMainState() === iframeStates.closed) {
coWebsiteManager.goToMain(coWebsite);
coWebsiteManager.displayMain();
} else {
highlightedEmbedScreen.toggleHighlight({
type: "cowebsite",
embed: coWebsite,
});
}
}
}
@@ -64,7 +68,10 @@
let isHighlight: boolean = false;
let isMain: boolean = false;
$: {
isMain = $mainCoWebsite !== undefined && $mainCoWebsite.getId() === coWebsite.getId();
isMain =
$mainState === iframeStates.opened &&
$mainCoWebsite !== undefined &&
$mainCoWebsite.getId() === coWebsite.getId();
isHighlight =
$highlightedEmbedScreen !== null &&
$highlightedEmbedScreen.type === "cowebsite" &&
@@ -212,7 +219,8 @@
}
&:not(.vertical) {
animation: bounce 0.35s ease 6 alternate;
transition: all 300ms;
transform: translateY(0px);
}
&.vertical {
@@ -233,7 +241,7 @@
&.displayed {
&:not(.vertical) {
animation: activeThumbnail 300ms ease-in 0s forwards;
transform: translateY(-15px);
}
}
@@ -262,16 +270,6 @@
}
}
@keyframes activeThumbnail {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-15px);
}
}
@keyframes bounce {
from {
transform: translateY(0);
+82 -22
View File
@@ -1,5 +1,12 @@
<script lang="ts">
import LL from "../../i18n/i18n-svelte";
import { gameManager } from "../../Phaser/Game/GameManager";
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
let entryPoint: string = $startLayerNamesStore[0];
let walkAutomatically: boolean = false;
const currentPlayer = gameManager.getCurrentGameScene().CurrentPlayer;
const playerPos = { x: Math.floor(currentPlayer.x), y: Math.floor(currentPlayer.y) };
function copyLink() {
const input: HTMLInputElement = document.getElementById("input-share-link") as HTMLInputElement;
@@ -8,8 +15,23 @@
document.execCommand("copy");
}
function getLink() {
return `${location.origin}${location.pathname}#${entryPoint}${
walkAutomatically ? `&moveTo=${playerPos.x},${playerPos.y}` : ""
}`;
}
function updateInputFieldValue() {
const input = document.getElementById("input-share-link");
if (input) {
(input as HTMLInputElement).value = getLink();
}
}
let canShare = navigator.share !== undefined;
async function shareLink() {
const shareData = { url: location.toString() };
const shareData = { url: getLink() };
try {
await navigator.share(shareData);
@@ -22,16 +44,43 @@
<div class="guest-main">
<section class="container-overflow">
<section class="share-url not-mobile">
<h3>{$LL.menu.invite.description()}</h3>
<input type="text" readonly id="input-share-link" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={copyLink}>{$LL.menu.invite.copy()}</button>
</section>
<section class="is-mobile">
<h3>{$LL.menu.invite.description()}</h3>
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={shareLink}>{$LL.menu.invite.share()}</button>
{#if !canShare}
<section class="share-url not-mobile">
<h3>{$LL.menu.invite.description()}</h3>
<input type="text" readonly id="input-share-link" class="link-url" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={copyLink}>{$LL.menu.invite.copy()}</button>
</section>
{:else}
<section class="is-mobile">
<h3>{$LL.menu.invite.description()}</h3>
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={shareLink}>{$LL.menu.invite.share()}</button>
</section>
{/if}
<h3>Select an entry point</h3>
<section class="nes-select is-dark starting-points">
<select
bind:value={entryPoint}
on:blur={() => {
updateInputFieldValue();
}}
>
{#each $startLayerNamesStore as entryPointName}
<option value={entryPointName}>{entryPointName}</option>
{/each}
</select>
</section>
<label>
<input
type="checkbox"
class="nes-checkbox is-dark"
bind:checked={walkAutomatically}
on:change={() => {
updateInputFieldValue();
}}
/>
<span>{$LL.menu.invite.walk_automatically_to_position()}</span>
</label>
</section>
</div>
@@ -39,14 +88,27 @@
@import "../../../style/breakpoints.scss";
div.guest-main {
width: 50%;
margin-left: auto;
margin-right: auto;
height: calc(100% - 56px);
text-align: center;
input.link-url {
width: calc(100% - 200px);
}
.starting-points {
width: 80%;
}
section {
margin-bottom: 50px;
}
section.nes-select select:focus {
outline: none;
}
section.container-overflow {
height: 100%;
margin: 0;
@@ -55,25 +117,23 @@
}
section.is-mobile {
display: none;
display: block;
text-align: center;
margin-bottom: 20px;
}
}
@include media-breakpoint-up(md) {
div.guest-main {
section.share-url.not-mobile {
display: none;
}
section.is-mobile {
display: block;
text-align: center;
margin-bottom: 20px;
}
section.container-overflow {
height: calc(100% - 120px);
}
}
}
@include media-breakpoint-up(lg) {
div.guest-main {
width: 100%;
}
}
</style>
+4
View File
@@ -336,6 +336,10 @@ export class GameMap {
throw new Error("No possible position found");
}
public getObjectWithName(name: string): ITiledMapObject | undefined {
return this.tiledObjects.find((object) => object.name === name);
}
private getLayersByKey(key: number): Array<ITiledMapLayer> {
return this.flatLayers.filter((flatLayer) => flatLayer.type === "tilelayer" && flatLayer.data[key] !== 0);
}
@@ -10,7 +10,13 @@ import type { ITiledMapLayer } from "../Map/ITiledMap";
import { GameMapProperties } from "./GameMapProperties";
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
import { LL } from "../../i18n/i18n-svelte";
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
import { JITSI_PRIVATE_MODE, JITSI_URL } from "../../Enum/EnvironmentVariable";
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
import { audioManagerFileStore, audioManagerVisibilityStore } from "../../Stores/AudioManagerStore";
import { iframeListener } from "../../Api/IframeListener";
import { Room } from "../../Connexion/Room";
import LL from "../../i18n/i18n-svelte";
interface OpenCoWebsite {
actionId: string;
@@ -24,6 +30,7 @@ export class GameMapPropertiesListener {
constructor(private scene: GameScene, private gameMap: GameMap) {}
register() {
// Website on new tab
this.gameMap.onPropertyChange(GameMapProperties.OPEN_TAB, (newValue, oldValue, allProps) => {
if (newValue === undefined) {
layoutManagerActionStore.removeAction("openTab");
@@ -34,7 +41,7 @@ export class GameMapPropertiesListener {
if (forceTrigger || openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
let message = allProps.get(GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE);
if (message === undefined) {
message = get(LL).message.openWebsiteTabTrigger();
message = get(LL).trigger.newTab();
}
layoutManagerActionStore.addAction({
uuid: "openTab",
@@ -49,6 +56,129 @@ export class GameMapPropertiesListener {
}
});
// Jitsi room
this.gameMap.onPropertyChange(GameMapProperties.JITSI_ROOM, (newValue, oldValue, allProps) => {
if (newValue === undefined) {
layoutManagerActionStore.removeAction("jitsi");
coWebsiteManager.getCoWebsites().forEach((coWebsite) => {
if (coWebsite instanceof JitsiCoWebsite) {
coWebsiteManager.closeCoWebsite(coWebsite);
}
});
} else {
const openJitsiRoomFunction = () => {
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.scene.instance);
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
const adminTag = allProps.get(GameMapProperties.JITSI_ADMIN_ROOM_TAG) as string | undefined;
this.scene.connection?.emitQueryJitsiJwtMessage(roomName, adminTag);
} else {
let domain = jitsiUrl || JITSI_URL;
if (domain === undefined) {
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
}
if (domain.substring(0, 7) !== "http://" && domain.substring(0, 8) !== "https://") {
domain = `${location.protocol}//${domain}`;
}
const coWebsite = new JitsiCoWebsite(new URL(domain), false, undefined, undefined, false);
coWebsiteManager.addCoWebsiteToStore(coWebsite, 0);
this.scene.initialiseJitsi(coWebsite, roomName, undefined);
}
layoutManagerActionStore.removeAction("jitsi");
};
const jitsiTriggerValue = allProps.get(GameMapProperties.JITSI_TRIGGER);
const forceTrigger = localUserStore.getForceCowebsiteTrigger();
if (forceTrigger || jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
let message = allProps.get(GameMapProperties.JITSI_TRIGGER_MESSAGE);
if (message === undefined) {
message = get(LL).trigger.jitsiRoom();
}
layoutManagerActionStore.addAction({
uuid: "jitsi",
type: "message",
message: message,
callback: () => openJitsiRoomFunction(),
userInputManager: this.scene.userInputManager,
});
} else {
openJitsiRoomFunction();
}
}
});
this.gameMap.onPropertyChange(GameMapProperties.EXIT_SCENE_URL, (newValue, oldValue) => {
if (newValue) {
this.scene
.onMapExit(
Room.getRoomPathFromExitSceneUrl(
newValue as string,
window.location.toString(),
this.scene.MapUrlFile
)
)
.catch((e) => console.error(e));
} else {
setTimeout(() => {
layoutManagerActionStore.removeAction("roomAccessDenied");
}, 2000);
}
});
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
if (newValue) {
this.scene
.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString()))
.catch((e) => console.error(e));
} else {
setTimeout(() => {
layoutManagerActionStore.removeAction("roomAccessDenied");
}, 2000);
}
});
this.gameMap.onPropertyChange(GameMapProperties.SILENT, (newValue, oldValue) => {
if (newValue === undefined || newValue === false || newValue === "") {
this.scene.connection?.setSilent(false);
this.scene.CurrentPlayer.noSilent();
} else {
this.scene.connection?.setSilent(true);
this.scene.CurrentPlayer.isSilent();
}
});
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO, (newValue, oldValue, allProps) => {
const volume = allProps.get(GameMapProperties.AUDIO_VOLUME) as number | undefined;
const loop = allProps.get(GameMapProperties.AUDIO_LOOP) as boolean | undefined;
newValue === undefined
? audioManagerFileStore.unloadAudio()
: audioManagerFileStore.playAudio(newValue, this.scene.getMapDirUrl(), volume, loop);
audioManagerVisibilityStore.set(!(newValue === undefined));
});
// TODO: This legacy property should be removed at some point
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO_LOOP, (newValue, oldValue) => {
newValue === undefined
? audioManagerFileStore.unloadAudio()
: audioManagerFileStore.playAudio(newValue, this.scene.getMapDirUrl(), undefined, true);
audioManagerVisibilityStore.set(!(newValue === undefined));
});
// TODO: Legacy functionnality replace by layer change
this.gameMap.onPropertyChange(GameMapProperties.ZONE, (newValue, oldValue) => {
if (oldValue) {
iframeListener.sendLeaveEvent(oldValue as string);
}
if (newValue) {
iframeListener.sendEnterEvent(newValue as string);
}
});
// Open a new co-website by the property.
this.gameMap.onEnterLayer((newLayers) => {
const handler = () => {
@@ -136,7 +266,7 @@ export class GameMapPropertiesListener {
websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON
) {
if (!websiteTriggerMessageProperty) {
websiteTriggerMessageProperty = get(LL).message.openWebsiteTrigger();
websiteTriggerMessageProperty = get(LL).trigger.cowebsite();
}
this.coWebsitesActionTriggerByLayer.set(layer, actionId);
+48 -154
View File
@@ -20,15 +20,8 @@ import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
import { iframeListener } from "../../Api/IframeListener";
import {
DEBUG_MODE,
JITSI_PRIVATE_MODE,
JITSI_URL,
MAX_PER_GROUP,
POSITION_DELAY,
} from "../../Enum/EnvironmentVariable";
import { DEBUG_MODE, JITSI_URL, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
import { Room } from "../../Connexion/Room";
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
@@ -82,7 +75,7 @@ import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
import { userIsAdminStore } from "../../Stores/GameStore";
import { contactPageStore } from "../../Stores/MenuStore";
import type { WasCameraUpdatedEvent } from "../../Api/Events/WasCameraUpdatedEvent";
import { audioManagerFileStore, audioManagerVisibilityStore } from "../../Stores/AudioManagerStore";
import { audioManagerFileStore } from "../../Stores/AudioManagerStore";
import EVENT_TYPE = Phaser.Scenes.Events;
import Texture = Phaser.Textures.Texture;
@@ -97,8 +90,10 @@ import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import { MapStore } from "../../Stores/Utils/MapStore";
import { followUsersColorStore } from "../../Stores/FollowStore";
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
import { locale, LL } from "../../i18n/i18n-svelte";
import { locale } from "../../i18n/i18n-svelte";
import { i18nJson } from "../../i18n/locales";
import { StringUtils } from "../../Utils/StringUtils";
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
@@ -568,6 +563,8 @@ export class GameScene extends DirtyScene {
urlManager.getStartLayerNameFromUrl()
);
startLayerNamesStore.set(this.startPositionCalculator.getStartPositionNames());
//add entities
this.Objects = new Array<Phaser.Physics.Arcade.Sprite>();
@@ -595,6 +592,8 @@ export class GameScene extends DirtyScene {
this.createCurrentPlayer();
this.removeAllRemotePlayers(); //cleanup the list of remote players in case the scene was rebooted
this.tryMovePlayerWithMoveToParameter();
this.cameraManager = new CameraManager(
this,
{ x: this.Map.widthInPixels, y: this.Map.heightInPixels },
@@ -654,7 +653,6 @@ export class GameScene extends DirtyScene {
);
new GameMapPropertiesListener(this, this.gameMap).register();
this.triggerOnMapLayerPropertyChange();
if (!this.room.isDisconnected()) {
this.scene.sleep();
@@ -833,7 +831,7 @@ export class GameScene extends DirtyScene {
const coWebsite = new JitsiCoWebsite(new URL(domain), false, undefined, undefined, false);
coWebsiteManager.addCoWebsiteToStore(coWebsite, 0);
this.startJitsi(coWebsite, message.jitsiRoom, message.jwt);
this.initialiseJitsi(coWebsite, message.jitsiRoom, message.jwt);
});
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
@@ -970,116 +968,6 @@ export class GameScene extends DirtyScene {
}
}
private triggerOnMapLayerPropertyChange() {
this.gameMap.onPropertyChange(GameMapProperties.EXIT_SCENE_URL, (newValue, oldValue) => {
if (newValue) {
this.onMapExit(
Room.getRoomPathFromExitSceneUrl(newValue as string, window.location.toString(), this.MapUrlFile)
).catch((e) => console.error(e));
} else {
setTimeout(() => {
layoutManagerActionStore.removeAction("roomAccessDenied");
}, 2000);
}
});
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
if (newValue) {
this.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString())).catch((e) =>
console.error(e)
);
} else {
setTimeout(() => {
layoutManagerActionStore.removeAction("roomAccessDenied");
}, 2000);
}
});
this.gameMap.onPropertyChange(GameMapProperties.JITSI_ROOM, (newValue, oldValue, allProps) => {
if (newValue === undefined) {
layoutManagerActionStore.removeAction("jitsi");
this.stopJitsi();
} else {
const openJitsiRoomFunction = () => {
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance);
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
const adminTag = allProps.get(GameMapProperties.JITSI_ADMIN_ROOM_TAG) as string | undefined;
this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag);
} else {
let domain = jitsiUrl || JITSI_URL;
if (domain === undefined) {
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
}
if (domain.substring(0, 7) !== "http://" && domain.substring(0, 8) !== "https://") {
domain = `${location.protocol}//${domain}`;
}
const coWebsite = new JitsiCoWebsite(new URL(domain), false, undefined, undefined, false);
coWebsiteManager.addCoWebsiteToStore(coWebsite, 0);
this.startJitsi(coWebsite, roomName, undefined);
}
layoutManagerActionStore.removeAction("jitsi");
};
const jitsiTriggerValue = allProps.get(GameMapProperties.JITSI_TRIGGER);
const forceTrigger = localUserStore.getForceCowebsiteTrigger();
if (forceTrigger || jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
let message = allProps.get(GameMapProperties.JITSI_TRIGGER_MESSAGE);
if (message === undefined) {
message = get(LL).message.openJitsiTrigger();
}
layoutManagerActionStore.addAction({
uuid: "jitsi",
type: "message",
message: message,
callback: () => openJitsiRoomFunction(),
userInputManager: this.userInputManager,
});
} else {
openJitsiRoomFunction();
}
}
});
this.gameMap.onPropertyChange(GameMapProperties.SILENT, (newValue, oldValue) => {
if (newValue === undefined || newValue === false || newValue === "") {
this.connection?.setSilent(false);
this.CurrentPlayer.noSilent();
} else {
this.connection?.setSilent(true);
this.CurrentPlayer.isSilent();
}
});
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO, (newValue, oldValue, allProps) => {
const volume = allProps.get(GameMapProperties.AUDIO_VOLUME) as number | undefined;
const loop = allProps.get(GameMapProperties.AUDIO_LOOP) as boolean | undefined;
newValue === undefined
? audioManagerFileStore.unloadAudio()
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), volume, loop);
audioManagerVisibilityStore.set(!(newValue === undefined));
});
// TODO: This legacy property should be removed at some point
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO_LOOP, (newValue, oldValue) => {
newValue === undefined
? audioManagerFileStore.unloadAudio()
: audioManagerFileStore.playAudio(newValue, this.getMapDirUrl(), undefined, true);
audioManagerVisibilityStore.set(!(newValue === undefined));
});
// TODO: Legacy functionnality replace by layer change
this.gameMap.onPropertyChange(GameMapProperties.ZONE, (newValue, oldValue) => {
if (oldValue) {
iframeListener.sendLeaveEvent(oldValue as string);
}
if (newValue) {
iframeListener.sendEnterEvent(newValue as string);
}
});
}
private listenToIframeEvents(): void {
this.iframeSubscriptionList = [];
this.iframeSubscriptionList.push(
@@ -1462,7 +1350,7 @@ export class GameScene extends DirtyScene {
//Create new colliders with the new GameMap
this.createCollisionWithPlayer();
//Create new trigger with the new GameMap
this.triggerOnMapLayerPropertyChange();
new GameMapPropertiesListener(this, this.gameMap).register();
resolve(newFirstgid);
});
});
@@ -1533,9 +1421,9 @@ export class GameScene extends DirtyScene {
});
iframeListener.registerAnswerer("movePlayerTo", async (message) => {
const index = this.getGameMap().getTileIndexAt(message.x, message.y);
const startTile = this.getGameMap().getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y);
const path = await this.getPathfindingManager().findPath(startTile, index, true, true);
const startTileIndex = this.getGameMap().getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y);
const destinationTileIndex = this.getGameMap().getTileIndexAt(message.x, message.y);
const path = await this.getPathfindingManager().findPath(startTileIndex, destinationTileIndex, true, true);
path.shift();
if (path.length === 0) {
throw new Error("no path available");
@@ -1579,11 +1467,11 @@ export class GameScene extends DirtyScene {
this.markDirty();
}
private getMapDirUrl(): string {
return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf("/"));
public getMapDirUrl(): string {
return this.MapUrlFile.substring(0, this.MapUrlFile.lastIndexOf("/"));
}
private async onMapExit(roomUrl: URL) {
public async onMapExit(roomUrl: URL) {
if (this.mapTransitioning) return;
this.mapTransitioning = true;
@@ -1649,7 +1537,6 @@ export class GameScene extends DirtyScene {
iframeListener.unregisterScript(script);
}
this.stopJitsi();
audioManagerFileStore.unloadAudio();
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
this.connection?.closeConnection();
@@ -1700,6 +1587,36 @@ export class GameScene extends DirtyScene {
this.MapPlayersByKey.clear();
}
private tryMovePlayerWithMoveToParameter(): void {
const moveToParam = urlManager.getHashParameter("moveTo");
if (moveToParam) {
try {
let endPos;
const posFromParam = StringUtils.parsePointFromParam(moveToParam);
if (posFromParam) {
endPos = this.gameMap.getTileIndexAt(posFromParam.x, posFromParam.y);
} else {
const destinationObject = this.gameMap.getObjectWithName(moveToParam);
if (destinationObject) {
endPos = this.gameMap.getTileIndexAt(destinationObject.x, destinationObject.y);
} else {
endPos = this.gameMap.getRandomPositionFromLayer(moveToParam);
}
}
this.pathfindingManager
.findPath(this.gameMap.getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y), endPos)
.then((path) => {
if (path && path.length > 0) {
this.CurrentPlayer.setPathToFollow(path).catch((reason) => console.warn(reason));
}
})
.catch((reason) => console.warn(reason));
} catch (err) {
console.warn(`Cannot proceed with moveTo command:\n\t-> ${err}`);
}
}
}
private getExitUrl(layer: ITiledMapLayer): string | undefined {
return this.getProperty(layer, GameMapProperties.EXIT_URL) as string | undefined;
}
@@ -1822,22 +1739,6 @@ export class GameScene extends DirtyScene {
this.connection?.emitEmoteEvent(emoteKey);
analyticsClient.launchEmote(emoteKey);
});
const moveToParam = urlManager.getHashParameter("moveTo");
if (moveToParam) {
try {
const endPos = this.gameMap.getRandomPositionFromLayer(moveToParam);
this.pathfindingManager
.findPath(this.gameMap.getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y), endPos)
.then((path) => {
if (path && path.length > 0) {
this.CurrentPlayer.setPathToFollow(path).catch((reason) => console.warn(reason));
}
})
.catch((reason) => console.warn(reason));
} catch (err) {
console.warn(`Cannot proceed with moveTo command:\n\t-> ${err}`);
}
}
} catch (err) {
if (err instanceof TextureError) {
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
@@ -2190,7 +2091,7 @@ export class GameScene extends DirtyScene {
mediaManager.hideMyCamera();
}
public startJitsi(coWebsite: JitsiCoWebsite, roomName: string, jwt?: string): void {
public initialiseJitsi(coWebsite: JitsiCoWebsite, roomName: string, jwt?: string): void {
const allProps = this.gameMap.getCurrentProperties();
const jitsiConfig = this.safeParseJSONstring(
allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined,
@@ -2218,13 +2119,6 @@ export class GameScene extends DirtyScene {
analyticsClient.enteredJitsi(roomName, this.room.id);
}
public stopJitsi(): void {
const coWebsite = coWebsiteManager.searchJitsi();
if (coWebsite) {
coWebsiteManager.closeCoWebsite(coWebsite);
}
}
//todo: put this into an 'orchestrator' scene (EntryScene?)
private bannedUser() {
this.cleanupClosingScene();
@@ -16,32 +16,6 @@ export class StartPositionCalculator {
) {
this.initStartXAndStartY();
}
private initStartXAndStartY() {
// If there is an init position passed
if (this.initPosition !== null) {
this.startPosition = this.initPosition;
} else {
// Now, let's find the start layer
if (this.startLayerName) {
this.initPositionFromLayerName(this.startLayerName, this.startLayerName);
}
if (this.startPosition === undefined) {
// If we have no start layer specified or if the hash passed does not exist, let's go with the default start position.
this.initPositionFromLayerName(defaultStartLayerName, this.startLayerName);
}
}
// Still no start position? Something is wrong with the map, we need a "start" layer.
if (this.startPosition === undefined) {
console.warn(
'This map is missing a layer named "start" that contains the available default start positions.'
);
// Let's start in the middle of the map
this.startPosition = {
x: this.mapFile.width * 16,
y: this.mapFile.height * 16,
};
}
}
/**
*
@@ -77,6 +51,47 @@ export class StartPositionCalculator {
}
}
public getStartPositionNames(): string[] {
const names: string[] = [];
for (const layer of this.gameMap.flatLayers) {
if (layer.name === "start") {
names.push(layer.name);
continue;
}
if (this.isStartLayer(layer)) {
names.push(layer.name);
}
}
return names;
}
private initStartXAndStartY() {
// If there is an init position passed
if (this.initPosition !== null) {
this.startPosition = this.initPosition;
} else {
// Now, let's find the start layer
if (this.startLayerName) {
this.initPositionFromLayerName(this.startLayerName, this.startLayerName);
}
if (this.startPosition === undefined) {
// If we have no start layer specified or if the hash passed does not exist, let's go with the default start position.
this.initPositionFromLayerName(defaultStartLayerName, this.startLayerName);
}
}
// Still no start position? Something is wrong with the map, we need a "start" layer.
if (this.startPosition === undefined) {
console.warn(
'This map is missing a layer named "start" that contains the available default start positions.'
);
// Let's start in the middle of the map
this.startPosition = {
x: this.mapFile.width * 16,
y: this.mapFile.height * 16,
};
}
}
private isStartLayer(layer: ITiledMapLayer): boolean {
return this.getProperty(layer, GameMapProperties.START_LAYER) == true;
}
+1 -6
View File
@@ -1,6 +1,5 @@
import { derived, get, writable } from "svelte/store";
import { derived, writable } from "svelte/store";
import type { CoWebsite } from "../WebRtc/CoWebsite/CoWesbite";
import { JitsiCoWebsite } from "../WebRtc/CoWebsite/JitsiCoWebsite";
function createCoWebsiteStore() {
const { subscribe, set, update } = writable(Array<CoWebsite>());
@@ -50,7 +49,3 @@ export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) =>
export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) =>
$coWebsites.find((coWebsite) => coWebsite.getState() !== "asleep")
);
export const jitsiCoWebsite = derived([coWebsites], ([$coWebsites]) =>
$coWebsites.find((coWebsite) => coWebsite instanceof JitsiCoWebsite)
);
+6
View File
@@ -0,0 +1,6 @@
import { Readable, writable } from "svelte/store";
/**
* A store that contains the map starting layers names
*/
export const startLayerNamesStore = writable<string[]>([]);
+12
View File
@@ -0,0 +1,12 @@
export class StringUtils {
public static parsePointFromParam(param: string, separator: string = ","): { x: number; y: number } | undefined {
const values = param.split(separator).map((val) => parseInt(val));
if (values.length !== 2) {
return;
}
if (isNaN(values[0]) || isNaN(values[1])) {
return;
}
return { x: values[0], y: values[1] };
}
}
@@ -1,22 +1,11 @@
import CancelablePromise from "cancelable-promise";
import { gameManager } from "../../Phaser/Game/GameManager";
import { coWebsiteManager } from "../CoWebsiteManager";
import { jitsiFactory } from "../JitsiFactory";
import { SimpleCoWebsite } from "./SimpleCoWebsite";
export class JitsiCoWebsite extends SimpleCoWebsite {
private jitsiLoadPromise?: () => CancelablePromise<HTMLIFrameElement>;
constructor(url: URL, allowApi?: boolean, allowPolicy?: string, widthPercent?: number, closable?: boolean) {
const coWebsite = coWebsiteManager.searchJitsi();
if (coWebsite) {
coWebsiteManager.closeCoWebsite(coWebsite);
}
super(url, allowApi, allowPolicy, widthPercent, closable);
}
setJitsiLoadPromise(promise: () => CancelablePromise<HTMLIFrameElement>): void {
this.jitsiLoadPromise = promise;
}
@@ -26,7 +15,6 @@ export class JitsiCoWebsite extends SimpleCoWebsite {
this.state.set("loading");
gameManager.getCurrentGameScene().disableMediaBehaviors();
jitsiFactory.restart();
if (!this.jitsiLoadPromise) {
return reject("Undefined Jitsi start callback");
+14 -17
View File
@@ -1,8 +1,8 @@
import { HtmlUtils } from "./HtmlUtils";
import { Subject } from "rxjs";
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
import { coWebsites, coWebsitesNotAsleep, jitsiCoWebsite, mainCoWebsite } from "../Stores/CoWebsiteStore";
import { get } from "svelte/store";
import { coWebsites, coWebsitesNotAsleep, mainCoWebsite } from "../Stores/CoWebsiteStore";
import { get, Readable, Writable, writable } from "svelte/store";
import { embedScreenLayout, highlightedEmbedScreen } from "../Stores/EmbedScreensStore";
import { isMediaBreakpointDown } from "../Utils/BreakpointsUtils";
import { LayoutMode } from "./LayoutManager";
@@ -34,7 +34,7 @@ interface TouchMoveCoordinates {
}
class CoWebsiteManager {
private openedMain: iframeStates = iframeStates.closed;
private openedMain: Writable<iframeStates> = writable(iframeStates.closed);
private _onResize: Subject<void> = new Subject();
public onResize = this._onResize.asObservable();
@@ -57,6 +57,10 @@ class CoWebsiteManager {
});
public getMainState() {
return get(this.openedMain);
}
public getMainStateSubscriber(): Readable<iframeStates> {
return this.openedMain;
}
@@ -324,7 +328,7 @@ class CoWebsiteManager {
}
this.cowebsiteDom.classList.add("closing");
this.cowebsiteDom.classList.remove("opened");
this.openedMain = iframeStates.closed;
this.openedMain.set(iframeStates.closed);
this.fire();
}
@@ -332,7 +336,7 @@ class CoWebsiteManager {
this.toggleFullScreenIcon(true);
this.cowebsiteDom.classList.add("closing");
this.cowebsiteDom.classList.remove("opened");
this.openedMain = iframeStates.closed;
this.openedMain.set(iframeStates.closed);
this.resetStyleMain();
this.fire();
}
@@ -386,14 +390,14 @@ class CoWebsiteManager {
}
this.cowebsiteDom.classList.add("opened");
this.openedMain = iframeStates.loading;
this.openedMain.set(iframeStates.loading);
}
private openMain(): void {
this.cowebsiteDom.addEventListener("transitionend", () => {
this.resizeAllIframes();
});
this.openedMain = iframeStates.opened;
this.openedMain.set(iframeStates.opened);
}
public resetStyleMain() {
@@ -556,19 +560,12 @@ class CoWebsiteManager {
mainCoWebsite.getId() !== coWebsite.getId() &&
mainCoWebsite.getState() !== "asleep"
) {
highlightedEmbedScreen.toggleHighlight({
type: "cowebsite",
embed: mainCoWebsite,
});
highlightedEmbedScreen.removeHighlight();
}
this.resizeAllIframes();
}
public searchJitsi(): CoWebsite | undefined {
return get(jitsiCoWebsite);
}
public addCoWebsiteToStore(coWebsite: CoWebsite, position: number | undefined) {
const coWebsitePosition = position === undefined ? get(coWebsites).length : position;
coWebsites.add(coWebsite, coWebsitePosition);
@@ -591,7 +588,7 @@ class CoWebsiteManager {
}
// Check if the main is hide
if (this.getMainCoWebsite() && this.openedMain === iframeStates.closed) {
if (this.getMainCoWebsite() && this.getMainState() === iframeStates.closed) {
this.displayMain();
}
@@ -665,7 +662,7 @@ class CoWebsiteManager {
}
public getGameSize(): { width: number; height: number } {
if (this.openedMain === iframeStates.closed) {
if (this.getMainState() === iframeStates.closed) {
return {
width: window.innerWidth,
height: window.innerHeight,
+6 -29
View File
@@ -2,7 +2,6 @@ import { JITSI_URL } from "../Enum/EnvironmentVariable";
import { coWebsiteManager } from "./CoWebsiteManager";
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
import { get } from "svelte/store";
import type { CoWebsite } from "./CoWebsite/CoWesbite";
import CancelablePromise from "cancelable-promise";
interface jitsiConfigInterface {
@@ -183,13 +182,14 @@ class JitsiFactory {
const iframe = coWebsiteManager
.getCoWebsiteBuffer()
.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
if (iframe && this.jitsiApi) {
this.jitsiApi.addListener("videoConferenceLeft", () => {
this.closeOrUnload();
this.closeOrUnload(iframe);
});
this.jitsiApi.addListener("readyToClose", () => {
this.closeOrUnload();
this.closeOrUnload(iframe);
});
return resolve(iframe);
@@ -212,8 +212,9 @@ class JitsiFactory {
});
}
private closeOrUnload = function () {
const coWebsite = coWebsiteManager.searchJitsi();
private closeOrUnload = function (iframe: HTMLIFrameElement) {
const coWebsite = coWebsiteManager.getCoWebsites().find((coWebsite) => coWebsite.getIframe() === iframe);
if (!coWebsite) {
return;
}
@@ -227,30 +228,6 @@ class JitsiFactory {
}
};
public restart() {
if (!this.jitsiApi) {
return;
}
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
const coWebsite = coWebsiteManager.searchJitsi();
if (!coWebsite) {
this.destroy();
return;
}
this.jitsiApi.addListener("videoConferenceLeft", () => {
this.closeOrUnload();
});
this.jitsiApi.addListener("readyToClose", () => {
this.closeOrUnload();
});
}
public stop() {
if (!this.jitsiApi) {
return;
+3 -3
View File
@@ -8,14 +8,14 @@ import emoji from "./emoji";
import error from "./error";
import follow from "./follow";
import login from "./login";
import message from "./message";
import menu from "./menu";
import report from "./report";
import warning from "./warning";
import woka from "./woka";
import trigger from "./trigger";
const de_DE: Translation = {
...en_US,
...(en_US as Translation),
language: "Deutsch",
country: "Deutschland",
audio,
@@ -30,7 +30,7 @@ const de_DE: Translation = {
report,
warning,
emoji,
message,
trigger,
};
export default de_DE;
+1
View File
@@ -70,6 +70,7 @@ const menu: NonNullable<Translation["menu"]> = {
description: "Link zu diesem Raum teilen!",
copy: "Kopieren",
share: "Teilen",
walk_automatically_to_position: "Walk automatically to my position",
},
globalMessage: {
text: "Text",
-9
View File
@@ -1,9 +0,0 @@
import type { Translation } from "../i18n-types";
const message: NonNullable<Translation["message"]> = {
openWebsiteTrigger: "Drücke LEERTASTE oder tippe hier um die Webseite zu öffnen",
openWebsiteTabTrigger: "Drücke LEERTASTE oder tippe hier um die Webseite in einem neuen Tab zu öffnen",
openJitsiTrigger: "Drücke LEERTASTE oder tippe hier um dem Jitsi Meet Raum beizutreten",
};
export default message;
+9
View File
@@ -0,0 +1,9 @@
import type { Translation } from "../i18n-types";
const trigger: NonNullable<Translation["trigger"]> = {
cowebsite: "Drücke LEERTASTE oder tippe hier um die Webseite zu öffnen",
newTab: "Drücke LEERTASTE oder tippe hier um die Webseite in einem neuen Tab zu öffnen",
jitsiRoom: "Drücke LEERTASTE oder tippe hier um dem Jitsi Meet Raum beizutreten",
};
export default trigger;
+2 -2
View File
@@ -11,7 +11,7 @@ import menu from "./menu";
import report from "./report";
import warning from "./warning";
import emoji from "./emoji";
import message from "./message";
import trigger from "./trigger";
const en_US: BaseTranslation = {
language: "English",
@@ -28,7 +28,7 @@ const en_US: BaseTranslation = {
report,
warning,
emoji,
message,
trigger,
};
export default en_US;
+1
View File
@@ -70,6 +70,7 @@ const menu: BaseTranslation = {
description: "Share the link of the room!",
copy: "Copy",
share: "Share",
walk_automatically_to_position: "Walk automatically to my position",
},
globalMessage: {
text: "Text",
-9
View File
@@ -1,9 +0,0 @@
import type { BaseTranslation } from "../i18n-types";
const message: BaseTranslation = {
openWebsiteTrigger: "Press SPACE or touch here to open web site",
openWebsiteTabTrigger: "Press SPACE or touch here to open web site in new tab",
openJitsiTrigger: "Press SPACE or touch here to enter Jitsi Meet room",
};
export default message;
+9
View File
@@ -0,0 +1,9 @@
import type { BaseTranslation } from "../i18n-types";
const trigger: BaseTranslation = {
cowebsite: "Press SPACE or touch here to open web site",
jitsiRoom: "Press SPACE or touch here to enter Jitsi Meet room",
newTab: "Press SPACE or touch here to open web site in new tab",
};
export default trigger;