merged develop

This commit is contained in:
Hanusiak Piotr 2022-02-10 16:00:56 +01:00
commit 66375e6d53
17 changed files with 788 additions and 448 deletions

View File

@ -2,9 +2,9 @@
import { onMount } from "svelte"; import { onMount } from "svelte";
import { ICON_URL } from "../../Enum/EnvironmentVariable"; import { ICON_URL } from "../../Enum/EnvironmentVariable";
import { coWebsitesNotAsleep, mainCoWebsite } from "../../Stores/CoWebsiteStore"; import { coWebsitesNotAsleep, mainCoWebsite, jitsiCoWebsite } from "../../Stores/CoWebsiteStore";
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore"; import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
import type { CoWebsite } from "../../WebRtc/CoWebsiteManager"; import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
import { iframeStates } from "../../WebRtc/CoWebsiteManager"; import { iframeStates } from "../../WebRtc/CoWebsiteManager";
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
@ -14,16 +14,15 @@
let icon: HTMLImageElement; let icon: HTMLImageElement;
let iconLoaded = false; let iconLoaded = false;
let state = coWebsite.state; let state = coWebsite.getStateSubscriber();
let isJitsi: boolean = false;
const coWebsiteUrl = coWebsite.iframe.src;
const urlObject = new URL(coWebsiteUrl);
onMount(() => { onMount(() => {
icon.src = coWebsite.jitsi isJitsi = Boolean($jitsiCoWebsite && $jitsiCoWebsite.getId() === coWebsite.getId());
icon.src = isJitsi
? "/resources/logos/meet.svg" ? "/resources/logos/meet.svg"
: `${ICON_URL}/icon?url=${urlObject.hostname}&size=64..96..256&fallback_icon_color=14304c`; : `${ICON_URL}/icon?url=${coWebsite.getUrl().hostname}&size=64..96..256&fallback_icon_color=14304c`;
icon.alt = coWebsite.altMessage ?? urlObject.hostname; icon.alt = coWebsite.getUrl().hostname;
icon.onload = () => { icon.onload = () => {
iconLoaded = true; iconLoaded = true;
}; };
@ -33,10 +32,10 @@
if (vertical) { if (vertical) {
coWebsiteManager.goToMain(coWebsite); coWebsiteManager.goToMain(coWebsite);
} else if ($mainCoWebsite) { } else if ($mainCoWebsite) {
if ($mainCoWebsite.iframe.id === coWebsite.iframe.id) { if ($mainCoWebsite.getId() === coWebsite.getId()) {
const coWebsites = $coWebsitesNotAsleep; const coWebsites = $coWebsitesNotAsleep;
const newMain = $highlightedEmbedScreen ?? coWebsites.length > 1 ? coWebsites[1] : undefined; const newMain = $highlightedEmbedScreen ?? coWebsites.length > 1 ? coWebsites[1] : undefined;
if (newMain && newMain.iframe.id !== $mainCoWebsite.iframe.id) { if (newMain && newMain.getId() !== $mainCoWebsite.getId()) {
coWebsiteManager.goToMain(newMain); coWebsiteManager.goToMain(newMain);
} else if (coWebsiteManager.getMainState() === iframeStates.closed) { } else if (coWebsiteManager.getMainState() === iframeStates.closed) {
coWebsiteManager.displayMain(); coWebsiteManager.displayMain();
@ -65,11 +64,11 @@
let isHighlight: boolean = false; let isHighlight: boolean = false;
let isMain: boolean = false; let isMain: boolean = false;
$: { $: {
isMain = $mainCoWebsite !== undefined && $mainCoWebsite.iframe === coWebsite.iframe; isMain = $mainCoWebsite !== undefined && $mainCoWebsite.getId() === coWebsite.getId();
isHighlight = isHighlight =
$highlightedEmbedScreen !== null && $highlightedEmbedScreen !== null &&
$highlightedEmbedScreen.type === "cowebsite" && $highlightedEmbedScreen.type === "cowebsite" &&
$highlightedEmbedScreen.embed.iframe === coWebsite.iframe; $highlightedEmbedScreen.embed.getId() === coWebsite.getId();
} }
</script> </script>
@ -86,7 +85,7 @@
<img <img
class="cowebsite-icon noselect nes-pointer" class="cowebsite-icon noselect nes-pointer"
class:hide={!iconLoaded} class:hide={!iconLoaded}
class:jitsi={coWebsite.jitsi} class:jitsi={isJitsi}
bind:this={icon} bind:this={icon}
on:dragstart|preventDefault={noDrag} on:dragstart|preventDefault={noDrag}
alt="" alt=""

View File

@ -7,7 +7,7 @@
{#if $coWebsites.length > 0} {#if $coWebsites.length > 0}
<div id="cowebsite-thumbnail-container" class:vertical> <div id="cowebsite-thumbnail-container" class:vertical>
{#each [...$coWebsites.values()] as coWebsite, index (coWebsite.iframe.id)} {#each [...$coWebsites.values()] as coWebsite, index (coWebsite.getId())}
<CoWebsiteThumbnail {index} {coWebsite} {vertical} /> <CoWebsiteThumbnail {index} {coWebsite} {vertical} />
{/each} {/each}
</div> </div>

View File

@ -9,13 +9,11 @@
function closeCoWebsite() { function closeCoWebsite() {
if ($highlightedEmbedScreen?.type === "cowebsite") { if ($highlightedEmbedScreen?.type === "cowebsite") {
if ($highlightedEmbedScreen.embed.closable) { if ($highlightedEmbedScreen.embed.isClosable()) {
coWebsiteManager.closeCoWebsite($highlightedEmbedScreen.embed).catch(() => { coWebsiteManager.closeCoWebsite($highlightedEmbedScreen.embed);
console.error("Error during co-website highlighted closing");
});
} else { } else {
coWebsiteManager.unloadCoWebsite($highlightedEmbedScreen.embed).catch(() => { coWebsiteManager.unloadCoWebsite($highlightedEmbedScreen.embed).catch((err) => {
console.error("Error during co-website highlighted unloading"); console.error("Cannot unload co-website", err);
}); });
} }
} }
@ -68,9 +66,9 @@
/> />
{/key} {/key}
{:else if $highlightedEmbedScreen.type === "cowebsite"} {:else if $highlightedEmbedScreen.type === "cowebsite"}
{#key $highlightedEmbedScreen.embed.iframe.id} {#key $highlightedEmbedScreen.embed.getId()}
<div <div
id={"cowebsite-slot-" + $highlightedEmbedScreen.embed.iframe.id} id={"cowebsite-slot-" + $highlightedEmbedScreen.embed.getId()}
class="highlighted-cowebsite nes-container is-rounded" class="highlighted-cowebsite nes-container is-rounded"
> >
<div class="actions"> <div class="actions">

View File

@ -121,7 +121,7 @@ export class GameMap {
return []; return [];
} }
public getCollisionsGrid(): number[][] { public getCollisionGrid(): number[][] {
const grid: number[][] = []; const grid: number[][] = [];
for (let y = 0; y < this.map.height; y += 1) { for (let y = 0; y < this.map.height; y += 1) {
const row: number[] = []; const row: number[] = [];
@ -329,6 +329,9 @@ export class GameMap {
private isCollidingAt(x: number, y: number): boolean { private isCollidingAt(x: number, y: number): boolean {
for (const layer of this.phaserLayers) { for (const layer of this.phaserLayers) {
if (!layer.visible) {
continue;
}
if (layer.getTileAt(x, y)?.properties[GameMapProperties.COLLIDES]) { if (layer.getTileAt(x, y)?.properties[GameMapProperties.COLLIDES]) {
return true; return true;
} }

View File

@ -1,7 +1,6 @@
import type { GameScene } from "./GameScene"; import type { GameScene } from "./GameScene";
import type { GameMap } from "./GameMap"; import type { GameMap } from "./GameMap";
import { scriptUtils } from "../../Api/ScriptUtils"; import { scriptUtils } from "../../Api/ScriptUtils";
import type { CoWebsite } from "../../WebRtc/CoWebsiteManager";
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore"; import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
import { localUserStore } from "../../Connexion/LocalUserStore"; import { localUserStore } from "../../Connexion/LocalUserStore";
@ -9,17 +8,12 @@ import { get } from "svelte/store";
import { ON_ACTION_TRIGGER_BUTTON, ON_ICON_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager"; import { ON_ACTION_TRIGGER_BUTTON, ON_ICON_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
import type { ITiledMapLayer } from "../Map/ITiledMap"; import type { ITiledMapLayer } from "../Map/ITiledMap";
import { GameMapProperties } from "./GameMapProperties"; import { GameMapProperties } from "./GameMapProperties";
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
enum OpenCoWebsiteState { import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
ASLEEP,
OPENED,
MUST_BE_CLOSE,
}
interface OpenCoWebsite { interface OpenCoWebsite {
actionId: string; actionId: string;
coWebsite?: CoWebsite; coWebsite?: CoWebsite;
state: OpenCoWebsiteState;
} }
export class GameMapPropertiesListener { export class GameMapPropertiesListener {
@ -106,49 +100,33 @@ export class GameMapPropertiesListener {
return; return;
} }
this.coWebsitesOpenByLayer.set(layer, { const coWebsiteOpen: OpenCoWebsite = {
actionId: actionId, actionId: actionId,
coWebsite: undefined, };
state: OpenCoWebsiteState.ASLEEP,
}); this.coWebsitesOpenByLayer.set(layer, coWebsiteOpen);
const loadCoWebsiteFunction = (coWebsite: CoWebsite) => { const loadCoWebsiteFunction = (coWebsite: CoWebsite) => {
coWebsiteManager coWebsiteManager.loadCoWebsite(coWebsite).catch(() => {
.loadCoWebsite(coWebsite) console.error("Error during loading a co-website: " + coWebsite.getUrl());
.then((coWebsite) => { });
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
console.error("Error during a co-website closing");
});
this.coWebsitesOpenByLayer.delete(layer);
this.coWebsitesActionTriggerByLayer.delete(layer);
} else {
this.coWebsitesOpenByLayer.set(layer, {
actionId,
coWebsite,
state: OpenCoWebsiteState.OPENED,
});
}
})
.catch(() => {
console.error("Error during loading a co-website: " + coWebsite.url);
});
layoutManagerActionStore.removeAction(actionId); layoutManagerActionStore.removeAction(actionId);
}; };
const openCoWebsiteFunction = () => { const openCoWebsiteFunction = () => {
const coWebsite = coWebsiteManager.addCoWebsite( const coWebsite = new SimpleCoWebsite(
openWebsiteProperty ?? "", new URL(openWebsiteProperty ?? "", this.scene.MapUrlFile),
this.scene.MapUrlFile,
allowApiProperty, allowApiProperty,
websitePolicyProperty, websitePolicyProperty,
websiteWidthProperty, websiteWidthProperty,
websitePositionProperty,
false false
); );
coWebsiteOpen.coWebsite = coWebsite;
coWebsiteManager.addCoWebsiteToStore(coWebsite, websitePositionProperty);
loadCoWebsiteFunction(coWebsite); loadCoWebsiteFunction(coWebsite);
}; };
@ -170,21 +148,17 @@ export class GameMapPropertiesListener {
userInputManager: this.scene.userInputManager, userInputManager: this.scene.userInputManager,
}); });
} else if (websiteTriggerProperty === ON_ICON_TRIGGER_BUTTON) { } else if (websiteTriggerProperty === ON_ICON_TRIGGER_BUTTON) {
const coWebsite = coWebsiteManager.addCoWebsite( const coWebsite = new SimpleCoWebsite(
openWebsiteProperty, new URL(openWebsiteProperty ?? "", this.scene.MapUrlFile),
this.scene.MapUrlFile,
allowApiProperty, allowApiProperty,
websitePolicyProperty, websitePolicyProperty,
websiteWidthProperty, websiteWidthProperty,
websitePositionProperty,
false false
); );
const ObjectByLayer = this.coWebsitesOpenByLayer.get(layer); coWebsiteOpen.coWebsite = coWebsite;
if (ObjectByLayer) { coWebsiteManager.addCoWebsiteToStore(coWebsite, websitePositionProperty);
ObjectByLayer.coWebsite = coWebsite;
}
} }
if (!websiteTriggerProperty) { if (!websiteTriggerProperty) {
@ -228,12 +202,10 @@ export class GameMapPropertiesListener {
return; return;
} }
if (coWebsiteOpen.state === OpenCoWebsiteState.ASLEEP) { const coWebsite = coWebsiteOpen.coWebsite;
coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE;
}
if (coWebsiteOpen.coWebsite !== undefined) { if (coWebsite) {
coWebsiteManager.closeCoWebsite(coWebsiteOpen.coWebsite).catch((e) => console.error(e)); coWebsiteManager.closeCoWebsite(coWebsite);
} }
this.coWebsitesOpenByLayer.delete(layer); this.coWebsitesOpenByLayer.delete(layer);

View File

@ -5,7 +5,7 @@ import { get, Unsubscriber } from "svelte/store";
import { userMessageManager } from "../../Administration/UserMessageManager"; import { userMessageManager } from "../../Administration/UserMessageManager";
import { connectionManager } from "../../Connexion/ConnectionManager"; import { connectionManager } from "../../Connexion/ConnectionManager";
import { CoWebsite, coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
import { urlManager } from "../../Url/UrlManager"; import { urlManager } from "../../Url/UrlManager";
import { mediaManager } from "../../WebRtc/MediaManager"; import { mediaManager } from "../../WebRtc/MediaManager";
import { UserInputManager } from "../UserInput/UserInputManager"; import { UserInputManager } from "../UserInput/UserInputManager";
@ -22,7 +22,13 @@ import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/Pl
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager"; import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager"; import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
import { iframeListener } from "../../Api/IframeListener"; import { iframeListener } from "../../Api/IframeListener";
import { DEBUG_MODE, JITSI_PRIVATE_MODE, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable"; import {
DEBUG_MODE,
JITSI_PRIVATE_MODE,
JITSI_URL,
MAX_PER_GROUP,
POSITION_DELAY,
} from "../../Enum/EnvironmentVariable";
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils"; import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
import { Room } from "../../Connexion/Room"; import { Room } from "../../Connexion/Room";
import { jitsiFactory } from "../../WebRtc/JitsiFactory"; import { jitsiFactory } from "../../WebRtc/JitsiFactory";
@ -93,6 +99,9 @@ import { followUsersColorStore } from "../../Stores/FollowStore";
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler"; import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
import { locale } from "../../i18n/i18n-svelte"; import { locale } from "../../i18n/i18n-svelte";
import { localVolumeStore } from "../../Stores/MediaStore"; import { localVolumeStore } from "../../Stores/MediaStore";
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
export interface GameSceneInitInterface { export interface GameSceneInitInterface {
initPosition: PointInterface | null; initPosition: PointInterface | null;
reconnecting: boolean; reconnecting: boolean;
@ -565,7 +574,7 @@ export class GameScene extends DirtyScene {
this.pathfindingManager = new PathfindingManager( this.pathfindingManager = new PathfindingManager(
this, this,
this.gameMap.getCollisionsGrid(), this.gameMap.getCollisionGrid(),
this.gameMap.getTileDimensions() this.gameMap.getTileDimensions()
); );
@ -581,7 +590,7 @@ export class GameScene extends DirtyScene {
this.pathfindingManager = new PathfindingManager( this.pathfindingManager = new PathfindingManager(
this, this,
this.gameMap.getCollisionsGrid(), this.gameMap.getCollisionGrid(),
this.gameMap.getTileDimensions() this.gameMap.getTileDimensions()
); );
@ -826,7 +835,19 @@ export class GameScene extends DirtyScene {
* Triggered when we receive the JWT token to connect to Jitsi * Triggered when we receive the JWT token to connect to Jitsi
*/ */
this.connection.sendJitsiJwtMessageStream.subscribe((message) => { this.connection.sendJitsiJwtMessageStream.subscribe((message) => {
this.startJitsi(message.jitsiRoom, message.jwt); if (!JITSI_URL) {
throw new Error("Missing JITSI_URL environment variable.");
}
let domain = JITSI_URL;
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, message.jitsiRoom, message.jwt);
}); });
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => { this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
@ -995,12 +1016,25 @@ export class GameScene extends DirtyScene {
const openJitsiRoomFunction = () => { const openJitsiRoomFunction = () => {
const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance); const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance);
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined; const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
if (JITSI_PRIVATE_MODE && !jitsiUrl) { if (JITSI_PRIVATE_MODE && !jitsiUrl) {
const adminTag = allProps.get(GameMapProperties.JITSI_ADMIN_ROOM_TAG) as string | undefined; const adminTag = allProps.get(GameMapProperties.JITSI_ADMIN_ROOM_TAG) as string | undefined;
this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag); this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag);
} else { } else {
this.startJitsi(roomName, undefined); 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"); layoutManagerActionStore.removeAction("jitsi");
}; };
@ -1292,13 +1326,11 @@ ${escapedMessage}
throw new Error("Unknown query source"); throw new Error("Unknown query source");
} }
const coWebsite = coWebsiteManager.addCoWebsite( const coWebsite: SimpleCoWebsite = new SimpleCoWebsite(
openCoWebsite.url, new URL(openCoWebsite.url, iframeListener.getBaseUrlFromSource(source)),
iframeListener.getBaseUrlFromSource(source),
openCoWebsite.allowApi, openCoWebsite.allowApi,
openCoWebsite.allowPolicy, openCoWebsite.allowPolicy,
openCoWebsite.widthPercent, openCoWebsite.widthPercent,
openCoWebsite.position,
openCoWebsite.closable ?? true openCoWebsite.closable ?? true
); );
@ -1307,7 +1339,7 @@ ${escapedMessage}
} }
return { return {
id: coWebsite.iframe.id, id: coWebsite.getId(),
}; };
}); });
@ -1316,27 +1348,23 @@ ${escapedMessage}
return coWebsites.map((coWebsite: CoWebsite) => { return coWebsites.map((coWebsite: CoWebsite) => {
return { return {
id: coWebsite.iframe.id, id: coWebsite.getId(),
}; };
}); });
}); });
iframeListener.registerAnswerer("closeCoWebsite", async (coWebsiteId) => { iframeListener.registerAnswerer("closeCoWebsite", (coWebsiteId) => {
const coWebsite = coWebsiteManager.getCoWebsiteById(coWebsiteId); const coWebsite = coWebsiteManager.getCoWebsiteById(coWebsiteId);
if (!coWebsite) { if (!coWebsite) {
throw new Error("Unknown co-website"); throw new Error("Unknown co-website");
} }
return coWebsiteManager.closeCoWebsite(coWebsite).catch((error) => { return coWebsiteManager.closeCoWebsite(coWebsite);
throw new Error("Error on closing co-website");
});
}); });
iframeListener.registerAnswerer("closeCoWebsites", async () => { iframeListener.registerAnswerer("closeCoWebsites", () => {
return await coWebsiteManager.closeCoWebsites().catch((error) => { return coWebsiteManager.closeCoWebsites();
throw new Error("Error on closing all co-websites");
});
}); });
iframeListener.registerAnswerer("getMapData", () => { iframeListener.registerAnswerer("getMapData", () => {
@ -1534,6 +1562,7 @@ ${escapedMessage}
phaserLayers[i].setCollisionByProperty({ collides: true }, visible); phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
} }
} }
this.pathfindingManager.setCollisionGrid(this.gameMap.getCollisionGrid());
this.markDirty(); this.markDirty();
} }
@ -1600,7 +1629,7 @@ ${escapedMessage}
public cleanupClosingScene(): void { public cleanupClosingScene(): void {
// stop playing audio, close any open website, stop any open Jitsi // stop playing audio, close any open website, stop any open Jitsi
coWebsiteManager.closeCoWebsites().catch((e) => console.error(e)); coWebsiteManager.closeCoWebsites();
// Stop the script, if any // Stop the script, if any
const scripts = this.getScriptUrls(this.mapFile); const scripts = this.getScriptUrls(this.mapFile);
for (const script of scripts) { for (const script of scripts) {
@ -2148,7 +2177,7 @@ ${escapedMessage}
mediaManager.hideMyCamera(); mediaManager.hideMyCamera();
} }
public startJitsi(roomName: string, jwt?: string): void { public startJitsi(coWebsite: JitsiCoWebsite, roomName: string, jwt?: string): void {
const allProps = this.gameMap.getCurrentProperties(); const allProps = this.gameMap.getCurrentProperties();
const jitsiConfig = this.safeParseJSONstring( const jitsiConfig = this.safeParseJSONstring(
allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined, allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined,
@ -2160,19 +2189,21 @@ ${escapedMessage}
); );
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined; const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl).catch(() => { coWebsite.setJitsiLoadPromise(() => {
console.error("Cannot start a Jitsi co-website"); return jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl);
}); });
this.disableMediaBehaviors();
coWebsiteManager.loadCoWebsite(coWebsite).catch((err) => {
console.error(err);
});
analyticsClient.enteredJitsi(roomName, this.room.id); analyticsClient.enteredJitsi(roomName, this.room.id);
} }
public stopJitsi(): void { public stopJitsi(): void {
const coWebsite = coWebsiteManager.searchJitsi(); const coWebsite = coWebsiteManager.searchJitsi();
if (coWebsite) { if (coWebsite) {
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => { coWebsiteManager.closeCoWebsite(coWebsite);
console.error("Error during Jitsi co-website closing", e);
});
} }
} }

View File

@ -1,5 +1,6 @@
import { derived, get, writable } from "svelte/store"; import { derived, get, writable } from "svelte/store";
import type { CoWebsite } from "../WebRtc/CoWebsiteManager"; import type { CoWebsite } from "../WebRtc/CoWebsite/CoWesbite";
import { JitsiCoWebsite } from "../WebRtc/CoWebsite/JitsiCoWebsite";
function createCoWebsiteStore() { function createCoWebsiteStore() {
const { subscribe, set, update } = writable(Array<CoWebsite>()); const { subscribe, set, update } = writable(Array<CoWebsite>());
@ -9,7 +10,7 @@ function createCoWebsiteStore() {
return { return {
subscribe, subscribe,
add: (coWebsite: CoWebsite, position?: number) => { add: (coWebsite: CoWebsite, position?: number) => {
coWebsite.state.subscribe((value) => { coWebsite.getStateSubscriber().subscribe((value) => {
update((currentArray) => currentArray); update((currentArray) => currentArray);
}); });
@ -31,7 +32,7 @@ function createCoWebsiteStore() {
}, },
remove: (coWebsite: CoWebsite) => { remove: (coWebsite: CoWebsite) => {
update((currentArray) => [ update((currentArray) => [
...currentArray.filter((currentCoWebsite) => currentCoWebsite.iframe.id !== coWebsite.iframe.id), ...currentArray.filter((currentCoWebsite) => currentCoWebsite.getId() !== coWebsite.getId()),
]); ]);
}, },
empty: () => { empty: () => {
@ -43,9 +44,13 @@ function createCoWebsiteStore() {
export const coWebsites = createCoWebsiteStore(); export const coWebsites = createCoWebsiteStore();
export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) => export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) =>
$coWebsites.filter((coWebsite) => get(coWebsite.state) !== "asleep") $coWebsites.filter((coWebsite) => coWebsite.getState() !== "asleep")
); );
export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) => export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) =>
$coWebsites.find((coWebsite) => get(coWebsite.state) !== "asleep") $coWebsites.find((coWebsite) => coWebsite.getState() !== "asleep")
);
export const jitsiCoWebsite = derived([coWebsites], ([$coWebsites]) =>
$coWebsites.find((coWebsite) => coWebsite instanceof JitsiCoWebsite)
); );

View File

@ -1,5 +1,5 @@
import { derived, get, writable } from "svelte/store"; import { derived, get, writable } from "svelte/store";
import type { CoWebsite } from "../WebRtc/CoWebsiteManager"; import type { CoWebsite } from "../WebRtc/CoWebsite/CoWesbite";
import { LayoutMode } from "../WebRtc/LayoutManager"; import { LayoutMode } from "../WebRtc/LayoutManager";
import { coWebsites } from "./CoWebsiteStore"; import { coWebsites } from "./CoWebsiteStore";
import { Streamable, streamableCollectionStore } from "./StreamableCollectionStore"; import { Streamable, streamableCollectionStore } from "./StreamableCollectionStore";
@ -31,7 +31,7 @@ function createHighlightedEmbedScreenStore() {
embedScreen.type !== currentEmbedScreen.type || embedScreen.type !== currentEmbedScreen.type ||
(embedScreen.type === "cowebsite" && (embedScreen.type === "cowebsite" &&
currentEmbedScreen.type === "cowebsite" && currentEmbedScreen.type === "cowebsite" &&
embedScreen.embed.iframe.id !== currentEmbedScreen.embed.iframe.id) || embedScreen.embed.getId() !== currentEmbedScreen.embed.getId()) ||
(embedScreen.type === "streamable" && (embedScreen.type === "streamable" &&
currentEmbedScreen.type === "streamable" && currentEmbedScreen.type === "streamable" &&
embedScreen.embed.uniqueId !== currentEmbedScreen.embed.uniqueId) embedScreen.embed.uniqueId !== currentEmbedScreen.embed.uniqueId)

View File

@ -19,6 +19,10 @@ export class PathfindingManager {
this.setEasyStarGrid(collisionsGrid); this.setEasyStarGrid(collisionsGrid);
} }
public setCollisionGrid(collisionGrid: number[][]): void {
this.setEasyStarGrid(collisionGrid);
}
public async findPath( public async findPath(
start: { x: number; y: number }, start: { x: number; y: number },
end: { x: number; y: number }, end: { x: number; y: number },

View File

@ -0,0 +1,17 @@
import type CancelablePromise from "cancelable-promise";
import type { Readable, Writable } from "svelte/store";
export type CoWebsiteState = "asleep" | "loading" | "ready";
export interface CoWebsite {
getId(): string;
getUrl(): URL;
getState(): CoWebsiteState;
getStateSubscriber(): Readable<CoWebsiteState>;
getIframe(): HTMLIFrameElement | undefined;
getLoadIframe(): CancelablePromise<HTMLIFrameElement> | undefined;
getWidthPercent(): number | undefined;
isClosable(): boolean;
load(): CancelablePromise<HTMLIFrameElement>;
unload(): Promise<void>;
}

View File

@ -0,0 +1,61 @@
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;
}
load(): CancelablePromise<HTMLIFrameElement> {
return new CancelablePromise((resolve, reject, cancel) => {
this.state.set("loading");
gameManager.getCurrentGameScene().disableMediaBehaviors();
jitsiFactory.restart();
if (!this.jitsiLoadPromise) {
return reject("Undefined Jitsi start callback");
}
const jitsiLoading = this.jitsiLoadPromise()
.then((iframe) => {
this.iframe = iframe;
this.iframe.classList.add("pixel");
this.state.set("ready");
return resolve(iframe);
})
.catch((err) => {
return reject(err);
});
cancel(() => {
jitsiLoading.cancel();
this.unload().catch((err) => {
console.error("Cannot unload Jitsi co-website while cancel loading", err);
});
});
});
}
unload(): Promise<void> {
jitsiFactory.destroy();
gameManager.getCurrentGameScene().enableMediaBehaviors();
return super.unload();
}
}

View File

@ -0,0 +1,133 @@
import CancelablePromise from "cancelable-promise";
import { get, Readable, writable, Writable } from "svelte/store";
import { iframeListener } from "../../Api/IframeListener";
import { coWebsiteManager } from "../CoWebsiteManager";
import type { CoWebsite, CoWebsiteState } from "./CoWesbite";
export class SimpleCoWebsite implements CoWebsite {
protected id: string;
protected url: URL;
protected state: Writable<CoWebsiteState>;
protected iframe?: HTMLIFrameElement;
protected loadIframe?: CancelablePromise<HTMLIFrameElement>;
protected allowApi?: boolean;
protected allowPolicy?: string;
protected widthPercent?: number;
protected closable: boolean;
constructor(url: URL, allowApi?: boolean, allowPolicy?: string, widthPercent?: number, closable?: boolean) {
this.id = coWebsiteManager.generateUniqueId();
this.url = url;
this.state = writable("asleep" as CoWebsiteState);
this.allowApi = allowApi;
this.allowPolicy = allowPolicy;
this.widthPercent = widthPercent;
this.closable = closable ?? false;
}
getId(): string {
return this.id;
}
getUrl(): URL {
return this.url;
}
getState(): CoWebsiteState {
return get(this.state);
}
getStateSubscriber(): Readable<CoWebsiteState> {
return this.state;
}
getIframe(): HTMLIFrameElement | undefined {
return this.iframe;
}
getLoadIframe(): CancelablePromise<HTMLIFrameElement> | undefined {
return this.loadIframe;
}
getWidthPercent(): number | undefined {
return this.widthPercent;
}
isClosable(): boolean {
return this.closable;
}
load(): CancelablePromise<HTMLIFrameElement> {
this.loadIframe = new CancelablePromise((resolve, reject, cancel) => {
this.state.set("loading");
const iframe = document.createElement("iframe");
this.iframe = iframe;
this.iframe.src = this.url.toString();
this.iframe.id = this.id;
if (this.allowPolicy) {
this.iframe.allow = this.allowPolicy;
}
if (this.allowApi) {
iframeListener.registerIframe(this.iframe);
}
this.iframe.classList.add("pixel");
const onloadPromise = new Promise<void>((resolve) => {
if (this.iframe) {
this.iframe.onload = () => {
this.state.set("ready");
resolve();
};
}
});
const onTimeoutPromise = new Promise<void>((resolve) => {
setTimeout(() => resolve(), 2000);
});
coWebsiteManager.getCoWebsiteBuffer().appendChild(this.iframe);
const race = CancelablePromise.race([onloadPromise, onTimeoutPromise])
.then(() => {
return resolve(iframe);
})
.catch((err) => {
console.error("Error on co-website loading => ", err);
return reject();
});
cancel(() => {
race.cancel();
this.unload().catch((err) => {
console.error("Cannot unload co-website while cancel loading", err);
});
});
});
return this.loadIframe;
}
unload(): Promise<void> {
return new Promise((resolve) => {
if (this.iframe) {
if (this.allowApi) {
iframeListener.unregisterIframe(this.iframe);
}
this.iframe.parentNode?.removeChild(this.iframe);
}
if (this.loadIframe) {
this.loadIframe.cancel();
this.loadIframe = undefined;
}
this.state.set("asleep");
resolve();
});
}
}

View File

@ -1,14 +1,13 @@
import { HtmlUtils } from "./HtmlUtils"; import { HtmlUtils } from "./HtmlUtils";
import { Subject } from "rxjs"; import { Subject } from "rxjs";
import { iframeListener } from "../Api/IframeListener";
import { waScaleManager } from "../Phaser/Services/WaScaleManager"; import { waScaleManager } from "../Phaser/Services/WaScaleManager";
import { coWebsites, coWebsitesNotAsleep, mainCoWebsite } from "../Stores/CoWebsiteStore"; import { coWebsites, coWebsitesNotAsleep, jitsiCoWebsite, mainCoWebsite } from "../Stores/CoWebsiteStore";
import { get, Writable, writable } from "svelte/store"; import { get } from "svelte/store";
import { embedScreenLayout, highlightedEmbedScreen } from "../Stores/EmbedScreensStore"; import { embedScreenLayout, highlightedEmbedScreen } from "../Stores/EmbedScreensStore";
import { isMediaBreakpointDown } from "../Utils/BreakpointsUtils"; import { isMediaBreakpointDown } from "../Utils/BreakpointsUtils";
import { jitsiFactory } from "./JitsiFactory";
import { gameManager } from "../Phaser/Game/GameManager";
import { LayoutMode } from "./LayoutManager"; import { LayoutMode } from "./LayoutManager";
import type { CoWebsite } from "./CoWebsite/CoWesbite";
import type CancelablePromise from "cancelable-promise";
export enum iframeStates { export enum iframeStates {
closed = 1, closed = 1,
@ -34,30 +33,12 @@ interface TouchMoveCoordinates {
y: number; y: number;
} }
export type CoWebsiteState = "asleep" | "loading" | "ready";
export type CoWebsite = {
iframe: HTMLIFrameElement;
url: URL;
state: Writable<CoWebsiteState>;
closable: boolean;
allowPolicy: string | undefined;
allowApi: boolean | undefined;
widthPercent?: number | undefined;
jitsi?: boolean;
altMessage?: string;
};
class CoWebsiteManager { class CoWebsiteManager {
private openedMain: iframeStates = iframeStates.closed; private openedMain: iframeStates = iframeStates.closed;
private _onResize: Subject<void> = new Subject(); private _onResize: Subject<void> = new Subject();
public onResize = this._onResize.asObservable(); public onResize = this._onResize.asObservable();
/**
* Quickly going in and out of an iframe trigger can create conflicts between the iframe states.
* So we use this promise to queue up every cowebsite state transition
*/
private currentOperationPromise: Promise<void> = Promise.resolve();
private cowebsiteDom: HTMLDivElement; private cowebsiteDom: HTMLDivElement;
private resizing: boolean = false; private resizing: boolean = false;
private gameOverlayDom: HTMLDivElement; private gameOverlayDom: HTMLDivElement;
@ -147,13 +128,11 @@ class CoWebsiteManager {
throw new Error("Undefined main co-website on closing"); throw new Error("Undefined main co-website on closing");
} }
if (coWebsite.closable) { if (coWebsite.isClosable()) {
this.closeCoWebsite(coWebsite).catch(() => { this.closeCoWebsite(coWebsite);
console.error("Error during closing a co-website by a button");
});
} else { } else {
this.unloadCoWebsite(coWebsite).catch(() => { this.unloadCoWebsite(coWebsite).catch((err) => {
console.error("Error during unloading a co-website by a button"); console.error("Cannot unload co-website on click on close button", err);
}); });
} }
}); });
@ -241,7 +220,10 @@ class CoWebsiteManager {
return; return;
} }
coWebsite.iframe.style.display = "none"; const iframe = coWebsite.getIframe();
if (iframe) {
iframe.style.display = "none";
}
this.resizing = true; this.resizing = true;
document.addEventListener("mousemove", movecallback); document.addEventListener("mousemove", movecallback);
}); });
@ -257,7 +239,10 @@ class CoWebsiteManager {
return; return;
} }
coWebsite.iframe.style.display = "flex"; const iframe = coWebsite.getIframe();
if (iframe) {
iframe.style.display = "flex";
}
this.resizing = false; this.resizing = false;
}); });
@ -270,7 +255,10 @@ class CoWebsiteManager {
return; return;
} }
coWebsite.iframe.style.display = "none"; const iframe = coWebsite.getIframe();
if (iframe) {
iframe.style.display = "none";
}
this.resizing = true; this.resizing = true;
const touchEvent = event.touches[0]; const touchEvent = event.touches[0];
this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY }; this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY };
@ -289,7 +277,10 @@ class CoWebsiteManager {
return; return;
} }
coWebsite.iframe.style.display = "flex"; const iframe = coWebsite.getIframe();
if (iframe) {
iframe.style.display = "flex";
}
this.resizing = false; this.resizing = false;
}); });
} }
@ -313,9 +304,12 @@ class CoWebsiteManager {
public displayMain() { public displayMain() {
const coWebsite = this.getMainCoWebsite(); const coWebsite = this.getMainCoWebsite();
if (coWebsite) { if (coWebsite) {
coWebsite.iframe.style.display = "block"; const iframe = coWebsite.getIframe();
if (iframe) {
iframe.style.display = "block";
}
} }
this.loadMain(); this.loadMain(coWebsite?.getWidthPercent());
this.openMain(); this.openMain();
this.fire(); this.fire();
} }
@ -323,7 +317,10 @@ class CoWebsiteManager {
public hideMain() { public hideMain() {
const coWebsite = this.getMainCoWebsite(); const coWebsite = this.getMainCoWebsite();
if (coWebsite) { if (coWebsite) {
coWebsite.iframe.style.display = "none"; const iframe = coWebsite.getIframe();
if (iframe) {
iframe.style.display = "none";
}
} }
this.cowebsiteDom.classList.add("closing"); this.cowebsiteDom.classList.add("closing");
this.cowebsiteDom.classList.remove("opened"); this.cowebsiteDom.classList.remove("opened");
@ -409,7 +406,9 @@ class CoWebsiteManager {
} }
public getCoWebsiteById(coWebsiteId: string): CoWebsite | undefined { public getCoWebsiteById(coWebsiteId: string): CoWebsite | undefined {
return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.iframe.id === coWebsiteId); return get(coWebsites).find((coWebsite: CoWebsite) => {
return coWebsite.getId() === coWebsiteId;
});
} }
private getCoWebsiteByPosition(position: number): CoWebsite | undefined { private getCoWebsiteByPosition(position: number): CoWebsite | undefined {
@ -429,7 +428,9 @@ class CoWebsiteManager {
} }
private getPositionByCoWebsite(coWebsite: CoWebsite): number { private getPositionByCoWebsite(coWebsite: CoWebsite): number {
return get(coWebsites).findIndex((currentCoWebsite) => currentCoWebsite.iframe.id === coWebsite.iframe.id); return get(coWebsites).findIndex((currentCoWebsite) => {
return currentCoWebsite.getId() === coWebsite.getId();
});
} }
private getSlotByCowebsite(coWebsite: CoWebsite): HTMLDivElement | undefined { private getSlotByCowebsite(coWebsite: CoWebsite): HTMLDivElement | undefined {
@ -443,7 +444,7 @@ class CoWebsiteManager {
if (index === 0) { if (index === 0) {
id += "main"; id += "main";
} else { } else {
id += coWebsite.iframe.id; id += coWebsite.getId();
} }
const slot = HtmlUtils.getElementById<HTMLDivElement>(id); const slot = HtmlUtils.getElementById<HTMLDivElement>(id);
@ -460,60 +461,72 @@ class CoWebsiteManager {
const bounding = coWebsiteSlot.getBoundingClientRect(); const bounding = coWebsiteSlot.getBoundingClientRect();
coWebsite.iframe.style.top = bounding.top + "px"; const iframe = coWebsite.getIframe();
coWebsite.iframe.style.left = bounding.left + "px";
coWebsite.iframe.style.width = bounding.right - bounding.left + "px"; if (iframe) {
coWebsite.iframe.style.height = bounding.bottom - bounding.top + "px"; iframe.style.top = bounding.top + "px";
iframe.style.left = bounding.left + "px";
iframe.style.width = bounding.right - bounding.left + "px";
iframe.style.height = bounding.bottom - bounding.top + "px";
}
} }
public resizeAllIframes() { public resizeAllIframes() {
const mainCoWebsite = this.getCoWebsiteByPosition(0); const mainCoWebsite = this.getCoWebsiteByPosition(0);
const mainIframe = mainCoWebsite?.getIframe();
const highlightEmbed = get(highlightedEmbedScreen); const highlightEmbed = get(highlightedEmbedScreen);
get(coWebsites).forEach((coWebsite) => { get(coWebsites).forEach((coWebsite: CoWebsite) => {
const notMain = !mainCoWebsite || (mainCoWebsite && mainCoWebsite.iframe.id !== coWebsite.iframe.id); const iframe = coWebsite.getIframe();
if (!iframe) {
return;
}
const notMain = !mainCoWebsite || (mainCoWebsite && mainIframe && mainIframe.id !== iframe.id);
const notHighlighEmbed = const notHighlighEmbed =
!highlightEmbed || !highlightEmbed ||
(highlightEmbed && (highlightEmbed &&
(highlightEmbed.type !== "cowebsite" || (highlightEmbed.type !== "cowebsite" ||
(highlightEmbed.type === "cowebsite" && (highlightEmbed.type === "cowebsite" && highlightEmbed.embed.getId() !== coWebsite.getId())));
highlightEmbed.embed.iframe.id !== coWebsite.iframe.id)));
if (coWebsite.iframe.classList.contains("main") && notMain) { if (iframe.classList.contains("main") && notMain) {
coWebsite.iframe.classList.remove("main"); iframe.classList.remove("main");
} }
if (coWebsite.iframe.classList.contains("highlighted") && notHighlighEmbed) { if (iframe.classList.contains("highlighted") && notHighlighEmbed) {
coWebsite.iframe.classList.remove("highlighted"); iframe.classList.remove("highlighted");
coWebsite.iframe.classList.add("pixel"); iframe.classList.add("pixel");
coWebsite.iframe.style.top = "-1px"; iframe.style.top = "-1px";
coWebsite.iframe.style.left = "-1px"; iframe.style.left = "-1px";
} }
if (notMain && notHighlighEmbed) { if (notMain && notHighlighEmbed) {
coWebsite.iframe.classList.add("pixel"); iframe.classList.add("pixel");
coWebsite.iframe.style.top = "-1px"; iframe.style.top = "-1px";
coWebsite.iframe.style.left = "-1px"; iframe.style.left = "-1px";
} }
this.setIframeOffset(coWebsite); this.setIframeOffset(coWebsite);
}); });
if (mainCoWebsite) { if (mainIframe) {
mainCoWebsite.iframe.classList.add("main"); mainIframe.classList.add("main");
mainCoWebsite.iframe.classList.remove("pixel"); mainIframe.classList.remove("pixel");
} }
if (highlightEmbed && highlightEmbed.type === "cowebsite") { if (highlightEmbed && highlightEmbed.type === "cowebsite") {
highlightEmbed.embed.iframe.classList.add("highlighted"); const highlightEmbedIframe = highlightEmbed.embed.getIframe();
highlightEmbed.embed.iframe.classList.remove("pixel"); if (highlightEmbedIframe) {
highlightEmbedIframe.classList.add("highlighted");
highlightEmbedIframe.classList.remove("pixel");
}
} }
} }
private removeHighlightCoWebsite(coWebsite: CoWebsite) { private removeHighlightCoWebsite(coWebsite: CoWebsite) {
const highlighted = get(highlightedEmbedScreen); const highlighted = get(highlightedEmbedScreen);
if (highlighted && highlighted.type === "cowebsite" && highlighted.embed.iframe.id === coWebsite.iframe.id) { if (highlighted && highlighted.type === "cowebsite" && highlighted.embed.getId() === coWebsite.getId()) {
highlightedEmbedScreen.removeHighlight(); highlightedEmbedScreen.removeHighlight();
} }
} }
@ -526,7 +539,9 @@ class CoWebsiteManager {
this.closeMain(); this.closeMain();
} }
coWebsite.iframe.remove(); coWebsite.unload().catch((err) => {
console.error("Cannot unload cowebsite on remove from stack");
});
} }
public goToMain(coWebsite: CoWebsite) { public goToMain(coWebsite: CoWebsite) {
@ -538,8 +553,8 @@ class CoWebsiteManager {
isMediaBreakpointDown("lg") && isMediaBreakpointDown("lg") &&
get(embedScreenLayout) === LayoutMode.Presentation && get(embedScreenLayout) === LayoutMode.Presentation &&
mainCoWebsite && mainCoWebsite &&
mainCoWebsite.iframe.id !== coWebsite.iframe.id && mainCoWebsite.getId() !== coWebsite.getId() &&
get(mainCoWebsite.state) !== "asleep" mainCoWebsite.getState() !== "asleep"
) { ) {
highlightedEmbedScreen.toggleHighlight({ highlightedEmbedScreen.toggleHighlight({
type: "cowebsite", type: "cowebsite",
@ -551,25 +566,15 @@ class CoWebsiteManager {
} }
public searchJitsi(): CoWebsite | undefined { public searchJitsi(): CoWebsite | undefined {
return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.jitsi); return get(jitsiCoWebsite);
} }
private initialiseCowebsite(coWebsite: CoWebsite, position: number | undefined) { public addCoWebsiteToStore(coWebsite: CoWebsite, position: number | undefined) {
if (coWebsite.allowPolicy) {
coWebsite.iframe.allow = coWebsite.allowPolicy;
}
if (coWebsite.allowApi) {
iframeListener.registerIframe(coWebsite.iframe);
}
coWebsite.iframe.classList.add("pixel");
const coWebsitePosition = position === undefined ? get(coWebsites).length : position; const coWebsitePosition = position === undefined ? get(coWebsites).length : position;
coWebsites.add(coWebsite, coWebsitePosition); coWebsites.add(coWebsite, coWebsitePosition);
} }
private generateUniqueId() { public generateUniqueId() {
let id = undefined; let id = undefined;
do { do {
id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7); id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
@ -578,80 +583,11 @@ class CoWebsiteManager {
return id; return id;
} }
public addCoWebsite( public loadCoWebsite(coWebsite: CoWebsite): CancelablePromise<void> {
url: string,
base: string,
allowApi?: boolean,
allowPolicy?: string,
widthPercent?: number,
position?: number,
closable?: boolean,
altMessage?: string
): CoWebsite {
const iframe = document.createElement("iframe");
const fullUrl = new URL(url, base);
iframe.src = fullUrl.toString();
iframe.id = this.generateUniqueId();
const newCoWebsite: CoWebsite = {
iframe,
url: fullUrl,
state: writable("asleep" as CoWebsiteState),
closable: closable ?? false,
allowPolicy,
allowApi,
widthPercent,
altMessage,
};
this.initialiseCowebsite(newCoWebsite, position);
return newCoWebsite;
}
public addCoWebsiteFromIframe(
iframe: HTMLIFrameElement,
allowApi?: boolean,
allowPolicy?: string,
widthPercent?: number,
position?: number,
closable?: boolean,
jitsi?: boolean
): CoWebsite {
if (get(coWebsitesNotAsleep).length < 1) {
this.loadMain(widthPercent);
}
iframe.id = this.generateUniqueId();
const newCoWebsite: CoWebsite = {
iframe,
url: new URL(iframe.src),
state: writable("ready" as CoWebsiteState),
closable: closable ?? false,
allowPolicy,
allowApi,
widthPercent,
jitsi,
};
if (position === 0) {
this.openMain();
setTimeout(() => {
this.fire();
}, animationTime);
}
this.initialiseCowebsite(newCoWebsite, position);
return newCoWebsite;
}
public loadCoWebsite(coWebsite: CoWebsite): Promise<CoWebsite> {
if (get(coWebsitesNotAsleep).length < 1) { if (get(coWebsitesNotAsleep).length < 1) {
coWebsites.remove(coWebsite); coWebsites.remove(coWebsite);
coWebsites.add(coWebsite, 0); coWebsites.add(coWebsite, 0);
this.loadMain(coWebsite.widthPercent); this.loadMain(coWebsite.getWidthPercent());
} }
// Check if the main is hide // Check if the main is hide
@ -659,125 +595,73 @@ class CoWebsiteManager {
this.displayMain(); this.displayMain();
} }
coWebsite.state.set("loading"); const coWebsiteLloading = coWebsite
.load()
.then(() => {
const mainCoWebsite = this.getMainCoWebsite();
if (mainCoWebsite && mainCoWebsite.getId() === coWebsite.getId()) {
this.openMain();
const mainCoWebsite = this.getMainCoWebsite(); setTimeout(() => {
this.fire();
return new Promise((resolve, reject) => { }, animationTime);
const onloadPromise = new Promise<void>((resolve) => { }
coWebsite.iframe.onload = () => { this.resizeAllIframes();
coWebsite.state.set("ready"); })
resolve(); .catch((err) => {
}; console.error("Error on co-website loading => ", err);
this.removeCoWebsiteFromStack(coWebsite);
}); });
const onTimeoutPromise = new Promise<void>((resolve) => { return coWebsiteLloading;
setTimeout(() => resolve(), 2000);
});
this.cowebsiteBufferDom.appendChild(coWebsite.iframe);
if (coWebsite.jitsi) {
const gameScene = gameManager.getCurrentGameScene();
gameScene.disableMediaBehaviors();
jitsiFactory.restart();
}
this.currentOperationPromise = this.currentOperationPromise
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
.then(() => {
if (mainCoWebsite && mainCoWebsite.iframe.id === coWebsite.iframe.id) {
this.openMain();
setTimeout(() => {
this.fire();
}, animationTime);
}
return resolve(coWebsite);
})
.catch((err) => {
console.error("Error on co-website loading => ", err);
this.removeCoWebsiteFromStack(coWebsite);
return reject();
});
});
} }
public unloadCoWebsite(coWebsite: CoWebsite): Promise<void> { public unloadCoWebsite(coWebsite: CoWebsite): Promise<void> {
return new Promise((resolve, reject) => { this.removeHighlightCoWebsite(coWebsite);
this.removeHighlightCoWebsite(coWebsite);
coWebsite.iframe.parentNode?.removeChild(coWebsite.iframe); return coWebsite
coWebsite.state.set("asleep"); .unload()
coWebsites.remove(coWebsite); .then(() => {
coWebsites.remove(coWebsite);
const mainCoWebsite = this.getMainCoWebsite();
if (coWebsite.jitsi) { if (mainCoWebsite) {
jitsiFactory.stop(); this.removeHighlightCoWebsite(mainCoWebsite);
const gameScene = gameManager.getCurrentGameScene(); this.goToMain(mainCoWebsite);
gameScene.enableMediaBehaviors(); this.resizeAllIframes();
} } else {
this.closeMain();
}
const mainCoWebsite = this.getMainCoWebsite(); coWebsites.add(coWebsite, get(coWebsites).length);
})
if (mainCoWebsite) { .catch(() => {
this.removeHighlightCoWebsite(mainCoWebsite); console.error();
this.goToMain(mainCoWebsite);
this.resizeAllIframes();
} else {
this.closeMain();
}
coWebsites.add(coWebsite, get(coWebsites).length);
resolve();
});
}
public closeCoWebsite(coWebsite: CoWebsite): Promise<void> {
this.currentOperationPromise = this.currentOperationPromise.then(
() =>
new Promise((resolve) => {
if (coWebsite.jitsi) {
jitsiFactory.destroy();
const gameScene = gameManager.getCurrentGameScene();
gameScene.enableMediaBehaviors();
}
if (get(coWebsites).length === 1) {
this.fire();
}
if (coWebsite.allowApi) {
iframeListener.unregisterIframe(coWebsite.iframe);
}
this.removeCoWebsiteFromStack(coWebsite);
const mainCoWebsite = this.getMainCoWebsite();
if (mainCoWebsite) {
this.removeHighlightCoWebsite(mainCoWebsite);
this.goToMain(mainCoWebsite);
this.resizeAllIframes();
} else {
this.closeMain();
}
resolve();
})
);
return this.currentOperationPromise;
}
public closeCoWebsites(): Promise<void> {
return (this.currentOperationPromise = this.currentOperationPromise.then(() => {
get(coWebsites).forEach((coWebsite: CoWebsite) => {
this.closeCoWebsite(coWebsite).catch(() => {
console.error("Error during closing a co-website");
});
}); });
})); }
return this.currentOperationPromise;
public closeCoWebsite(coWebsite: CoWebsite): void {
if (get(coWebsites).length === 1) {
this.fire();
}
this.removeCoWebsiteFromStack(coWebsite);
const mainCoWebsite = this.getMainCoWebsite();
if (mainCoWebsite) {
this.removeHighlightCoWebsite(mainCoWebsite);
this.goToMain(mainCoWebsite);
this.resizeAllIframes();
} else {
this.closeMain();
}
}
public closeCoWebsites(): void {
get(coWebsites).forEach((coWebsite: CoWebsite) => {
this.closeCoWebsite(coWebsite);
});
} }
public getGameSize(): { width: number; height: number } { public getGameSize(): { width: number; height: number } {

View File

@ -1,7 +1,9 @@
import { JITSI_URL } from "../Enum/EnvironmentVariable"; import { JITSI_URL } from "../Enum/EnvironmentVariable";
import { CoWebsite, coWebsiteManager } from "./CoWebsiteManager"; import { coWebsiteManager } from "./CoWebsiteManager";
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore"; import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
import { get } from "svelte/store"; import { get } from "svelte/store";
import type { CoWebsite } from "./CoWebsite/CoWesbite";
import CancelablePromise from "cancelable-promise";
interface jitsiConfigInterface { interface jitsiConfigInterface {
startWithAudioMuted: boolean; startWithAudioMuted: boolean;
@ -134,92 +136,90 @@ class JitsiFactory {
return slugify(instance.replace("/", "-") + "-" + roomName); return slugify(instance.replace("/", "-") + "-" + roomName);
} }
public async start( public start(
roomName: string, roomName: string,
playerName: string, playerName: string,
jwt?: string, jwt?: string,
config?: object, config?: object,
interfaceConfig?: object, interfaceConfig?: object,
jitsiUrl?: string jitsiUrl?: string
) { ): CancelablePromise<HTMLIFrameElement> {
const coWebsite = coWebsiteManager.searchJitsi(); return new CancelablePromise((resolve, reject, cancel) => {
// Jitsi meet external API maintains some data in local storage
// which is sent via the appData URL parameter when joining a
// conference. Problem is that this data grows indefinitely. Thus
// after some time the URLs get so huge that loading the iframe
// becomes slow and eventually breaks completely. Thus lets just
// clear jitsi local storage before starting a new conference.
window.localStorage.removeItem("jitsiLocalStorage");
if (coWebsite) { const domain = jitsiUrl || JITSI_URL;
await coWebsiteManager.closeCoWebsite(coWebsite); if (domain === undefined) {
} throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
// Jitsi meet external API maintains some data in local storage
// which is sent via the appData URL parameter when joining a
// conference. Problem is that this data grows indefinitely. Thus
// after some time the URLs get so huge that loading the iframe
// becomes slow and eventually breaks completely. Thus lets just
// clear jitsi local storage before starting a new conference.
window.localStorage.removeItem("jitsiLocalStorage");
const domain = jitsiUrl || JITSI_URL;
if (domain === undefined) {
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
}
await this.loadJitsiScript(domain);
const options: JitsiOptions = {
roomName: roomName,
jwt: jwt,
width: "100%",
height: "100%",
parentNode: coWebsiteManager.getCoWebsiteBuffer(),
configOverwrite: mergeConfig(config),
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
};
if (!options.jwt) {
delete options.jwt;
}
const doResolve = (): void => {
const iframe = coWebsiteManager.getCoWebsiteBuffer().querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
if (iframe && this.jitsiApi) {
const coWebsite = coWebsiteManager.addCoWebsiteFromIframe(
iframe,
false,
undefined,
undefined,
0,
false,
true
);
this.jitsiApi.addListener("videoConferenceLeft", () => {
this.closeOrUnload(coWebsite);
});
this.jitsiApi.addListener("readyToClose", () => {
this.closeOrUnload(coWebsite);
});
} }
coWebsiteManager.resizeAllIframes(); const loadScript = this.loadJitsiScript(domain).then(() => {
}; const options: JitsiOptions = {
roomName: roomName,
jwt: jwt,
width: "100%",
height: "100%",
parentNode: coWebsiteManager.getCoWebsiteBuffer(),
configOverwrite: mergeConfig(config),
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
};
this.jitsiApi = undefined; if (!options.jwt) {
delete options.jwt;
}
options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations. const timemout = setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
this.jitsiApi.executeCommand("displayName", playerName);
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback); const doResolve = (): void => {
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback); clearTimeout(timemout);
const iframe = coWebsiteManager
.getCoWebsiteBuffer()
.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
if (iframe && this.jitsiApi) {
this.jitsiApi.addListener("videoConferenceLeft", () => {
this.closeOrUnload();
});
this.jitsiApi.addListener("readyToClose", () => {
this.closeOrUnload();
});
return resolve(iframe);
}
};
this.jitsiApi = undefined;
options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations.
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
this.jitsiApi.executeCommand("displayName", playerName);
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
});
cancel(() => {
loadScript.cancel();
});
});
} }
private closeOrUnload = function (coWebsite: CoWebsite) { private closeOrUnload = function () {
if (coWebsite.closable) { const coWebsite = coWebsiteManager.searchJitsi();
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => { if (!coWebsite) {
console.error("Error during closing a Jitsi Meet"); return;
}); }
if (coWebsite.isClosable()) {
coWebsiteManager.closeCoWebsite(coWebsite);
} else { } else {
coWebsiteManager.unloadCoWebsite(coWebsite).catch(() => { coWebsiteManager.unloadCoWebsite(coWebsite).catch((err) => {
console.error("Error during unloading a Jitsi Meet"); console.error("Cannot unload co-website from the Jitsi factory", err);
}); });
} }
}; };
@ -233,8 +233,6 @@ class JitsiFactory {
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback); this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
const coWebsite = coWebsiteManager.searchJitsi(); const coWebsite = coWebsiteManager.searchJitsi();
console.log("jitsi api ", this.jitsiApi);
console.log("iframe cowebsite", coWebsite?.iframe);
if (!coWebsite) { if (!coWebsite) {
this.destroy(); this.destroy();
@ -242,11 +240,11 @@ class JitsiFactory {
} }
this.jitsiApi.addListener("videoConferenceLeft", () => { this.jitsiApi.addListener("videoConferenceLeft", () => {
this.closeOrUnload(coWebsite); this.closeOrUnload();
}); });
this.jitsiApi.addListener("readyToClose", () => { this.jitsiApi.addListener("readyToClose", () => {
this.closeOrUnload(coWebsite); this.closeOrUnload();
}); });
} }
@ -284,8 +282,8 @@ class JitsiFactory {
} }
} }
private async loadJitsiScript(domain: string): Promise<void> { private loadJitsiScript(domain: string): CancelablePromise<void> {
return new Promise<void>((resolve, reject) => { return new CancelablePromise<void>((resolve, reject, cancel) => {
if (this.jitsiScriptLoaded) { if (this.jitsiScriptLoaded) {
resolve(); resolve();
return; return;
@ -304,6 +302,10 @@ class JitsiFactory {
}; };
document.head.appendChild(jitsiScript); document.head.appendChild(jitsiScript);
cancel(() => {
jitsiScript.remove();
});
}); });
} }
} }

View File

@ -0,0 +1,197 @@
{ "compressionlevel":-1,
"height":30,
"infinite":false,
"layers":[
{
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 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, 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, 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, 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, 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":30,
"id":1,
"name":"floor",
"opacity":1,
"properties":[
{
"name":"openWebsite",
"type":"string",
"value":"script.php"
},
{
"name":"openWebsiteAllowApi",
"type":"bool",
"value":true
}],
"type":"tilelayer",
"visible":true,
"width":30,
"x":0,
"y":0
},
{
"data":[17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 6, 6, 6, 6, 6, 0, 0, 6, 6, 6, 6, 6, 6, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 17, 17, 17, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 28, 28, 28, 28, 28, 28, 0, 0, 28, 28, 28, 28, 28, 28, 28, 29, 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, 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, 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, 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, 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, 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, 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, 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":30,
"id":6,
"name":"furnitures",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":30,
"x":0,
"y":0
},
{
"data":[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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 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, 73, 74, 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, 73, 74, 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, 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, 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, 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, 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, 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, 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, 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":30,
"id":8,
"name":"closedPath",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":30,
"x":0,
"y":0
},
{
"data":[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, 74, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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":30,
"id":2,
"name":"start",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":30,
"x":0,
"y":0
},
{
"draworder":"topdown",
"id":3,
"name":"floorLayer",
"objects":[
{
"height":101.5,
"id":11,
"name":"",
"rotation":0,
"text":
{
"text":"You should be able to get here only if the path isn't blocked",
"wrap":true
},
"type":"",
"visible":true,
"width":383,
"x":81.226595249185,
"y":297.048206800186
},
{
"height":101.5,
"id":12,
"name":"",
"rotation":0,
"text":
{
"text":"Try to move to the next room by using right-click \/ tap movement. Click \"Toggle Door\" button to block \/ make access.",
"wrap":true
},
"type":"",
"visible":true,
"width":383,
"x":81,
"y":99.75
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":9,
"nextobjectid":13,
"orientation":"orthogonal",
"properties":[
{
"name":"openWebsite",
"type":"string",
"value":"script.php"
},
{
"name":"openWebsiteAllowApi",
"type":"bool",
"value":true
}],
"renderorder":"right-down",
"tiledversion":"1.7.2",
"tileheight":32,
"tilesets":[
{
"columns":11,
"firstgid":1,
"image":"..\/tileset1.png",
"imageheight":352,
"imagewidth":352,
"margin":0,
"name":"tileset1",
"spacing":0,
"tilecount":121,
"tileheight":32,
"tiles":[
{
"id":16,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":17,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":27,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":28,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":72,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
},
{
"id":73,
"properties":[
{
"name":"collides",
"type":"bool",
"value":true
}]
}],
"tilewidth":32
}],
"tilewidth":32,
"type":"map",
"version":"1.6",
"width":30
}

View File

@ -0,0 +1,26 @@
<!doctype html>
<html lang="en">
<head>
<script src="<?php echo $_SERVER["FRONT_URL"] ?>/iframe_api.js"></script>
<script>
let closed = true;
window.addEventListener('load', () => {
//@ts-ignore
WA.onInit().then(() => {
console.log('After WA init');
const toogleDoorButton = document.getElementById('toogleDoorButton');
toogleDoorButton.addEventListener('click', async () => {
closed ? WA.room.hideLayer('closedPath') : WA.room.showLayer('closedPath');
closed = !closed;
});
});
})
</script>
</head>
<body>
<button id="toogleDoorButton">Toggle Door</button>
</body>
</html>

View File

@ -34,7 +34,7 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<input type="radio" name="test-animated-tiles"> Success <input type="radio" name="test-animated-tiles"> Failure <input type="radio" name="test-animated-tiles" checked> Pending <input type="radio" name="test-parallax-effect"> Success <input type="radio" name="test-parallax-effect"> Failure <input type="radio" name="test-parallax-effect" checked> Pending
</td> </td>
<td> <td>
<a href="#" class="testLink" data-testmap="parallax.json" target="_blank">Test parallax effect</a> <a href="#" class="testLink" data-testmap="parallax.json" target="_blank">Test parallax effect</a>
@ -48,6 +48,14 @@
<a href="#" class="testLink" data-testmap="animated_tiles.json" target="_blank">Test animated tiles</a> <a href="#" class="testLink" data-testmap="animated_tiles.json" target="_blank">Test animated tiles</a>
</td> </td>
</tr> </tr>
<tr>
<td>
<input type="radio" name="test-door-map"> Success <input type="radio" name="test-door-map"> Failure <input type="radio" name="test-door-map" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="DoorTest/map.json" target="_blank">Test Doors</a>
</td>
</tr>
<tr> <tr>
<td> <td>
<input type="radio" name="test-start-tile-S1"> Success <input type="radio" name="test-start-tile-S1"> Failure <input type="radio" name="test-start-tile-S1" checked> Pending <input type="radio" name="test-start-tile-S1"> Success <input type="radio" name="test-start-tile-S1"> Failure <input type="radio" name="test-start-tile-S1" checked> Pending