Merge pull request #1854 from thecodingmachine/develop
Deploy 2022-02-11
This commit is contained in:
commit
c4d18716c3
@ -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"
|
||||||
|
@ -82,7 +82,11 @@ We are able to direct a Woka to the desired place immediately after spawn. To ma
|
|||||||
```
|
```
|
||||||
.../my_map.json#moveTo=meeting-room&start
|
.../my_map.json#moveTo=meeting-room&start
|
||||||
```
|
```
|
||||||
|
*...or even like this!*
|
||||||
|
```
|
||||||
|
.../my_map.json#start&moveTo=200,100
|
||||||
|
```
|
||||||
|
|
||||||
For this to work, moveTo must be equal to the layer name of interest. This layer should have at least one tile defined. In case of layer having many tiles, user will go to one of them, randomly selected.
|
For this to work, moveTo must be equal to the x and y position, layer name, or object name of interest. Layer should have at least one tile defined. In case of layer having many tiles, user will go to one of them, randomly selected.
|
||||||
|
|
||||||
![](images/moveTo-layer-example.png)
|
![](images/moveTo-layer-example.png)
|
@ -71,7 +71,7 @@
|
|||||||
"zod": "^3.11.6"
|
"zod": "^3.11.6"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "run-p templater serve svelte-check-watch typesafe-i18n",
|
"start": "run-p templater serve svelte-check-watch typesafe-i18n-watch",
|
||||||
"templater": "cross-env ./templater.sh",
|
"templater": "cross-env ./templater.sh",
|
||||||
"serve": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" webpack serve --open",
|
"serve": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" webpack serve --open",
|
||||||
"build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production webpack",
|
"build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production webpack",
|
||||||
@ -84,7 +84,8 @@
|
|||||||
"svelte-check": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore\"",
|
"svelte-check": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore\"",
|
||||||
"pretty": "yarn prettier --write 'src/**/*.{ts,svelte}'",
|
"pretty": "yarn prettier --write 'src/**/*.{ts,svelte}'",
|
||||||
"pretty-check": "yarn prettier --check 'src/**/*.{ts,svelte}'",
|
"pretty-check": "yarn prettier --check 'src/**/*.{ts,svelte}'",
|
||||||
"typesafe-i18n": "typesafe-i18n --no-watch"
|
"typesafe-i18n": "typesafe-i18n --no-watch",
|
||||||
|
"typesafe-i18n-watch": "typesafe-i18n"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.svelte": [
|
"*.svelte": [
|
||||||
|
@ -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, jitsiCoWebsite } from "../../Stores/CoWebsiteStore";
|
import { mainCoWebsite } from "../../Stores/CoWebsiteStore";
|
||||||
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||||
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
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";
|
||||||
|
|
||||||
@ -15,10 +16,10 @@
|
|||||||
let icon: HTMLImageElement;
|
let icon: HTMLImageElement;
|
||||||
let iconLoaded = false;
|
let iconLoaded = false;
|
||||||
let state = coWebsite.getStateSubscriber();
|
let state = coWebsite.getStateSubscriber();
|
||||||
let isJitsi: boolean = false;
|
let isJitsi: boolean = coWebsite instanceof JitsiCoWebsite;
|
||||||
|
const mainState = coWebsiteManager.getMainStateSubscriber();
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
isJitsi = Boolean($jitsiCoWebsite && $jitsiCoWebsite.getId() === coWebsite.getId());
|
|
||||||
icon.src = isJitsi
|
icon.src = isJitsi
|
||||||
? "/resources/logos/meet.svg"
|
? "/resources/logos/meet.svg"
|
||||||
: `${ICON_URL}/icon?url=${coWebsite.getUrl().hostname}&size=64..96..256&fallback_icon_color=14304c`;
|
: `${ICON_URL}/icon?url=${coWebsite.getUrl().hostname}&size=64..96..256&fallback_icon_color=14304c`;
|
||||||
@ -33,20 +34,23 @@
|
|||||||
coWebsiteManager.goToMain(coWebsite);
|
coWebsiteManager.goToMain(coWebsite);
|
||||||
} else if ($mainCoWebsite) {
|
} else if ($mainCoWebsite) {
|
||||||
if ($mainCoWebsite.getId() === coWebsite.getId()) {
|
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.getId() !== $mainCoWebsite.getId()) {
|
|
||||||
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +68,10 @@
|
|||||||
let isHighlight: boolean = false;
|
let isHighlight: boolean = false;
|
||||||
let isMain: boolean = false;
|
let isMain: boolean = false;
|
||||||
$: {
|
$: {
|
||||||
isMain = $mainCoWebsite !== undefined && $mainCoWebsite.getId() === coWebsite.getId();
|
isMain =
|
||||||
|
$mainState === iframeStates.opened &&
|
||||||
|
$mainCoWebsite !== undefined &&
|
||||||
|
$mainCoWebsite.getId() === coWebsite.getId();
|
||||||
isHighlight =
|
isHighlight =
|
||||||
$highlightedEmbedScreen !== null &&
|
$highlightedEmbedScreen !== null &&
|
||||||
$highlightedEmbedScreen.type === "cowebsite" &&
|
$highlightedEmbedScreen.type === "cowebsite" &&
|
||||||
@ -212,7 +219,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:not(.vertical) {
|
&:not(.vertical) {
|
||||||
animation: bounce 0.35s ease 6 alternate;
|
transition: all 300ms;
|
||||||
|
transform: translateY(0px);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.vertical {
|
&.vertical {
|
||||||
@ -233,7 +241,7 @@
|
|||||||
|
|
||||||
&.displayed {
|
&.displayed {
|
||||||
&:not(.vertical) {
|
&:not(.vertical) {
|
||||||
animation: activeThumbnail 300ms ease-in 0s forwards;
|
transform: translateY(-15px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,16 +270,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes activeThumbnail {
|
|
||||||
0% {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: translateY(-15px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes bounce {
|
@keyframes bounce {
|
||||||
from {
|
from {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import LL from "../../i18n/i18n-svelte";
|
import LL from "../../i18n/i18n-svelte";
|
||||||
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
|
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
||||||
|
|
||||||
|
let entryPoint: string = $startLayerNamesStore[0];
|
||||||
|
let walkAutomatically: boolean = false;
|
||||||
|
const currentPlayer = gameManager.getCurrentGameScene().CurrentPlayer;
|
||||||
|
const playerPos = { x: Math.floor(currentPlayer.x), y: Math.floor(currentPlayer.y) };
|
||||||
|
|
||||||
function copyLink() {
|
function copyLink() {
|
||||||
const input: HTMLInputElement = document.getElementById("input-share-link") as HTMLInputElement;
|
const input: HTMLInputElement = document.getElementById("input-share-link") as HTMLInputElement;
|
||||||
@ -8,8 +15,23 @@
|
|||||||
document.execCommand("copy");
|
document.execCommand("copy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLink() {
|
||||||
|
return `${location.origin}${location.pathname}#${entryPoint}${
|
||||||
|
walkAutomatically ? `&moveTo=${playerPos.x},${playerPos.y}` : ""
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateInputFieldValue() {
|
||||||
|
const input = document.getElementById("input-share-link");
|
||||||
|
if (input) {
|
||||||
|
(input as HTMLInputElement).value = getLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let canShare = navigator.share !== undefined;
|
||||||
|
|
||||||
async function shareLink() {
|
async function shareLink() {
|
||||||
const shareData = { url: location.toString() };
|
const shareData = { url: getLink() };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await navigator.share(shareData);
|
await navigator.share(shareData);
|
||||||
@ -22,16 +44,43 @@
|
|||||||
|
|
||||||
<div class="guest-main">
|
<div class="guest-main">
|
||||||
<section class="container-overflow">
|
<section class="container-overflow">
|
||||||
<section class="share-url not-mobile">
|
{#if !canShare}
|
||||||
<h3>{$LL.menu.invite.description()}</h3>
|
<section class="share-url not-mobile">
|
||||||
<input type="text" readonly id="input-share-link" value={location.toString()} />
|
<h3>{$LL.menu.invite.description()}</h3>
|
||||||
<button type="button" class="nes-btn is-primary" on:click={copyLink}>{$LL.menu.invite.copy()}</button>
|
<input type="text" readonly id="input-share-link" class="link-url" value={location.toString()} />
|
||||||
</section>
|
<button type="button" class="nes-btn is-primary" on:click={copyLink}>{$LL.menu.invite.copy()}</button>
|
||||||
<section class="is-mobile">
|
</section>
|
||||||
<h3>{$LL.menu.invite.description()}</h3>
|
{:else}
|
||||||
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
|
<section class="is-mobile">
|
||||||
<button type="button" class="nes-btn is-primary" on:click={shareLink}>{$LL.menu.invite.share()}</button>
|
<h3>{$LL.menu.invite.description()}</h3>
|
||||||
|
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click={shareLink}>{$LL.menu.invite.share()}</button>
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
|
<h3>Select an entry point</h3>
|
||||||
|
<section class="nes-select is-dark starting-points">
|
||||||
|
<select
|
||||||
|
bind:value={entryPoint}
|
||||||
|
on:blur={() => {
|
||||||
|
updateInputFieldValue();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{#each $startLayerNamesStore as entryPointName}
|
||||||
|
<option value={entryPointName}>{entryPointName}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
</section>
|
</section>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="nes-checkbox is-dark"
|
||||||
|
bind:checked={walkAutomatically}
|
||||||
|
on:change={() => {
|
||||||
|
updateInputFieldValue();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span>{$LL.menu.invite.walk_automatically_to_position()}</span>
|
||||||
|
</label>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -39,14 +88,27 @@
|
|||||||
@import "../../../style/breakpoints.scss";
|
@import "../../../style/breakpoints.scss";
|
||||||
|
|
||||||
div.guest-main {
|
div.guest-main {
|
||||||
|
width: 50%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
|
|
||||||
text-align: center;
|
input.link-url {
|
||||||
|
width: calc(100% - 200px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.starting-points {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section.nes-select select:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
section.container-overflow {
|
section.container-overflow {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -55,25 +117,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
section.is-mobile {
|
section.is-mobile {
|
||||||
display: none;
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
div.guest-main {
|
div.guest-main {
|
||||||
section.share-url.not-mobile {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.is-mobile {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.container-overflow {
|
section.container-overflow {
|
||||||
height: calc(100% - 120px);
|
height: calc(100% - 120px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-up(lg) {
|
||||||
|
div.guest-main {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -323,6 +323,10 @@ export class GameMap {
|
|||||||
throw new Error("No possible position found");
|
throw new Error("No possible position found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getObjectWithName(name: string): ITiledMapObject | undefined {
|
||||||
|
return this.tiledObjects.find((object) => object.name === name);
|
||||||
|
}
|
||||||
|
|
||||||
private getLayersByKey(key: number): Array<ITiledMapLayer> {
|
private getLayersByKey(key: number): Array<ITiledMapLayer> {
|
||||||
return this.flatLayers.filter((flatLayer) => flatLayer.type === "tilelayer" && flatLayer.data[key] !== 0);
|
return this.flatLayers.filter((flatLayer) => flatLayer.type === "tilelayer" && flatLayer.data[key] !== 0);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,13 @@ import type { ITiledMapLayer } from "../Map/ITiledMap";
|
|||||||
import { GameMapProperties } from "./GameMapProperties";
|
import { GameMapProperties } from "./GameMapProperties";
|
||||||
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||||
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
||||||
|
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||||
|
import { JITSI_PRIVATE_MODE, JITSI_URL } from "../../Enum/EnvironmentVariable";
|
||||||
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
|
import { audioManagerFileStore, audioManagerVisibilityStore } from "../../Stores/AudioManagerStore";
|
||||||
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
|
import { Room } from "../../Connexion/Room";
|
||||||
|
import LL from "../../i18n/i18n-svelte";
|
||||||
|
|
||||||
interface OpenCoWebsite {
|
interface OpenCoWebsite {
|
||||||
actionId: string;
|
actionId: string;
|
||||||
@ -23,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");
|
||||||
@ -33,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",
|
||||||
@ -48,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 = () => {
|
||||||
@ -135,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);
|
||||||
|
@ -20,15 +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 {
|
import { DEBUG_MODE, JITSI_URL, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
||||||
DEBUG_MODE,
|
|
||||||
JITSI_PRIVATE_MODE,
|
|
||||||
JITSI_URL,
|
|
||||||
MAX_PER_GROUP,
|
|
||||||
POSITION_DELAY,
|
|
||||||
} from "../../Enum/EnvironmentVariable";
|
|
||||||
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
||||||
import { Room } from "../../Connexion/Room";
|
import { Room } from "../../Connexion/Room";
|
||||||
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||||
@ -82,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;
|
||||||
@ -98,6 +91,8 @@ import { MapStore } from "../../Stores/Utils/MapStore";
|
|||||||
import { followUsersColorStore } from "../../Stores/FollowStore";
|
import { followUsersColorStore } from "../../Stores/FollowStore";
|
||||||
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
|
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
|
||||||
import { locale } from "../../i18n/i18n-svelte";
|
import { locale } from "../../i18n/i18n-svelte";
|
||||||
|
import { StringUtils } from "../../Utils/StringUtils";
|
||||||
|
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
||||||
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
||||||
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||||
@ -550,6 +545,8 @@ export class GameScene extends DirtyScene {
|
|||||||
urlManager.getStartLayerNameFromUrl()
|
urlManager.getStartLayerNameFromUrl()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
startLayerNamesStore.set(this.startPositionCalculator.getStartPositionNames());
|
||||||
|
|
||||||
//add entities
|
//add entities
|
||||||
this.Objects = new Array<Phaser.Physics.Arcade.Sprite>();
|
this.Objects = new Array<Phaser.Physics.Arcade.Sprite>();
|
||||||
|
|
||||||
@ -577,6 +574,8 @@ export class GameScene extends DirtyScene {
|
|||||||
this.createCurrentPlayer();
|
this.createCurrentPlayer();
|
||||||
this.removeAllRemotePlayers(); //cleanup the list of remote players in case the scene was rebooted
|
this.removeAllRemotePlayers(); //cleanup the list of remote players in case the scene was rebooted
|
||||||
|
|
||||||
|
this.tryMovePlayerWithMoveToParameter();
|
||||||
|
|
||||||
this.cameraManager = new CameraManager(
|
this.cameraManager = new CameraManager(
|
||||||
this,
|
this,
|
||||||
{ x: this.Map.widthInPixels, y: this.Map.heightInPixels },
|
{ x: this.Map.widthInPixels, y: this.Map.heightInPixels },
|
||||||
@ -636,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();
|
||||||
@ -815,7 +813,7 @@ export class GameScene extends DirtyScene {
|
|||||||
|
|
||||||
const coWebsite = new JitsiCoWebsite(new URL(domain), false, undefined, undefined, false);
|
const coWebsite = new JitsiCoWebsite(new URL(domain), false, undefined, undefined, false);
|
||||||
coWebsiteManager.addCoWebsiteToStore(coWebsite, 0);
|
coWebsiteManager.addCoWebsiteToStore(coWebsite, 0);
|
||||||
this.startJitsi(coWebsite, message.jitsiRoom, message.jwt);
|
this.initialiseJitsi(coWebsite, message.jitsiRoom, message.jwt);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
|
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
|
||||||
@ -952,116 +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 {
|
|
||||||
let domain = jitsiUrl || JITSI_URL;
|
|
||||||
if (domain === undefined) {
|
|
||||||
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (domain.substring(0, 7) !== "http://" && domain.substring(0, 8) !== "https://") {
|
|
||||||
domain = `${location.protocol}//${domain}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const coWebsite = new JitsiCoWebsite(new URL(domain), false, undefined, undefined, false);
|
|
||||||
|
|
||||||
coWebsiteManager.addCoWebsiteToStore(coWebsite, 0);
|
|
||||||
this.startJitsi(coWebsite, roomName, undefined);
|
|
||||||
}
|
|
||||||
layoutManagerActionStore.removeAction("jitsi");
|
|
||||||
};
|
|
||||||
|
|
||||||
const jitsiTriggerValue = allProps.get(GameMapProperties.JITSI_TRIGGER);
|
|
||||||
const forceTrigger = localUserStore.getForceCowebsiteTrigger();
|
|
||||||
if (forceTrigger || jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) {
|
|
||||||
let message = allProps.get(GameMapProperties.JITSI_TRIGGER_MESSAGE);
|
|
||||||
if (message === undefined) {
|
|
||||||
message = "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(
|
||||||
@ -1417,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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1488,9 +1376,9 @@ ${escapedMessage}
|
|||||||
});
|
});
|
||||||
|
|
||||||
iframeListener.registerAnswerer("movePlayerTo", async (message) => {
|
iframeListener.registerAnswerer("movePlayerTo", async (message) => {
|
||||||
const index = this.getGameMap().getTileIndexAt(message.x, message.y);
|
const startTileIndex = this.getGameMap().getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
||||||
const startTile = this.getGameMap().getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y);
|
const destinationTileIndex = this.getGameMap().getTileIndexAt(message.x, message.y);
|
||||||
const path = await this.getPathfindingManager().findPath(startTile, index, true, true);
|
const path = await this.getPathfindingManager().findPath(startTileIndex, destinationTileIndex, true, true);
|
||||||
path.shift();
|
path.shift();
|
||||||
if (path.length === 0) {
|
if (path.length === 0) {
|
||||||
throw new Error("no path available");
|
throw new Error("no path available");
|
||||||
@ -1534,11 +1422,11 @@ ${escapedMessage}
|
|||||||
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;
|
||||||
|
|
||||||
@ -1604,7 +1492,6 @@ ${escapedMessage}
|
|||||||
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();
|
||||||
@ -1655,6 +1542,36 @@ ${escapedMessage}
|
|||||||
this.MapPlayersByKey.clear();
|
this.MapPlayersByKey.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private tryMovePlayerWithMoveToParameter(): void {
|
||||||
|
const moveToParam = urlManager.getHashParameter("moveTo");
|
||||||
|
if (moveToParam) {
|
||||||
|
try {
|
||||||
|
let endPos;
|
||||||
|
const posFromParam = StringUtils.parsePointFromParam(moveToParam);
|
||||||
|
if (posFromParam) {
|
||||||
|
endPos = this.gameMap.getTileIndexAt(posFromParam.x, posFromParam.y);
|
||||||
|
} else {
|
||||||
|
const destinationObject = this.gameMap.getObjectWithName(moveToParam);
|
||||||
|
if (destinationObject) {
|
||||||
|
endPos = this.gameMap.getTileIndexAt(destinationObject.x, destinationObject.y);
|
||||||
|
} else {
|
||||||
|
endPos = this.gameMap.getRandomPositionFromLayer(moveToParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.pathfindingManager
|
||||||
|
.findPath(this.gameMap.getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y), endPos)
|
||||||
|
.then((path) => {
|
||||||
|
if (path && path.length > 0) {
|
||||||
|
this.CurrentPlayer.setPathToFollow(path).catch((reason) => console.warn(reason));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((reason) => console.warn(reason));
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`Cannot proceed with moveTo command:\n\t-> ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private getExitUrl(layer: ITiledMapLayer): string | undefined {
|
private getExitUrl(layer: ITiledMapLayer): string | undefined {
|
||||||
return this.getProperty(layer, GameMapProperties.EXIT_URL) as string | undefined;
|
return this.getProperty(layer, GameMapProperties.EXIT_URL) as string | undefined;
|
||||||
}
|
}
|
||||||
@ -1777,22 +1694,6 @@ ${escapedMessage}
|
|||||||
this.connection?.emitEmoteEvent(emoteKey);
|
this.connection?.emitEmoteEvent(emoteKey);
|
||||||
analyticsClient.launchEmote(emoteKey);
|
analyticsClient.launchEmote(emoteKey);
|
||||||
});
|
});
|
||||||
const moveToParam = urlManager.getHashParameter("moveTo");
|
|
||||||
if (moveToParam) {
|
|
||||||
try {
|
|
||||||
const endPos = this.gameMap.getRandomPositionFromLayer(moveToParam);
|
|
||||||
this.pathfindingManager
|
|
||||||
.findPath(this.gameMap.getTileIndexAt(this.CurrentPlayer.x, this.CurrentPlayer.y), endPos)
|
|
||||||
.then((path) => {
|
|
||||||
if (path && path.length > 0) {
|
|
||||||
this.CurrentPlayer.setPathToFollow(path).catch((reason) => console.warn(reason));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((reason) => console.warn(reason));
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(`Cannot proceed with moveTo command:\n\t-> ${err}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof TextureError) {
|
if (err instanceof TextureError) {
|
||||||
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
||||||
@ -2145,7 +2046,7 @@ ${escapedMessage}
|
|||||||
mediaManager.hideMyCamera();
|
mediaManager.hideMyCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
public startJitsi(coWebsite: JitsiCoWebsite, roomName: string, jwt?: string): void {
|
public initialiseJitsi(coWebsite: JitsiCoWebsite, roomName: string, jwt?: string): void {
|
||||||
const allProps = this.gameMap.getCurrentProperties();
|
const 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,
|
||||||
@ -2157,9 +2058,9 @@ ${escapedMessage}
|
|||||||
);
|
);
|
||||||
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
||||||
|
|
||||||
coWebsite.setJitsiLoadPromise(
|
coWebsite.setJitsiLoadPromise(() => {
|
||||||
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl)
|
return jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl);
|
||||||
);
|
});
|
||||||
|
|
||||||
coWebsiteManager.loadCoWebsite(coWebsite).catch((err) => {
|
coWebsiteManager.loadCoWebsite(coWebsite).catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -2168,13 +2069,6 @@ ${escapedMessage}
|
|||||||
analyticsClient.enteredJitsi(roomName, this.room.id);
|
analyticsClient.enteredJitsi(roomName, this.room.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopJitsi(): void {
|
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
|
||||||
if (coWebsite) {
|
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo: put this into an 'orchestrator' scene (EntryScene?)
|
//todo: put this into an 'orchestrator' scene (EntryScene?)
|
||||||
private bannedUser() {
|
private bannedUser() {
|
||||||
this.cleanupClosingScene();
|
this.cleanupClosingScene();
|
||||||
|
@ -16,32 +16,6 @@ export class StartPositionCalculator {
|
|||||||
) {
|
) {
|
||||||
this.initStartXAndStartY();
|
this.initStartXAndStartY();
|
||||||
}
|
}
|
||||||
private initStartXAndStartY() {
|
|
||||||
// If there is an init position passed
|
|
||||||
if (this.initPosition !== null) {
|
|
||||||
this.startPosition = this.initPosition;
|
|
||||||
} else {
|
|
||||||
// Now, let's find the start layer
|
|
||||||
if (this.startLayerName) {
|
|
||||||
this.initPositionFromLayerName(this.startLayerName, this.startLayerName);
|
|
||||||
}
|
|
||||||
if (this.startPosition === undefined) {
|
|
||||||
// If we have no start layer specified or if the hash passed does not exist, let's go with the default start position.
|
|
||||||
this.initPositionFromLayerName(defaultStartLayerName, this.startLayerName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Still no start position? Something is wrong with the map, we need a "start" layer.
|
|
||||||
if (this.startPosition === undefined) {
|
|
||||||
console.warn(
|
|
||||||
'This map is missing a layer named "start" that contains the available default start positions.'
|
|
||||||
);
|
|
||||||
// Let's start in the middle of the map
|
|
||||||
this.startPosition = {
|
|
||||||
x: this.mapFile.width * 16,
|
|
||||||
y: this.mapFile.height * 16,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -76,6 +50,47 @@ export class StartPositionCalculator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getStartPositionNames(): string[] {
|
||||||
|
const names: string[] = [];
|
||||||
|
for (const layer of this.gameMap.flatLayers) {
|
||||||
|
if (layer.name === "start") {
|
||||||
|
names.push(layer.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.isStartLayer(layer)) {
|
||||||
|
names.push(layer.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initStartXAndStartY() {
|
||||||
|
// If there is an init position passed
|
||||||
|
if (this.initPosition !== null) {
|
||||||
|
this.startPosition = this.initPosition;
|
||||||
|
} else {
|
||||||
|
// Now, let's find the start layer
|
||||||
|
if (this.startLayerName) {
|
||||||
|
this.initPositionFromLayerName(this.startLayerName, this.startLayerName);
|
||||||
|
}
|
||||||
|
if (this.startPosition === undefined) {
|
||||||
|
// If we have no start layer specified or if the hash passed does not exist, let's go with the default start position.
|
||||||
|
this.initPositionFromLayerName(defaultStartLayerName, this.startLayerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Still no start position? Something is wrong with the map, we need a "start" layer.
|
||||||
|
if (this.startPosition === undefined) {
|
||||||
|
console.warn(
|
||||||
|
'This map is missing a layer named "start" that contains the available default start positions.'
|
||||||
|
);
|
||||||
|
// Let's start in the middle of the map
|
||||||
|
this.startPosition = {
|
||||||
|
x: this.mapFile.width * 16,
|
||||||
|
y: this.mapFile.height * 16,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private isStartLayer(layer: ITiledMapLayer): boolean {
|
private isStartLayer(layer: ITiledMapLayer): boolean {
|
||||||
return this.getProperty(layer, GameMapProperties.START_LAYER) == true;
|
return this.getProperty(layer, GameMapProperties.START_LAYER) == true;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { derived, get, writable } from "svelte/store";
|
import { derived, writable } from "svelte/store";
|
||||||
import type { CoWebsite } from "../WebRtc/CoWebsite/CoWesbite";
|
import type { CoWebsite } from "../WebRtc/CoWebsite/CoWesbite";
|
||||||
import { JitsiCoWebsite } from "../WebRtc/CoWebsite/JitsiCoWebsite";
|
|
||||||
|
|
||||||
function createCoWebsiteStore() {
|
function createCoWebsiteStore() {
|
||||||
const { subscribe, set, update } = writable(Array<CoWebsite>());
|
const { subscribe, set, update } = writable(Array<CoWebsite>());
|
||||||
@ -50,7 +49,3 @@ export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) =>
|
|||||||
export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) =>
|
export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) =>
|
||||||
$coWebsites.find((coWebsite) => coWebsite.getState() !== "asleep")
|
$coWebsites.find((coWebsite) => coWebsite.getState() !== "asleep")
|
||||||
);
|
);
|
||||||
|
|
||||||
export const jitsiCoWebsite = derived([coWebsites], ([$coWebsites]) =>
|
|
||||||
$coWebsites.find((coWebsite) => coWebsite instanceof JitsiCoWebsite)
|
|
||||||
);
|
|
||||||
|
6
front/src/Stores/StartLayerNamesStore.ts
Normal file
6
front/src/Stores/StartLayerNamesStore.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { Readable, writable } from "svelte/store";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A store that contains the map starting layers names
|
||||||
|
*/
|
||||||
|
export const startLayerNamesStore = writable<string[]>([]);
|
12
front/src/Utils/StringUtils.ts
Normal file
12
front/src/Utils/StringUtils.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export class StringUtils {
|
||||||
|
public static parsePointFromParam(param: string, separator: string = ","): { x: number; y: number } | undefined {
|
||||||
|
const values = param.split(separator).map((val) => parseInt(val));
|
||||||
|
if (values.length !== 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNaN(values[0]) || isNaN(values[1])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return { x: values[0], y: values[1] };
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,12 @@
|
|||||||
import CancelablePromise from "cancelable-promise";
|
import CancelablePromise from "cancelable-promise";
|
||||||
import { gameManager } from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
import { coWebsiteManager } from "../CoWebsiteManager";
|
|
||||||
import { jitsiFactory } from "../JitsiFactory";
|
import { jitsiFactory } from "../JitsiFactory";
|
||||||
import { SimpleCoWebsite } from "./SimpleCoWebsite";
|
import { SimpleCoWebsite } from "./SimpleCoWebsite";
|
||||||
|
|
||||||
export class JitsiCoWebsite extends SimpleCoWebsite {
|
export class JitsiCoWebsite extends SimpleCoWebsite {
|
||||||
private jitsiLoadPromise?: CancelablePromise<HTMLIFrameElement>;
|
private jitsiLoadPromise?: () => CancelablePromise<HTMLIFrameElement>;
|
||||||
|
|
||||||
constructor(url: URL, allowApi?: boolean, allowPolicy?: string, widthPercent?: number, closable?: boolean) {
|
setJitsiLoadPromise(promise: () => CancelablePromise<HTMLIFrameElement>): void {
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
|
||||||
|
|
||||||
if (coWebsite) {
|
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite);
|
|
||||||
}
|
|
||||||
|
|
||||||
super(url, allowApi, allowPolicy, widthPercent, closable);
|
|
||||||
}
|
|
||||||
|
|
||||||
setJitsiLoadPromise(promise: CancelablePromise<HTMLIFrameElement>): void {
|
|
||||||
this.jitsiLoadPromise = promise;
|
this.jitsiLoadPromise = promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,13 +15,12 @@ export class JitsiCoWebsite extends SimpleCoWebsite {
|
|||||||
this.state.set("loading");
|
this.state.set("loading");
|
||||||
|
|
||||||
gameManager.getCurrentGameScene().disableMediaBehaviors();
|
gameManager.getCurrentGameScene().disableMediaBehaviors();
|
||||||
jitsiFactory.restart();
|
|
||||||
|
|
||||||
if (!this.jitsiLoadPromise) {
|
if (!this.jitsiLoadPromise) {
|
||||||
return reject("Undefined Jitsi start callback");
|
return reject("Undefined Jitsi start callback");
|
||||||
}
|
}
|
||||||
|
|
||||||
const jitsiLoading = this.jitsiLoadPromise
|
const jitsiLoading = this.jitsiLoadPromise()
|
||||||
.then((iframe) => {
|
.then((iframe) => {
|
||||||
this.iframe = iframe;
|
this.iframe = iframe;
|
||||||
this.iframe.classList.add("pixel");
|
this.iframe.classList.add("pixel");
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { HtmlUtils } from "./HtmlUtils";
|
import { HtmlUtils } from "./HtmlUtils";
|
||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
|
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
|
||||||
import { coWebsites, coWebsitesNotAsleep, jitsiCoWebsite, mainCoWebsite } from "../Stores/CoWebsiteStore";
|
import { coWebsites, coWebsitesNotAsleep, mainCoWebsite } from "../Stores/CoWebsiteStore";
|
||||||
import { get } 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 { LayoutMode } from "./LayoutManager";
|
import { LayoutMode } from "./LayoutManager";
|
||||||
@ -34,7 +34,7 @@ interface TouchMoveCoordinates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
@ -57,6 +57,10 @@ class CoWebsiteManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
public getMainState() {
|
public getMainState() {
|
||||||
|
return get(this.openedMain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMainStateSubscriber(): Readable<iframeStates> {
|
||||||
return this.openedMain;
|
return this.openedMain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,7 +328,7 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,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();
|
||||||
}
|
}
|
||||||
@ -386,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() {
|
||||||
@ -556,19 +560,12 @@ class CoWebsiteManager {
|
|||||||
mainCoWebsite.getId() !== coWebsite.getId() &&
|
mainCoWebsite.getId() !== coWebsite.getId() &&
|
||||||
mainCoWebsite.getState() !== "asleep"
|
mainCoWebsite.getState() !== "asleep"
|
||||||
) {
|
) {
|
||||||
highlightedEmbedScreen.toggleHighlight({
|
highlightedEmbedScreen.removeHighlight();
|
||||||
type: "cowebsite",
|
|
||||||
embed: mainCoWebsite,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resizeAllIframes();
|
this.resizeAllIframes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public searchJitsi(): CoWebsite | undefined {
|
|
||||||
return get(jitsiCoWebsite);
|
|
||||||
}
|
|
||||||
|
|
||||||
public addCoWebsiteToStore(coWebsite: CoWebsite, position: number | undefined) {
|
public addCoWebsiteToStore(coWebsite: CoWebsite, position: number | undefined) {
|
||||||
const coWebsitePosition = position === undefined ? get(coWebsites).length : position;
|
const coWebsitePosition = position === undefined ? get(coWebsites).length : position;
|
||||||
coWebsites.add(coWebsite, coWebsitePosition);
|
coWebsites.add(coWebsite, coWebsitePosition);
|
||||||
@ -591,7 +588,7 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,7 +662,7 @@ class CoWebsiteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
@ -2,7 +2,6 @@ import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
|||||||
import { coWebsiteManager } from "./CoWebsiteManager";
|
import { coWebsiteManager } from "./CoWebsiteManager";
|
||||||
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import type { CoWebsite } from "./CoWebsite/CoWesbite";
|
|
||||||
import CancelablePromise from "cancelable-promise";
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
|
||||||
interface jitsiConfigInterface {
|
interface jitsiConfigInterface {
|
||||||
@ -180,13 +179,14 @@ class JitsiFactory {
|
|||||||
const iframe = coWebsiteManager
|
const iframe = coWebsiteManager
|
||||||
.getCoWebsiteBuffer()
|
.getCoWebsiteBuffer()
|
||||||
.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
||||||
|
|
||||||
if (iframe && this.jitsiApi) {
|
if (iframe && this.jitsiApi) {
|
||||||
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
||||||
this.closeOrUnload();
|
this.closeOrUnload(iframe);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.jitsiApi.addListener("readyToClose", () => {
|
this.jitsiApi.addListener("readyToClose", () => {
|
||||||
this.closeOrUnload();
|
this.closeOrUnload(iframe);
|
||||||
});
|
});
|
||||||
|
|
||||||
return resolve(iframe);
|
return resolve(iframe);
|
||||||
@ -209,8 +209,9 @@ class JitsiFactory {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private closeOrUnload = function () {
|
private closeOrUnload = function (iframe: HTMLIFrameElement) {
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
const coWebsite = coWebsiteManager.getCoWebsites().find((coWebsite) => coWebsite.getIframe() === iframe);
|
||||||
|
|
||||||
if (!coWebsite) {
|
if (!coWebsite) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -224,30 +225,6 @@ class JitsiFactory {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public restart() {
|
|
||||||
if (!this.jitsiApi) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
|
|
||||||
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
|
||||||
|
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
|
||||||
|
|
||||||
if (!coWebsite) {
|
|
||||||
this.destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
|
||||||
this.closeOrUnload();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("readyToClose", () => {
|
|
||||||
this.closeOrUnload();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public stop() {
|
public stop() {
|
||||||
if (!this.jitsiApi) {
|
if (!this.jitsiApi) {
|
||||||
return;
|
return;
|
||||||
|
@ -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,
|
||||||
|
@ -70,6 +70,7 @@ const menu: NonNullable<Translation["menu"]> = {
|
|||||||
description: "Link zu diesem Raum teilen!",
|
description: "Link zu diesem Raum teilen!",
|
||||||
copy: "Kopieren",
|
copy: "Kopieren",
|
||||||
share: "Teilen",
|
share: "Teilen",
|
||||||
|
walk_automatically_to_position: "Walk automatically to my position",
|
||||||
},
|
},
|
||||||
globalMessage: {
|
globalMessage: {
|
||||||
text: "Text",
|
text: "Text",
|
||||||
|
@ -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;
|
||||||
|
@ -70,6 +70,7 @@ const menu: BaseTranslation = {
|
|||||||
description: "Share the link of the room!",
|
description: "Share the link of the room!",
|
||||||
copy: "Copy",
|
copy: "Copy",
|
||||||
share: "Share",
|
share: "Share",
|
||||||
|
walk_automatically_to_position: "Walk automatically to my position",
|
||||||
},
|
},
|
||||||
globalMessage: {
|
globalMessage: {
|
||||||
text: "Text",
|
text: "Text",
|
||||||
|
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,13 +63,14 @@ 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: {
|
||||||
description: "Partager le lien de la salle!",
|
description: "Partager le lien de la salle!",
|
||||||
copy: "Copier",
|
copy: "Copier",
|
||||||
share: "Partager",
|
share: "Partager",
|
||||||
|
walk_automatically_to_position: "Marcher automatiquement jusqu'à ma position",
|
||||||
},
|
},
|
||||||
globalMessage: {
|
globalMessage: {
|
||||||
text: "Texte",
|
text: "Texte",
|
||||||
|
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;
|
@ -3,7 +3,7 @@
|
|||||||
"infinite":false,
|
"infinite":false,
|
||||||
"layers":[
|
"layers":[
|
||||||
{
|
{
|
||||||
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
"height":10,
|
"height":10,
|
||||||
"id":1,
|
"id":1,
|
||||||
"name":"floor",
|
"name":"floor",
|
||||||
@ -204,6 +204,71 @@
|
|||||||
"width":92.7120717279925,
|
"width":92.7120717279925,
|
||||||
"x":233.848901257569,
|
"x":233.848901257569,
|
||||||
"y":135.845612785282
|
"y":135.845612785282
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":0,
|
||||||
|
"id":9,
|
||||||
|
"name":"destination",
|
||||||
|
"point":true,
|
||||||
|
"rotation":0,
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":0,
|
||||||
|
"x":207.918025151374,
|
||||||
|
"y":243.31625523987
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":45.0829063809967,
|
||||||
|
"id":10,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"halign":"center",
|
||||||
|
"text":"destination object",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":83,
|
||||||
|
"x":167.26,
|
||||||
|
"y":254.682580344667
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":19.6921,
|
||||||
|
"id":11,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":13,
|
||||||
|
"text":"...#start&moveTo=destination",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":202.260327899394,
|
||||||
|
"x":32.2652715416861,
|
||||||
|
"y":148.51445302748
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":19.6921,
|
||||||
|
"id":12,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":13,
|
||||||
|
"text":"...#start2&moveTo=200,100",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":202.26,
|
||||||
|
"x":32.2654354913834,
|
||||||
|
"y":169.008165183978
|
||||||
}],
|
}],
|
||||||
"opacity":1,
|
"opacity":1,
|
||||||
"type":"objectgroup",
|
"type":"objectgroup",
|
||||||
@ -212,7 +277,7 @@
|
|||||||
"y":0
|
"y":0
|
||||||
}],
|
}],
|
||||||
"nextlayerid":11,
|
"nextlayerid":11,
|
||||||
"nextobjectid":9,
|
"nextobjectid":13,
|
||||||
"orientation":"orthogonal",
|
"orientation":"orthogonal",
|
||||||
"renderorder":"right-down",
|
"renderorder":"right-down",
|
||||||
"tiledversion":"1.7.2",
|
"tiledversion":"1.7.2",
|
||||||
|
Loading…
Reference in New Issue
Block a user