Merge branch 'develop' of github.com:thecodingmachine/workadventure into move-to-improvements
This commit is contained in:
commit
0b82df0d41
@ -1,20 +1,118 @@
|
|||||||
|
# Security
|
||||||
|
#
|
||||||
|
|
||||||
|
SECRET_KEY=
|
||||||
|
ADMIN_API_TOKEN=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Networking
|
||||||
|
#
|
||||||
|
|
||||||
# The base domain
|
# The base domain
|
||||||
DOMAIN=workadventure.localhost
|
DOMAIN=workadventure.localhost
|
||||||
|
|
||||||
DEBUG_MODE=false
|
# Subdomains
|
||||||
|
# MUST match the DOMAIN variable above
|
||||||
|
FRONT_HOST=front.workadventure.localhost
|
||||||
|
PUSHER_HOST=pusher.workadventure.localhost
|
||||||
|
BACK_HOST=api.workadventure.localhost
|
||||||
|
MAPS_HOST=maps.workadventure.localhost
|
||||||
|
ICON_HOST=icon.workadventure.localhost
|
||||||
|
|
||||||
|
# SAAS admin panel
|
||||||
|
ADMIN_API_URL=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Basic configuration
|
||||||
|
#
|
||||||
|
|
||||||
|
# The directory to store data in
|
||||||
|
DATA_DIR=./wa
|
||||||
|
|
||||||
|
# The URL used by default, in the form: "/_/global/map/url.json"
|
||||||
|
START_ROOM_URL=/_/global/maps.workadventu.re/Floor0/floor0.json
|
||||||
|
|
||||||
|
# If you want to have a contact page in your menu,
|
||||||
|
# you MUST set CONTACT_URL to the URL of the page that you want
|
||||||
|
CONTACT_URL=
|
||||||
|
|
||||||
|
MAX_PER_GROUP=4
|
||||||
|
MAX_USERNAME_LENGTH=8
|
||||||
|
DISABLE_ANONYMOUS=false
|
||||||
|
|
||||||
|
# The version of the docker image to use
|
||||||
|
# MUST uncomment "image" keys in the docker-compose file for it to be effective
|
||||||
|
VERSION=master
|
||||||
|
|
||||||
|
TZ=Europe/Paris
|
||||||
|
|
||||||
|
#
|
||||||
|
# Jitsi
|
||||||
|
#
|
||||||
|
|
||||||
JITSI_URL=meet.jit.si
|
JITSI_URL=meet.jit.si
|
||||||
# If your Jitsi environment has authentication set up, you MUST set JITSI_PRIVATE_MODE to "true" and you MUST pass a SECRET_JITSI_KEY to generate the JWT secret
|
# If your Jitsi environment has authentication set up,
|
||||||
|
# you MUST set JITSI_PRIVATE_MODE to "true"
|
||||||
|
# and you MUST pass a SECRET_JITSI_KEY to generate the JWT secret
|
||||||
JITSI_PRIVATE_MODE=false
|
JITSI_PRIVATE_MODE=false
|
||||||
JITSI_ISS=
|
JITSI_ISS=
|
||||||
SECRET_JITSI_KEY=
|
SECRET_JITSI_KEY=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Turn/Stun
|
||||||
|
#
|
||||||
|
|
||||||
# URL of the TURN server (needed to "punch a hole" through some networks for P2P connections)
|
# URL of the TURN server (needed to "punch a hole" through some networks for P2P connections)
|
||||||
TURN_SERVER=
|
TURN_SERVER=
|
||||||
TURN_USER=
|
TURN_USER=
|
||||||
TURN_PASSWORD=
|
TURN_PASSWORD=
|
||||||
|
# If your Turn server is configured to use the Turn REST API, you MUST put the shared auth secret here.
|
||||||
|
# If you are using Coturn, this is the value of the "static-auth-secret" parameter in your coturn config file.
|
||||||
|
# Keep empty if you are sharing hard coded / clear text credentials.
|
||||||
|
TURN_STATIC_AUTH_SECRET=
|
||||||
|
# URL of the STUN server
|
||||||
|
STUN_SERVER=
|
||||||
|
|
||||||
# The URL used by default, in the form: "/_/global/map/url.json"
|
#
|
||||||
START_ROOM_URL=/_/global/maps.workadventu.re/Floor0/floor0.json
|
# Certificate config
|
||||||
|
#
|
||||||
|
|
||||||
# The email address used by Let's encrypt to send renewal warnings (compulsory)
|
# The email address used by Let's encrypt to send renewal warnings (compulsory)
|
||||||
ACME_EMAIL=
|
ACME_EMAIL=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Additional app configs
|
||||||
|
# Configuration for apps which are not workadventure itself
|
||||||
|
#
|
||||||
|
|
||||||
|
# openID
|
||||||
|
OPID_CLIENT_ID=
|
||||||
|
OPID_CLIENT_SECRET=
|
||||||
|
OPID_CLIENT_ISSUER=
|
||||||
|
OPID_CLIENT_REDIRECT_URL=
|
||||||
|
OPID_LOGIN_SCREEN_PROVIDER=http://pusher.workadventure.localhost/login-screen
|
||||||
|
OPID_PROFILE_SCREEN_PROVIDER=
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Advanced configuration
|
||||||
|
# Generally does not need to be changed
|
||||||
|
#
|
||||||
|
|
||||||
|
# Networking
|
||||||
|
HTTP_PORT=80
|
||||||
|
HTTPS_PORT=443
|
||||||
|
|
||||||
|
# Workadventure settings
|
||||||
|
DISABLE_NOTIFICATIONS=false
|
||||||
|
SKIP_RENDER_OPTIMIZATIONS=false
|
||||||
|
STORE_VARIABLES_FOR_LOCAL_MAPS=true
|
||||||
|
|
||||||
|
# Debugging options
|
||||||
|
DEBUG_MODE=false
|
||||||
|
LOG_LEVEL=WARN
|
||||||
|
|
||||||
|
# Internal URLs
|
||||||
|
API_URL=back:50051
|
||||||
|
|
||||||
|
RESTART_POLICY=unless-stopped
|
||||||
|
@ -1,114 +1,128 @@
|
|||||||
version: "3.3"
|
version: "3.5"
|
||||||
services:
|
services:
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
image: traefik:v2.3
|
image: traefik:v2.6
|
||||||
command:
|
command:
|
||||||
- --log.level=WARN
|
- --log.level=${LOG_LEVEL}
|
||||||
#- --api.insecure=true
|
|
||||||
- --providers.docker
|
- --providers.docker
|
||||||
- --entryPoints.web.address=:80
|
# Entry points
|
||||||
|
- --entryPoints.web.address=:${HTTP_PORT}
|
||||||
- --entrypoints.web.http.redirections.entryPoint.to=websecure
|
- --entrypoints.web.http.redirections.entryPoint.to=websecure
|
||||||
- --entrypoints.web.http.redirections.entryPoint.scheme=https
|
- --entrypoints.web.http.redirections.entryPoint.scheme=https
|
||||||
- --entryPoints.websecure.address=:443
|
- --entryPoints.websecure.address=:${HTTPS_PORT}
|
||||||
|
# HTTP challenge
|
||||||
- --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}
|
- --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}
|
||||||
- --certificatesresolvers.myresolver.acme.storage=/acme.json
|
- --certificatesresolvers.myresolver.acme.storage=/acme.json
|
||||||
# used during the challenge
|
|
||||||
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||||
|
# Let's Encrypt's staging server
|
||||||
|
# uncomment during testing to avoid rate limiting
|
||||||
|
#- --certificatesresolvers.dnsresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "${HTTP_PORT}:80"
|
||||||
- "443:443"
|
- "${HTTPS_PORT}:443"
|
||||||
# The Web UI (enabled by --api.insecure=true)
|
|
||||||
#- "8080:8080"
|
|
||||||
depends_on:
|
|
||||||
- pusher
|
|
||||||
- front
|
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ./acme.json:/acme.json
|
- ${DATA_DIR}/letsencrypt/acme.json:/acme.json
|
||||||
restart: unless-stopped
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
|
|
||||||
front:
|
front:
|
||||||
build:
|
build:
|
||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: front/Dockerfile
|
dockerfile: front/Dockerfile
|
||||||
#image: thecodingmachine/workadventure-front:master
|
#image: thecodingmachine/workadventure-front:${VERSION}
|
||||||
environment:
|
environment:
|
||||||
DEBUG_MODE: "$DEBUG_MODE"
|
- DEBUG_MODE
|
||||||
JITSI_URL: $JITSI_URL
|
- JITSI_URL
|
||||||
JITSI_PRIVATE_MODE: "$JITSI_PRIVATE_MODE"
|
- JITSI_PRIVATE_MODE
|
||||||
PUSHER_URL: //pusher.${DOMAIN}
|
- PUSHER_URL=//${PUSHER_HOST}
|
||||||
ICON_URL: //icon.${DOMAIN}
|
- ICON_URL=//${ICON_HOST}
|
||||||
TURN_SERVER: "${TURN_SERVER}"
|
- TURN_SERVER
|
||||||
TURN_USER: "${TURN_USER}"
|
- TURN_USER
|
||||||
TURN_PASSWORD: "${TURN_PASSWORD}"
|
- TURN_PASSWORD
|
||||||
START_ROOM_URL: "${START_ROOM_URL}"
|
- TURN_STATIC_AUTH_SECRET
|
||||||
|
- STUN_SERVER
|
||||||
|
- START_ROOM_URL
|
||||||
|
- SKIP_RENDER_OPTIMIZATIONS
|
||||||
|
- MAX_PER_GROUP
|
||||||
|
- MAX_USERNAME_LENGTH
|
||||||
|
- DISABLE_ANONYMOUS
|
||||||
|
- DISABLE_NOTIFICATIONS
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.front.rule=Host(`play.${DOMAIN}`)"
|
- "traefik.http.routers.front.rule=Host(`${FRONT_HOST}`)"
|
||||||
- "traefik.http.routers.front.entryPoints=web,traefik"
|
- "traefik.http.routers.front.entryPoints=web"
|
||||||
- "traefik.http.services.front.loadbalancer.server.port=80"
|
- "traefik.http.services.front.loadbalancer.server.port=80"
|
||||||
- "traefik.http.routers.front-ssl.rule=Host(`play.${DOMAIN}`)"
|
- "traefik.http.routers.front-ssl.rule=Host(`${FRONT_HOST}`)"
|
||||||
- "traefik.http.routers.front-ssl.entryPoints=websecure"
|
- "traefik.http.routers.front-ssl.entryPoints=websecure"
|
||||||
- "traefik.http.routers.front-ssl.tls=true"
|
|
||||||
- "traefik.http.routers.front-ssl.service=front"
|
- "traefik.http.routers.front-ssl.service=front"
|
||||||
|
- "traefik.http.routers.front-ssl.tls=true"
|
||||||
- "traefik.http.routers.front-ssl.tls.certresolver=myresolver"
|
- "traefik.http.routers.front-ssl.tls.certresolver=myresolver"
|
||||||
restart: unless-stopped
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
pusher:
|
pusher:
|
||||||
build:
|
build:
|
||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: pusher/Dockerfile
|
dockerfile: pusher/Dockerfile
|
||||||
#image: thecodingmachine/workadventure-pusher:master
|
#image: thecodingmachine/workadventure-pusher:${VERSION}
|
||||||
command: yarn run runprod
|
command: yarn run runprod
|
||||||
environment:
|
environment:
|
||||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
- SECRET_JITSI_KEY
|
||||||
SECRET_KEY: yourSecretKey
|
- SECRET_KEY
|
||||||
API_URL: back:50051
|
- API_URL
|
||||||
JITSI_URL: $JITSI_URL
|
- FRONT_URL=https://${FRONT_HOST}
|
||||||
JITSI_ISS: $JITSI_ISS
|
- JITSI_URL
|
||||||
FRONT_URL: https://play.${DOMAIN}
|
- JITSI_ISS
|
||||||
|
- DISABLE_ANONYMOUS
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.pusher.rule=Host(`pusher.${DOMAIN}`)"
|
- "traefik.http.routers.pusher.rule=Host(`${PUSHER_HOST}`)"
|
||||||
- "traefik.http.routers.pusher.entryPoints=web,traefik"
|
- "traefik.http.routers.pusher.entryPoints=web"
|
||||||
- "traefik.http.services.pusher.loadbalancer.server.port=8080"
|
- "traefik.http.services.pusher.loadbalancer.server.port=8080"
|
||||||
- "traefik.http.routers.pusher-ssl.rule=Host(`pusher.${DOMAIN}`)"
|
- "traefik.http.routers.pusher-ssl.rule=Host(${PUSHER_HOST}`)"
|
||||||
- "traefik.http.routers.pusher-ssl.entryPoints=websecure"
|
- "traefik.http.routers.pusher-ssl.entryPoints=websecure"
|
||||||
- "traefik.http.routers.pusher-ssl.tls=true"
|
|
||||||
- "traefik.http.routers.pusher-ssl.service=pusher"
|
- "traefik.http.routers.pusher-ssl.service=pusher"
|
||||||
|
- "traefik.http.routers.pusher-ssl.tls=true"
|
||||||
- "traefik.http.routers.pusher-ssl.tls.certresolver=myresolver"
|
- "traefik.http.routers.pusher-ssl.tls.certresolver=myresolver"
|
||||||
restart: unless-stopped
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
back:
|
back:
|
||||||
build:
|
build:
|
||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: back/Dockerfile
|
dockerfile: back/Dockerfile
|
||||||
#image: thecodingmachine/workadventure-back:master
|
#image: thecodingmachine/workadventure-back:${VERSION}
|
||||||
command: yarn run runprod
|
command: yarn run runprod
|
||||||
environment:
|
environment:
|
||||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
- SECRET_JITSI_KEY
|
||||||
ADMIN_API_TOKEN: "$ADMIN_API_TOKEN"
|
- SECRET_KEY
|
||||||
ADMIN_API_URL: "$ADMIN_API_URL"
|
- ADMIN_API_TOKEN
|
||||||
JITSI_URL: $JITSI_URL
|
- ADMIN_API_URL
|
||||||
JITSI_ISS: $JITSI_ISS
|
- TURN_SERVER
|
||||||
|
- TURN_USER
|
||||||
|
- TURN_PASSWORD
|
||||||
|
- TURN_STATIC_AUTH_SECRET
|
||||||
|
- STUN_SERVER
|
||||||
|
- JITSI_URL
|
||||||
|
- JITSI_ISS
|
||||||
|
- MAX_PER_GROUP
|
||||||
|
- STORE_VARIABLES_FOR_LOCAL_MAPS
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.back.rule=Host(`api.${DOMAIN}`)"
|
- "traefik.http.routers.back.rule=Host(`${BACK_HOST}`)"
|
||||||
- "traefik.http.routers.back.entryPoints=web"
|
- "traefik.http.routers.back.entryPoints=web"
|
||||||
- "traefik.http.services.back.loadbalancer.server.port=8080"
|
- "traefik.http.services.back.loadbalancer.server.port=8080"
|
||||||
- "traefik.http.routers.back-ssl.rule=Host(`api.${DOMAIN}`)"
|
- "traefik.http.routers.back-ssl.rule=Host(`${BACK_HOST}`)"
|
||||||
- "traefik.http.routers.back-ssl.entryPoints=websecure"
|
- "traefik.http.routers.back-ssl.entryPoints=websecure"
|
||||||
- "traefik.http.routers.back-ssl.tls=true"
|
|
||||||
- "traefik.http.routers.back-ssl.service=back"
|
- "traefik.http.routers.back-ssl.service=back"
|
||||||
|
- "traefik.http.routers.back-ssl.tls=true"
|
||||||
- "traefik.http.routers.back-ssl.tls.certresolver=myresolver"
|
- "traefik.http.routers.back-ssl.tls.certresolver=myresolver"
|
||||||
restart: unless-stopped
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
icon:
|
icon:
|
||||||
image: matthiasluedtke/iconserver:v3.13.0
|
image: matthiasluedtke/iconserver:v3.13.0
|
||||||
labels:
|
labels:
|
||||||
- "traefik.http.routers.icon.rule=Host(`icon.${DOMAIN}`)"
|
- "traefik.http.routers.icon.rule=Host(`${ICON_HOST}`)"
|
||||||
- "traefik.http.routers.icon.entryPoints=web,traefik"
|
- "traefik.http.routers.icon.entryPoints=web,traefik"
|
||||||
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
||||||
- "traefik.http.routers.icon-ssl.rule=Host(`icon.${DOMAIN}`)"
|
- "traefik.http.routers.icon-ssl.rule=Host(`${ICON_HOST}`)"
|
||||||
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
||||||
- "traefik.http.routers.icon-ssl.tls=true"
|
|
||||||
- "traefik.http.routers.icon-ssl.service=icon"
|
- "traefik.http.routers.icon-ssl.service=icon"
|
||||||
|
- "traefik.http.routers.icon-ssl.tls=true"
|
||||||
- "traefik.http.routers.icon-ssl.tls.certresolver=myresolver"
|
- "traefik.http.routers.icon-ssl.tls.certresolver=myresolver"
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
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 { mainCoWebsite } 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 { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
|
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
|
||||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||||
|
|
||||||
@ -14,16 +15,15 @@
|
|||||||
|
|
||||||
let icon: HTMLImageElement;
|
let icon: HTMLImageElement;
|
||||||
let iconLoaded = false;
|
let iconLoaded = false;
|
||||||
let state = coWebsite.state;
|
let state = coWebsite.getStateSubscriber();
|
||||||
|
let isJitsi: boolean = coWebsite instanceof JitsiCoWebsite;
|
||||||
const coWebsiteUrl = coWebsite.iframe.src;
|
const mainState = coWebsiteManager.getMainStateSubscriber();
|
||||||
const urlObject = new URL(coWebsiteUrl);
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
icon.src = coWebsite.jitsi
|
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,21 +33,24 @@
|
|||||||
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;
|
if (coWebsiteManager.getMainState() === iframeStates.closed) {
|
||||||
const newMain = $highlightedEmbedScreen ?? coWebsites.length > 1 ? coWebsites[1] : undefined;
|
|
||||||
if (newMain && newMain.iframe.id !== $mainCoWebsite.iframe.id) {
|
|
||||||
coWebsiteManager.goToMain(newMain);
|
|
||||||
} else if (coWebsiteManager.getMainState() === iframeStates.closed) {
|
|
||||||
coWebsiteManager.displayMain();
|
coWebsiteManager.displayMain();
|
||||||
|
} else if ($highlightedEmbedScreen?.type === "cowebsite") {
|
||||||
|
coWebsiteManager.goToMain($highlightedEmbedScreen.embed);
|
||||||
} else {
|
} else {
|
||||||
coWebsiteManager.hideMain();
|
coWebsiteManager.hideMain();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
highlightedEmbedScreen.toggleHighlight({
|
if (coWebsiteManager.getMainState() === iframeStates.closed) {
|
||||||
type: "cowebsite",
|
coWebsiteManager.goToMain(coWebsite);
|
||||||
embed: coWebsite,
|
coWebsiteManager.displayMain();
|
||||||
});
|
} else {
|
||||||
|
highlightedEmbedScreen.toggleHighlight({
|
||||||
|
type: "cowebsite",
|
||||||
|
embed: coWebsite,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,11 +68,14 @@
|
|||||||
let isHighlight: boolean = false;
|
let isHighlight: boolean = false;
|
||||||
let isMain: boolean = false;
|
let isMain: boolean = false;
|
||||||
$: {
|
$: {
|
||||||
isMain = $mainCoWebsite !== undefined && $mainCoWebsite.iframe === coWebsite.iframe;
|
isMain =
|
||||||
|
$mainState === iframeStates.opened &&
|
||||||
|
$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 +92,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=""
|
||||||
@ -213,7 +219,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:not(.vertical) {
|
&:not(.vertical) {
|
||||||
animation: bounce 0.35s ease 6 alternate;
|
transition: all 300ms;
|
||||||
|
transform: translateY(0px);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.vertical {
|
&.vertical {
|
||||||
@ -234,7 +241,7 @@
|
|||||||
|
|
||||||
&.displayed {
|
&.displayed {
|
||||||
&:not(.vertical) {
|
&:not(.vertical) {
|
||||||
animation: activeThumbnail 300ms ease-in 0s forwards;
|
transform: translateY(-15px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,16 +270,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes activeThumbnail {
|
|
||||||
0% {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: translateY(-15px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes bounce {
|
@keyframes bounce {
|
||||||
from {
|
from {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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[] = [];
|
||||||
@ -333,6 +333,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;
|
||||||
}
|
}
|
||||||
|
@ -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,19 @@ 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,
|
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||||
OPENED,
|
import { JITSI_PRIVATE_MODE, JITSI_URL } from "../../Enum/EnvironmentVariable";
|
||||||
MUST_BE_CLOSE,
|
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 {
|
interface OpenCoWebsite {
|
||||||
actionId: string;
|
actionId: string;
|
||||||
coWebsite?: CoWebsite;
|
coWebsite?: CoWebsite;
|
||||||
state: OpenCoWebsiteState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GameMapPropertiesListener {
|
export class GameMapPropertiesListener {
|
||||||
@ -29,6 +30,7 @@ export class GameMapPropertiesListener {
|
|||||||
constructor(private scene: GameScene, private gameMap: GameMap) {}
|
constructor(private scene: GameScene, private gameMap: GameMap) {}
|
||||||
|
|
||||||
register() {
|
register() {
|
||||||
|
// Website on new tab
|
||||||
this.gameMap.onPropertyChange(GameMapProperties.OPEN_TAB, (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange(GameMapProperties.OPEN_TAB, (newValue, oldValue, allProps) => {
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
layoutManagerActionStore.removeAction("openTab");
|
layoutManagerActionStore.removeAction("openTab");
|
||||||
@ -39,7 +41,7 @@ export class GameMapPropertiesListener {
|
|||||||
if (forceTrigger || openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
if (forceTrigger || openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
||||||
let message = allProps.get(GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE);
|
let message = allProps.get(GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE);
|
||||||
if (message === undefined) {
|
if (message === undefined) {
|
||||||
message = "Press SPACE or touch here to open web site in new tab";
|
message = get(LL).trigger.newTab();
|
||||||
}
|
}
|
||||||
layoutManagerActionStore.addAction({
|
layoutManagerActionStore.addAction({
|
||||||
uuid: "openTab",
|
uuid: "openTab",
|
||||||
@ -54,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.
|
// Open a new co-website by the property.
|
||||||
this.gameMap.onEnterLayer((newLayers) => {
|
this.gameMap.onEnterLayer((newLayers) => {
|
||||||
const handler = () => {
|
const handler = () => {
|
||||||
@ -106,49 +231,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);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,7 +266,7 @@ export class GameMapPropertiesListener {
|
|||||||
websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON
|
websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON
|
||||||
) {
|
) {
|
||||||
if (!websiteTriggerMessageProperty) {
|
if (!websiteTriggerMessageProperty) {
|
||||||
websiteTriggerMessageProperty = "Press SPACE or touch here to open web site";
|
websiteTriggerMessageProperty = get(LL).trigger.cowebsite();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.coWebsitesActionTriggerByLayer.set(layer, actionId);
|
this.coWebsitesActionTriggerByLayer.set(layer, actionId);
|
||||||
@ -170,21 +279,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 +333,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);
|
||||||
|
@ -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";
|
||||||
@ -20,9 +20,8 @@ import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
|||||||
|
|
||||||
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||||
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_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";
|
||||||
@ -76,7 +75,7 @@ import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
|
|||||||
import { userIsAdminStore } from "../../Stores/GameStore";
|
import { userIsAdminStore } from "../../Stores/GameStore";
|
||||||
import { contactPageStore } from "../../Stores/MenuStore";
|
import { contactPageStore } from "../../Stores/MenuStore";
|
||||||
import type { WasCameraUpdatedEvent } from "../../Api/Events/WasCameraUpdatedEvent";
|
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 EVENT_TYPE = Phaser.Scenes.Events;
|
||||||
import Texture = Phaser.Textures.Texture;
|
import Texture = Phaser.Textures.Texture;
|
||||||
@ -94,6 +93,9 @@ import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandle
|
|||||||
import { locale } from "../../i18n/i18n-svelte";
|
import { locale } from "../../i18n/i18n-svelte";
|
||||||
import { StringUtils } from "../../Utils/StringUtils";
|
import { StringUtils } from "../../Utils/StringUtils";
|
||||||
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
||||||
|
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;
|
||||||
@ -564,7 +566,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()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -582,7 +584,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()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -633,7 +635,6 @@ export class GameScene extends DirtyScene {
|
|||||||
);
|
);
|
||||||
|
|
||||||
new GameMapPropertiesListener(this, this.gameMap).register();
|
new GameMapPropertiesListener(this, this.gameMap).register();
|
||||||
this.triggerOnMapLayerPropertyChange();
|
|
||||||
|
|
||||||
if (!this.room.isDisconnected()) {
|
if (!this.room.isDisconnected()) {
|
||||||
this.scene.sleep();
|
this.scene.sleep();
|
||||||
@ -800,7 +801,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.initialiseJitsi(coWebsite, message.jitsiRoom, message.jwt);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
|
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
|
||||||
@ -937,103 +950,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 {
|
|
||||||
this.startJitsi(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 = "Press SPACE or touch here to enter Jitsi Meet room";
|
|
||||||
}
|
|
||||||
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 {
|
private listenToIframeEvents(): void {
|
||||||
this.iframeSubscriptionList = [];
|
this.iframeSubscriptionList = [];
|
||||||
this.iframeSubscriptionList.push(
|
this.iframeSubscriptionList.push(
|
||||||
@ -1266,13 +1182,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
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1281,7 +1195,7 @@ ${escapedMessage}
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: coWebsite.iframe.id,
|
id: coWebsite.getId(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1290,27 +1204,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", () => {
|
||||||
@ -1395,7 +1305,7 @@ ${escapedMessage}
|
|||||||
//Create new colliders with the new GameMap
|
//Create new colliders with the new GameMap
|
||||||
this.createCollisionWithPlayer();
|
this.createCollisionWithPlayer();
|
||||||
//Create new trigger with the new GameMap
|
//Create new trigger with the new GameMap
|
||||||
this.triggerOnMapLayerPropertyChange();
|
new GameMapPropertiesListener(this, this.gameMap).register();
|
||||||
resolve(newFirstgid);
|
resolve(newFirstgid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1508,14 +1418,15 @@ ${escapedMessage}
|
|||||||
phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
|
phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.pathfindingManager.setCollisionGrid(this.gameMap.getCollisionGrid());
|
||||||
this.markDirty();
|
this.markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMapDirUrl(): string {
|
public getMapDirUrl(): string {
|
||||||
return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf("/"));
|
return this.MapUrlFile.substring(0, this.MapUrlFile.lastIndexOf("/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onMapExit(roomUrl: URL) {
|
public async onMapExit(roomUrl: URL) {
|
||||||
if (this.mapTransitioning) return;
|
if (this.mapTransitioning) return;
|
||||||
this.mapTransitioning = true;
|
this.mapTransitioning = true;
|
||||||
|
|
||||||
@ -1574,14 +1485,13 @@ ${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) {
|
||||||
iframeListener.unregisterScript(script);
|
iframeListener.unregisterScript(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stopJitsi();
|
|
||||||
audioManagerFileStore.unloadAudio();
|
audioManagerFileStore.unloadAudio();
|
||||||
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
|
||||||
this.connection?.closeConnection();
|
this.connection?.closeConnection();
|
||||||
@ -2136,7 +2046,7 @@ ${escapedMessage}
|
|||||||
mediaManager.hideMyCamera();
|
mediaManager.hideMyCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
public startJitsi(roomName: string, jwt?: string): void {
|
public initialiseJitsi(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,
|
||||||
@ -2148,20 +2058,15 @@ ${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();
|
|
||||||
analyticsClient.enteredJitsi(roomName, this.room.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public stopJitsi(): void {
|
coWebsiteManager.loadCoWebsite(coWebsite).catch((err) => {
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
console.error(err);
|
||||||
if (coWebsite) {
|
});
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => {
|
|
||||||
console.error("Error during Jitsi co-website closing", e);
|
analyticsClient.enteredJitsi(roomName, this.room.id);
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: put this into an 'orchestrator' scene (EntryScene?)
|
//todo: put this into an 'orchestrator' scene (EntryScene?)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { derived, get, writable } from "svelte/store";
|
import { derived, writable } from "svelte/store";
|
||||||
import type { CoWebsite } from "../WebRtc/CoWebsiteManager";
|
import type { CoWebsite } from "../WebRtc/CoWebsite/CoWesbite";
|
||||||
|
|
||||||
function createCoWebsiteStore() {
|
function createCoWebsiteStore() {
|
||||||
const { subscribe, set, update } = writable(Array<CoWebsite>());
|
const { subscribe, set, update } = writable(Array<CoWebsite>());
|
||||||
@ -9,7 +9,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 +31,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 +43,9 @@ 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")
|
||||||
);
|
);
|
||||||
|
@ -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)
|
||||||
|
@ -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 },
|
||||||
|
17
front/src/WebRtc/CoWebsite/CoWesbite.ts
Normal file
17
front/src/WebRtc/CoWebsite/CoWesbite.ts
Normal 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>;
|
||||||
|
}
|
49
front/src/WebRtc/CoWebsite/JitsiCoWebsite.ts
Normal file
49
front/src/WebRtc/CoWebsite/JitsiCoWebsite.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
|
import { jitsiFactory } from "../JitsiFactory";
|
||||||
|
import { SimpleCoWebsite } from "./SimpleCoWebsite";
|
||||||
|
|
||||||
|
export class JitsiCoWebsite extends SimpleCoWebsite {
|
||||||
|
private jitsiLoadPromise?: () => CancelablePromise<HTMLIFrameElement>;
|
||||||
|
|
||||||
|
setJitsiLoadPromise(promise: () => CancelablePromise<HTMLIFrameElement>): void {
|
||||||
|
this.jitsiLoadPromise = promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
load(): CancelablePromise<HTMLIFrameElement> {
|
||||||
|
return new CancelablePromise((resolve, reject, cancel) => {
|
||||||
|
this.state.set("loading");
|
||||||
|
|
||||||
|
gameManager.getCurrentGameScene().disableMediaBehaviors();
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
133
front/src/WebRtc/CoWebsite/SimpleCoWebsite.ts
Normal file
133
front/src/WebRtc/CoWebsite/SimpleCoWebsite.ts
Normal 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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -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, mainCoWebsite } from "../Stores/CoWebsiteStore";
|
||||||
import { get, Writable, writable } from "svelte/store";
|
import { get, Readable, Writable, writable } 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: Writable<iframeStates> = writable(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;
|
||||||
@ -76,6 +57,10 @@ class CoWebsiteManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
public getMainState() {
|
public getMainState() {
|
||||||
|
return get(this.openedMain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMainStateSubscriber(): Readable<iframeStates> {
|
||||||
return this.openedMain;
|
return this.openedMain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,13 +132,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 +224,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 +243,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 +259,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 +281,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 +308,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,11 +321,14 @@ 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");
|
||||||
this.openedMain = iframeStates.closed;
|
this.openedMain.set(iframeStates.closed);
|
||||||
this.fire();
|
this.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +336,7 @@ class CoWebsiteManager {
|
|||||||
this.toggleFullScreenIcon(true);
|
this.toggleFullScreenIcon(true);
|
||||||
this.cowebsiteDom.classList.add("closing");
|
this.cowebsiteDom.classList.add("closing");
|
||||||
this.cowebsiteDom.classList.remove("opened");
|
this.cowebsiteDom.classList.remove("opened");
|
||||||
this.openedMain = iframeStates.closed;
|
this.openedMain.set(iframeStates.closed);
|
||||||
this.resetStyleMain();
|
this.resetStyleMain();
|
||||||
this.fire();
|
this.fire();
|
||||||
}
|
}
|
||||||
@ -389,14 +390,14 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.cowebsiteDom.classList.add("opened");
|
this.cowebsiteDom.classList.add("opened");
|
||||||
this.openedMain = iframeStates.loading;
|
this.openedMain.set(iframeStates.loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
private openMain(): void {
|
private openMain(): void {
|
||||||
this.cowebsiteDom.addEventListener("transitionend", () => {
|
this.cowebsiteDom.addEventListener("transitionend", () => {
|
||||||
this.resizeAllIframes();
|
this.resizeAllIframes();
|
||||||
});
|
});
|
||||||
this.openedMain = iframeStates.opened;
|
this.openedMain.set(iframeStates.opened);
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetStyleMain() {
|
public resetStyleMain() {
|
||||||
@ -409,7 +410,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 +432,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 +448,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 +465,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 +543,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,38 +557,21 @@ 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.removeHighlight();
|
||||||
type: "cowebsite",
|
|
||||||
embed: mainCoWebsite,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resizeAllIframes();
|
this.resizeAllIframes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public searchJitsi(): CoWebsite | undefined {
|
public addCoWebsiteToStore(coWebsite: CoWebsite, position: number | undefined) {
|
||||||
return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.jitsi);
|
|
||||||
}
|
|
||||||
|
|
||||||
private initialiseCowebsite(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,210 +580,89 @@ 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
|
||||||
if (this.getMainCoWebsite() && this.openedMain === iframeStates.closed) {
|
if (this.getMainCoWebsite() && this.getMainState() === iframeStates.closed) {
|
||||||
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);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.error();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (mainCoWebsite) {
|
public closeCoWebsite(coWebsite: CoWebsite): void {
|
||||||
this.removeHighlightCoWebsite(mainCoWebsite);
|
if (get(coWebsites).length === 1) {
|
||||||
this.goToMain(mainCoWebsite);
|
this.fire();
|
||||||
this.resizeAllIframes();
|
}
|
||||||
} else {
|
|
||||||
this.closeMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
coWebsites.add(coWebsite, get(coWebsites).length);
|
this.removeCoWebsiteFromStack(coWebsite);
|
||||||
|
|
||||||
resolve();
|
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 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 getGameSize(): { width: number; height: number } {
|
public getGameSize(): { width: number; height: number } {
|
||||||
if (this.openedMain === iframeStates.closed) {
|
if (this.getMainState() === iframeStates.closed) {
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
height: window.innerHeight,
|
height: window.innerHeight,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
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 CancelablePromise from "cancelable-promise";
|
||||||
|
|
||||||
interface jitsiConfigInterface {
|
interface jitsiConfigInterface {
|
||||||
startWithAudioMuted: boolean;
|
startWithAudioMuted: boolean;
|
||||||
@ -134,122 +135,96 @@ 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(iframe);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.jitsiApi.addListener("readyToClose", () => {
|
||||||
|
this.closeOrUnload(iframe);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 (iframe: HTMLIFrameElement) {
|
||||||
if (coWebsite.closable) {
|
const coWebsite = coWebsiteManager.getCoWebsites().find((coWebsite) => coWebsite.getIframe() === iframe);
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
|
|
||||||
console.error("Error during closing a Jitsi Meet");
|
if (!coWebsite) {
|
||||||
});
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public restart() {
|
|
||||||
if (!this.jitsiApi) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
|
|
||||||
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
|
||||||
|
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
|
||||||
console.log("jitsi api ", this.jitsiApi);
|
|
||||||
console.log("iframe cowebsite", coWebsite?.iframe);
|
|
||||||
|
|
||||||
if (!coWebsite) {
|
|
||||||
this.destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
|
||||||
this.closeOrUnload(coWebsite);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("readyToClose", () => {
|
|
||||||
this.closeOrUnload(coWebsite);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public stop() {
|
public stop() {
|
||||||
if (!this.jitsiApi) {
|
if (!this.jitsiApi) {
|
||||||
return;
|
return;
|
||||||
@ -284,8 +259,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 +279,10 @@ class JitsiFactory {
|
|||||||
};
|
};
|
||||||
|
|
||||||
document.head.appendChild(jitsiScript);
|
document.head.appendChild(jitsiScript);
|
||||||
|
|
||||||
|
cancel(() => {
|
||||||
|
jitsiScript.remove();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import warning from "./warning";
|
|||||||
import woka from "./woka";
|
import woka from "./woka";
|
||||||
|
|
||||||
const de_DE: Translation = {
|
const de_DE: Translation = {
|
||||||
...en_US,
|
...(en_US as Translation),
|
||||||
language: "Deutsch",
|
language: "Deutsch",
|
||||||
country: "Deutschland",
|
country: "Deutschland",
|
||||||
audio,
|
audio,
|
||||||
|
@ -11,6 +11,7 @@ import menu from "./menu";
|
|||||||
import report from "./report";
|
import report from "./report";
|
||||||
import warning from "./warning";
|
import warning from "./warning";
|
||||||
import emoji from "./emoji";
|
import emoji from "./emoji";
|
||||||
|
import trigger from "./trigger";
|
||||||
|
|
||||||
const en_US: BaseTranslation = {
|
const en_US: BaseTranslation = {
|
||||||
language: "English",
|
language: "English",
|
||||||
@ -27,6 +28,7 @@ const en_US: BaseTranslation = {
|
|||||||
report,
|
report,
|
||||||
warning,
|
warning,
|
||||||
emoji,
|
emoji,
|
||||||
|
trigger,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default en_US;
|
export default en_US;
|
||||||
|
9
front/src/i18n/en-US/trigger.ts
Normal file
9
front/src/i18n/en-US/trigger.ts
Normal 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;
|
@ -12,9 +12,10 @@ import menu from "./menu";
|
|||||||
import report from "./report";
|
import report from "./report";
|
||||||
import warning from "./warning";
|
import warning from "./warning";
|
||||||
import woka from "./woka";
|
import woka from "./woka";
|
||||||
|
import trigger from "./trigger";
|
||||||
|
|
||||||
const fr_FR: Translation = {
|
const fr_FR: Translation = {
|
||||||
...en_US,
|
...(en_US as Translation),
|
||||||
language: "Français",
|
language: "Français",
|
||||||
country: "France",
|
country: "France",
|
||||||
audio,
|
audio,
|
||||||
@ -29,6 +30,7 @@ const fr_FR: Translation = {
|
|||||||
report,
|
report,
|
||||||
warning,
|
warning,
|
||||||
emoji,
|
emoji,
|
||||||
|
trigger,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr_FR;
|
export default fr_FR;
|
||||||
|
@ -63,7 +63,7 @@ const menu: NonNullable<Translation["menu"]> = {
|
|||||||
},
|
},
|
||||||
fullscreen: "Plein écran",
|
fullscreen: "Plein écran",
|
||||||
notifications: "Notifications",
|
notifications: "Notifications",
|
||||||
cowebsiteTrigger: "Demander toujours avant d'ouvrir des sites web et des salles de réunion Jitsi",
|
cowebsiteTrigger: "Demander toujours avant d'ouvrir des sites web et des salles de conférence Jitsi",
|
||||||
ignoreFollowRequest: "Ignorer les demandes de suivi des autres utilisateurs",
|
ignoreFollowRequest: "Ignorer les demandes de suivi des autres utilisateurs",
|
||||||
},
|
},
|
||||||
invite: {
|
invite: {
|
||||||
|
9
front/src/i18n/fr-FR/trigger.ts
Normal file
9
front/src/i18n/fr-FR/trigger.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { Translation } from "../i18n-types";
|
||||||
|
|
||||||
|
const trigger: NonNullable<Translation["trigger"]> = {
|
||||||
|
cowebsite: "Appuyez sur ESPACE ou ici pour ouvrir le site Web",
|
||||||
|
jitsiRoom: "Appuyez sur ESPACE ou ici pour entrer dans la salle conférence Jitsi",
|
||||||
|
newTab: "Appuyez sur ESPACE ou ici pour ouvrir le site Web dans un nouvel onglet",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default trigger;
|
197
maps/tests/DoorTest/map.json
Normal file
197
maps/tests/DoorTest/map.json
Normal 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
|
||||||
|
}
|
26
maps/tests/DoorTest/script.php
Normal file
26
maps/tests/DoorTest/script.php
Normal 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>
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user